]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blob - data/rbot/plugins/forecast.rb
Plugin header boilerplating.
[user/henk/code/ruby/rbot.git] / data / rbot / plugins / forecast.rb
1 #-- vim:sw=2:et
2 #++
3 #
4 # :title: Forecast plugin for rbot
5 #
6 # Author:: MrChucho (mrchucho@mrchucho.net)
7 # Copyright:: (C) 2006 Ralph M. Churchill
8
9 require 'soap/wsdlDriver'
10 require 'open-uri'
11 require 'rexml/document'
12 require 'erb'
13
14
15 class LatLong
16     include ERB::Util
17     # Determine the latitude and longitude of a location. City, State and/or ZIP
18     # are all valid.
19     # [+return+] latitude,longitude
20     def get_lat_long(loc)
21         loc = url_encode(loc)
22         url="http://api.local.yahoo.com/MapsService/V1/geocode?appid=mrchucho_rbot_weather&location=#{loc}"
23         lat,long = 0,0
24         begin
25             open(url) do |xmldoc|
26                 results = (REXML::Document.new xmldoc).root
27                 lat = results.elements["//Latitude/text()"].to_s
28                 long = results.elements["//Longitude/text()"].to_s
29             end
30         rescue => err
31             raise err #?
32         end
33         return lat.to_f,long.to_f
34     end
35 end
36
37 class Forecast
38     WSDL_URI="http://www.nws.noaa.gov/forecasts/xml/SOAP_server/ndfdXMLserver.php?wsdl"
39     def initialize(lat,long)
40         @lat,@long=lat,long
41         # this extra step is for backward/forward compatibility
42         factory = SOAP::WSDLDriverFactory.new(WSDL_URI)
43         @forecaster=factory.respond_to?(:create_rpc_driver) ?
44             factory.create_rpc_driver : factory.create_driver
45     end
46     def forecast
47         return parse(retrieve),Time.new
48     end
49 private
50     def retrieve 
51         forecast = @forecaster.NDFDgenByDay(
52             @lat,@long,Time.now.strftime("%Y-%m-%d"),2,"24 hourly")
53         (REXML::Document.new(forecast)).root
54     end
55     def parse(xml)
56         msg = String.new
57         (1..2).each do |day|
58             d  = (day==1) ? 'Today' : 'Tomorrow'
59             hi = xml.elements["//temperature[@type='maximum']/value[#{day}]/text()"]
60             lo = xml.elements["//temperature[@type='minimum']/value[#{day}]/text()"]
61             w  = xml.elements["//weather/weather-conditions[#{day}]/@weather-summary"]
62             precip_am = xml.elements["//probability-of-precipitation/value[#{day*2-1}]/text()"]
63             precip_pm = xml.elements["//probability-of-precipitation/value[#{day*2}]/text()"]
64             msg += "#{d}: Hi #{hi} Lo #{lo}, #{w}. Precip: AM #{precip_am}% PM #{precip_pm}%\n"
65         end
66         msg
67     end
68 end
69
70 class ForecastPlugin < Plugin
71     USAGE='forecast <location> => show the 2-day forecast for a location. Location can be any combination of City, State, Country and ZIP'
72     def help(plugin,topic="")
73         USAGE
74     end
75     def usage(m,params={})
76         m.reply USAGE
77     end
78     def initialize
79         super
80         # this plugin only wants to store strings
81         class << @registry
82             def store(val)
83                 val
84             end
85             def restore(val)
86                 val
87             end
88         end
89         @forecast_cache = Hash.new
90     end
91
92     def forecast(m,params)
93         if params[:location] and params[:location].any?
94             loc = params[:location].join
95             @registry[m.sourcenick] = loc
96             get_forecast(m,loc)
97         else
98             if @registry.has_key?(m.sourcenick) then
99                 loc = @registry[m.sourcenick]
100                 get_forecast(m,loc)
101             else
102                 m.reply "Please specifiy the City, State or ZIP"
103             end
104         end
105     end
106     
107     def get_forecast(m,loc)
108         begin
109             if @forecast_cache.has_key?(loc) and
110                 Time.new - @forecast_cache[loc][:date] < 3600
111                 forecast = @forecast_cache[loc][:forecast]
112                 forecast_date = @forecast_cache[loc][:date]
113             else
114                 begin
115                     l = LatLong.new
116                     f = Forecast.new(*l.get_lat_long(loc))
117                     forecast,forecast_date = f.forecast
118                 rescue => err
119                     m.reply err
120                 end
121             end
122             if forecast
123                 m.reply forecast
124                 @forecast_cache[loc] = {}
125                 @forecast_cache[loc][:forecast] = forecast
126                 @forecast_cache[loc][:date] = forecast_date
127             else
128                 m.reply "Couldn't find forecast for #{loc}"
129             end
130         rescue => e
131             m.reply "ERROR: #{e}"
132         end
133     end
134 end
135 plugin = ForecastPlugin.new
136 plugin.map 'forecast *location', :defaults => {:location => false}