wu_forecaster.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  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. WeatherUnderground RSS Structure:
  5. feed
  6. entries
  7. 0 - current weather conditions
  8. summary_detail
  9. value - String of Temp, Hum, Pres, Cond, WindDir, WindSpd, CondImg
  10. """
  11. from datetime import datetime, timedelta
  12. from dateutil.parser import *
  13. import urllib
  14. import feedparser
  15. import elementtree.ElementTree as ET
  16. import time
  17. from almanac.models import WeatherConditions, WeatherAlert, WeatherForecast
  18. from directory.models import Town
  19. ALERT_ZONES={"Coastal_Hancock_County":'MEZ029',}
  20. LOCATIONS={'04624':'Blue Hill',
  21. '04627':'Stonington',}
  22. weather_url='http://rss.wunderground.com/auto/rss_full/ME/%s.xml?units=english'
  23. alerts_url='http://www.weather.gov/alerts-beta/wwaatmget.php?x=%s'
  24. def coords_for_zipcode(zipcode, client):
  25. coords=ET.fromstring(client.service.LatLonListZipCode(zipcode))
  26. coords=coords[0].text.split(',')
  27. return coords
  28. def update_conditions():
  29. """
  30. function process_conditions
  31. input: ElementTree object of weather conditions
  32. result: Look up new weather condition and save it to the db
  33. """
  34. for location in LOCATIONS:
  35. feed=feedparser.parse(weather_url % location)
  36. args={}
  37. args['observation_time']=parse(feed.feed.updated, ignoretz=True)
  38. args['town']=Town.objects.get(name=LOCATIONS.get(location))
  39. # First, we update the current conditions, assuming we have an update
  40. try:
  41. WeatherConditions.objects.get(observation_time__exact=args['observation_time'], town__exact=args['town'])
  42. print "Passing condition updates for %s..." % args['town']
  43. pass
  44. except:
  45. print "Going ahead with condition updates for %s..." % args['town']
  46. feed_cond=feed.entries[0].summary.split(" |")
  47. try:
  48. args['temperature']=float(feed_cond[0].split(": ")[1][0:4])
  49. except:
  50. args['temperature']=float(feed_cond[0].split(": ")[1][0:3])
  51. args['humidity']=feed_cond[1].split(": ")[1]
  52. args['pressure']=feed_cond[2].split(": ")[1].replace(' ', '')
  53. args['conditions']=feed_cond[3].split(": ")[1]
  54. args['wind_dir']=feed_cond[4].split(": ")[1]
  55. args['wind_speed']=float(feed_cond[5].split(": ")[1].split("mph")[0])
  56. condition=WeatherConditions.objects.create(**args)
  57. condition.save()
  58. # Now we try to get forecast updates which are everything after the current conditions:
  59. for entry in feed.entries[1:]:
  60. forecast_data=entry.summary.split(" - ")
  61. args={}
  62. args['observation_time']=parse(feed.feed.updated, ignoretz=True)
  63. print LOCATIONS.get(location)
  64. args['town']=Town.objects.get(name=LOCATIONS.get(location))
  65. args['period']=forecast_data[0]
  66. try:
  67. WeatherForecast.objects.get(observation_time__exact=args['observation_time'], period=args['period'], town__exact=args['town'])
  68. print "Passing forecast update for %s..." % args['town']
  69. pass
  70. except:
  71. print "Going ahead with forecasts for %s" % args['town']
  72. try:
  73. args['conditions'] = forecast_data[1]
  74. forecast=WeatherForecast.objects.create(**args)
  75. forecast.save()
  76. except:
  77. print "Oops, no forecast data"
  78. pass
  79. update_conditions()
  80. def process_alerts(alerts, zone):
  81. root=alerts.getroot()
  82. if root[6][3].text.strip(" ").strip("\n ")=="There are no active watches, warnings or advisories":
  83. pass
  84. else: # We have a alert, so lets process
  85. updated=parse(root[6][1].text)
  86. zone_id=ALERT_ZONES[zone]
  87. zone=zone.replace("_", " ")
  88. summary=root[6][5].text.strip("\n")
  89. effective=parse(root[6][6].text)
  90. expires=parse(root[6][7].text)
  91. status=root[6][8].text.strip("\n")
  92. msg_type=root[6][9].text.strip("\n")
  93. urgency=root[6][11].text.strip("\n")
  94. severity=root[6][12].text.strip("\n")
  95. certainty=root[6][13].text.strip("\n")
  96. area=root[6][14].text.strip("\n")
  97. try:
  98. WeatherAlert.objects.get(summary__exact=summary)
  99. pass
  100. except:
  101. alert=WeatherAlert.objects.create(updated=updated,
  102. zone_id=zone_id,
  103. zone=zone,
  104. summary=summary,
  105. effective=effective,
  106. expires=expires,
  107. status=status,
  108. msg_type=msg_type,
  109. urgency=urgency,
  110. severity=severity,
  111. certainty=certainty,
  112. area=area)
  113. alert.save()
  114. # Add alerts for given state
  115. #for zone in ALERT_ZONES:
  116. # alerts=ET.parse(urllib.urlopen(alerts_url % ALERT_ZONES[zone]))
  117. # process_alerts(alerts, zone)
  118. # Update current forecasts
  119. '''for loc in LOCATIONS:
  120. now=datetime.now()
  121. nowString=datetime.strftime(now,"%Y-%m-%dT%H:%M")
  122. laterString=datetime.strftime(now + timedelta(days=7),"%Y-%m-%dT%H:%M")
  123. coords=coords_for_zipcode(LOCATIONS[loc], NOAA)
  124. forecast=ET.parse(NOAA.service.NDFDgen(coords[0], coords[1],
  125. 'time-series', nowString, laterString,
  126. (1,1,1,1,1,1,1,1,1,1,1,1)))
  127. print forecast[0]'''
  128. #url = f_url % (lat, lon)
  129. #doc = ET.fromstring(urllib.urlopen(url))
  130. #forecasts=[]
  131. #for node in dom.getElementsByTagNameNS