forecaster.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. """
  2. forecaster.py
  3. This script is designed to run at a regular interval, polling various feeds from the National Weather Service and updating Django models WeatherCondition, WeatherAlert, and WeatherForecast in the Almanac application.
  4. For the current conditions, it grabs the them from the given NWS stations specified in the STATIONS array by their NOAA station ID and saves them as a WeatherConditions object.
  5. When current conditions are checked, the script also looks for weather alerts from NOAA's alert feed for the state specified in STATE. If any are found, a alert object is created and attached to
  6. """
  7. from datetime import datetime, timedelta
  8. from dateutil.parser import *
  9. import urllib
  10. # from suds.client import Client
  11. import elementtree.ElementTree as ET
  12. from almanac.models import WeatherConditions, WeatherAlert, WeatherForecast
  13. ALERT_ZONES = {
  14. "Coastal_Hancock_County": "MEZ029",
  15. }
  16. STATIONS = ["KBGR"]
  17. LOCATIONS = {
  18. "Castine": "04421",
  19. "Blue_Hill": "04614",
  20. "Deer_Isle": "04627",
  21. }
  22. conditions_url = "http://www.weather.gov/xml/current_obs/%s.xml"
  23. alerts_url = "http://www.weather.gov/alerts-beta/wwaatmget.php?x=%s"
  24. forecast_url = "http://www.weather.gov/forecasts/xml/DWMLgen/wsdl/ndfdXML.wsdl"
  25. # NOAA=Client(forecast_url)
  26. def coords_for_zipcode(zipcode, client):
  27. coords = ET.fromstring(client.service.LatLonListZipCode(zipcode))
  28. coords = coords[0].text.split(",")
  29. return coords
  30. def update_conditions(conditions):
  31. """
  32. function process_conditions
  33. input: ElementTree object of weather conditions
  34. result: Look up new weather condition and save it to the db
  35. """
  36. root = conditions.getroot()
  37. observation_time = parse(root[10].text[:31], ignoretz=True)
  38. try:
  39. WeatherConditions.objects.get(observation_time__exact=observation_time)
  40. print "Passing..."
  41. pass
  42. except:
  43. print "Going ahead..."
  44. # if root[20].text=="NA":
  45. wind_gust = 0.0
  46. # else:
  47. # wind_gust=float(root[20].text)
  48. # if root[28].text=="NA":
  49. heat_index = 0.0
  50. # else:
  51. # heat_index=root[28].text
  52. if root[25].text == "NA":
  53. dewpoint = 0
  54. else:
  55. dewpoint = float(root[25].text)
  56. if root[19].text == "NA":
  57. wind = 0
  58. else:
  59. wind = float(root[19].text)
  60. # if root[31].text=="NA":
  61. windchill = 0
  62. # else:
  63. # windchill=int(root[31].text)
  64. location = root[5].text
  65. noaa_station_id = root[6].text
  66. observation_time = parse(root[10].text[:31], ignoretz=True)
  67. weather = root[11].text
  68. temperature = float(root[13].text)
  69. wind_dir = root[17].text
  70. pressure = float(root[22].text)
  71. icon_url = root[28].text + root[30].text
  72. condition = WeatherConditions.objects.create(
  73. location=location,
  74. noaa_station_id=noaa_station_id,
  75. observation_time=observation_time,
  76. weather=weather,
  77. temperature_f=temperature,
  78. wind_dir=wind_dir,
  79. wind=wind,
  80. wind_gust=wind_gust,
  81. pressure=pressure,
  82. dewpoint=dewpoint,
  83. heat_index=heat_index,
  84. windchill=windchill,
  85. icon_url=icon_url,
  86. )
  87. condition.save()
  88. # Create updated conditions for the given stations:
  89. for station in STATIONS:
  90. conditions = ET.parse(urllib.urlopen(conditions_url % station))
  91. update_conditions(conditions)
  92. def process_alerts(alerts, zone):
  93. root = alerts.getroot()
  94. if (
  95. root[6][3].text.strip(" ").strip("\n ")
  96. == "There are no active watches, warnings or advisories"
  97. ):
  98. pass
  99. else: # We have a alert, so lets process
  100. updated = parse(root[6][1].text)
  101. zone_id = ALERT_ZONES[zone]
  102. zone = zone.replace("_", " ")
  103. summary = root[6][5].text.strip("\n")
  104. effective = parse(root[6][6].text)
  105. expires = parse(root[6][7].text)
  106. status = root[6][8].text.strip("\n")
  107. msg_type = root[6][9].text.strip("\n")
  108. urgency = root[6][11].text.strip("\n")
  109. severity = root[6][12].text.strip("\n")
  110. certainty = root[6][13].text.strip("\n")
  111. area = root[6][14].text.strip("\n")
  112. try:
  113. WeatherAlert.objects.get(summary__exact=summary)
  114. pass
  115. except:
  116. alert = WeatherAlert.objects.create(
  117. updated=updated,
  118. zone_id=zone_id,
  119. zone=zone,
  120. summary=summary,
  121. effective=effective,
  122. expires=expires,
  123. status=status,
  124. msg_type=msg_type,
  125. urgency=urgency,
  126. severity=severity,
  127. certainty=certainty,
  128. area=area,
  129. )
  130. alert.save()
  131. # Add alerts for given state
  132. for zone in ALERT_ZONES:
  133. alerts = ET.parse(urllib.urlopen(alerts_url % ALERT_ZONES[zone]))
  134. process_alerts(alerts, zone)
  135. # Update current forecasts
  136. """for loc in LOCATIONS:
  137. now=datetime.now()
  138. nowString=datetime.strftime(now,"%Y-%m-%dT%H:%M")
  139. laterString=datetime.strftime(now + timedelta(days=7),"%Y-%m-%dT%H:%M")
  140. coords=coords_for_zipcode(LOCATIONS[loc], NOAA)
  141. forecast=ET.parse(NOAA.service.NDFDgen(coords[0], coords[1],
  142. 'time-series', nowString, laterString,
  143. (1,1,1,1,1,1,1,1,1,1,1,1)))
  144. print forecast[0]"""
  145. # url = f_url % (lat, lon)
  146. # doc = ET.fromstring(urllib.urlopen(url))
  147. # forecasts=[]
  148. # for node in dom.getElementsByTagNameNS