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