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