forecaster.py 4.9 KB

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