Class: Barometer::WeatherService::WeatherDotCom

Inherits:
Barometer::WeatherService show all
Defined in:
lib/barometer/weather_services/weather_dot_com.rb

Overview

Weather.com

www.weather.com

  • usage restrictions: YES … many !!!

  • key required: YES (partnerid & licensekey)

  • registration required: YES

  • supported countries: US (by zipcode), International (by Weather Location ID)

performs geo coding

  • city: PARTIAL (just a name)

  • coordinates: YES

time info

  • sun rise/set: YES

  • provides timezone: NO, but provides a utc offset

  • requires TZInfo: NO

resources

  • API: ?

Possible queries:

where query can be:

  • zipcode (US) [5 digits only]

  • Weather Location ID (International)

Weather.com terms of use

There are many conditions when using weather.com. Please read the EULA you received when you registered for your API keys. In a nutshell (but not limited to), do the following:

  • display the weather.com links (all 5)

  • respect the data refresh rates

  • do not alter/delete content

  • display when weather was last updated

  • do not display data in combination with other 3rd party data (except NOAA or GOV)

  • do not reproduce, rent, lease, lend, distribute or re-market data

  • do not resell

  • do not use in combination with a service that charges a fee

  • do not use in a mobile application

  • use the images properly

  • do not display weather for more then 3 locations at a time

  • do not allow the data to be scraped (via robots, spiders, web crawlers, etc)

  • do not use the latitude and longitude information

notes

  • the Weather Location ID is a propreitary number (shared with yahoo.com)

TODO

  • improve “forecasted_wet_by_icon?” to determine if day or night and use right code

  • improve “forecasted_sunny_by_icon?” to determine if day or night and use right code

  • improve “forcasted_wet_by_humidity?” to use forecasted values

  • improve “forcasted_windy?” to use forecasted values

  • collect moon and uv information

Constant Summary collapse

@@partner_key =
nil
@@license_key =
nil

Class Method Summary collapse

Methods inherited from Barometer::WeatherService

_build_extra, _build_local_time, _build_station, _current_result, _forecast_result, _keys=, _links_result, _local_time, _location_result, _measure, _meets_requirements?, _parse_full_timezone, _station_result, _sun_result, _supports_country?, _time_result, _timezone, _timezone_result, measure, source

Class Method Details

._accepted_formatsObject



77
# File 'lib/barometer/weather_services/weather_dot_com.rb', line 77

def self._accepted_formats; [:short_zipcode, :weather_id]; end

._build_current(data, metric = true) ⇒ Object

Raises:

  • (ArgumentError)


118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/barometer/weather_services/weather_dot_com.rb', line 118

def self._build_current(data, metric=true)
  raise ArgumentError unless data.is_a?(Hash)
  current = Measurement::Result.new
  if data
    if data['cc']
      current.updated_at = Data::LocalDateTime.parse(data['cc']['lsup'])
      current.icon = data['cc']['icon']
      current.condition = data['cc']['t']
      current.humidity = data['cc']['hmid'].to_i
      current.temperature = Data::Temperature.new(metric)
      current.temperature << data['cc']['tmp']
      current.dew_point = Data::Temperature.new(metric)
      current.dew_point << data['cc']['dewp']
      current.wind_chill = Data::Temperature.new(metric)
      current.wind_chill << data['cc']['flik']
      current.visibility = Data::Distance.new(metric)
      current.visibility << data['cc']['vis']
      if data['cc']['wind']
        current.wind = Data::Speed.new(metric)
        current.wind << data['cc']['wind']['s']
        current.wind.degrees = data['cc']['wind']['d'].to_f
        current.wind.direction = data['cc']['wind']['t']
      end
      if data['cc']['bar']
        current.pressure = Data::Pressure.new(metric)
        current.pressure << data['cc']['bar']['r']
      end
    end
  end
  current
end

._build_forecast(data, metric = true) ⇒ Object

Raises:

  • (ArgumentError)


150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/barometer/weather_services/weather_dot_com.rb', line 150

def self._build_forecast(data, metric=true)
  raise ArgumentError unless data.is_a?(Hash)
  forecasts = Measurement::ResultArray.new

  if data && data['dayf'] && data['dayf']['day']
    local_date = data['dayf']['lsup']
    data['dayf']['day'].each do |forecast|
      day_measurement = Measurement::Result.new
      night_measurement = Measurement::Result.new
      
      # as stated by weather.com "day = 7am-7pm"
      # and "night = 7pm-7am"
      date = Date.parse(forecast['dt'])
      date_string = date.strftime("%b %d")
      day_measurement.valid_start_date = Data::LocalDateTime.new(date.year,date.month,date.day,7,0,0)
      day_measurement.valid_end_date = Data::LocalDateTime.new(date.year,date.month,date.day,18,59,59)
      night_measurement.valid_start_date = Data::LocalDateTime.new(date.year,date.month,date.day,19,0,0)
      night_measurement.valid_end_date = Data::LocalDateTime.new(date.year,date.month,date.day+1,6,59,59)
      
      high = Data::Temperature.new(metric)
      high << forecast['hi']
      low = Data::Temperature.new(metric)
      low << forecast['low']
      day_measurement.high = high
      day_measurement.low = low
      night_measurement.high = high
      night_measurement.low = low
      
      # build sun
      rise_local_time = Data::LocalTime.parse(forecast['sunr'])
      set_local_time = Data::LocalTime.parse(forecast['suns'])
      sun = Data::Sun.new(rise_local_time, set_local_time)
      day_measurement.sun = sun
      night_measurement.sun = sun
      
      if forecast['part']
        forecast['part'].each do |part|
          if part['p'] == 'd'
            # add this to the day
            day_measurement.description = "#{date_string} - Day"
            day_measurement.condition = part['t']
            day_measurement.icon = part['icon']
            day_measurement.pop = part['ppcp'].to_i
            day_measurement.humidity = part['hmid'].to_i
            
            if part['wind']
              day_measurement.wind = Data::Speed.new(metric)
              day_measurement.wind << part['wind']['s']
              day_measurement.wind.degrees = part['wind']['d'].to_i
              day_measurement.wind.direction = part['wind']['t']
            end
            
          elsif part['p'] == 'n'  
            # add this to the night
            night_measurement.description = "#{date_string} - Night"
            night_measurement.condition = part['t']
            night_measurement.icon = part['icon']
            night_measurement.pop = part['ppcp'].to_i
            night_measurement.humidity = part['hmid'].to_i
            
            if part['wind']
              night_measurement.wind = Data::Speed.new(metric)
              night_measurement.wind << part['wind']['s']
              night_measurement.wind.degrees = part['wind']['d'].to_i
              night_measurement.wind.direction = part['wind']['t']
            end
            
          end
        end
      end
      forecasts << day_measurement
      forecasts << night_measurement
    end
  end
  forecasts
end


108
109
110
111
112
113
114
115
116
# File 'lib/barometer/weather_services/weather_dot_com.rb', line 108

def self._build_links(data)
  links = {}
  if data && data['lnks'] && data['lnks']['link']
    data['lnks']['link'].each do |link_hash|
      links[link_hash['t']] = link_hash['l']
    end
  end
  links
end

._build_location(data, geo = nil) ⇒ Object

Raises:

  • (ArgumentError)


227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/barometer/weather_services/weather_dot_com.rb', line 227

def self._build_location(data, geo=nil)
  raise ArgumentError unless data.is_a?(Hash)
  raise ArgumentError unless (geo.nil? || geo.is_a?(Data::Geo))
  location = Data::Location.new
  # use the geocoded data if available, otherwise get data from result
  if geo
    location.city = geo.locality
    location.state_code = geo.region
    location.country = geo.country
    location.country_code = geo.country_code
    location.latitude = geo.latitude
    location.longitude = geo.longitude
  else
    if data && data['loc']
      location.name = data['loc']['dnam']
      location.latitude = data['loc']['lat']
      location.longitude = data['loc']['lon']
    end
  end
  location
end

._build_sun(data) ⇒ Object

Raises:

  • (ArgumentError)


249
250
251
252
253
254
255
256
257
258
259
260
# File 'lib/barometer/weather_services/weather_dot_com.rb', line 249

def self._build_sun(data)
  raise ArgumentError unless data.is_a?(Hash)
  sun = nil
  if data
    if data['loc']
      rise_local_time = Data::LocalTime.parse(data['loc']['sunr'])
      set_local_time = Data::LocalTime.parse(data['loc']['suns'])
    end  
    sun = Data::Sun.new(rise_local_time, set_local_time)
  end
  sun || Data::Sun.new
end

._build_timezone(data) ⇒ Object

first try to match the zone code, otherwise use the zone offset



93
94
95
96
97
98
99
100
101
102
# File 'lib/barometer/weather_services/weather_dot_com.rb', line 93

def self._build_timezone(data)
  if data
    if data['cc'] && data['cc']['lsup'] &&
       (zone_match = data['cc']['lsup'].match(/ ([A-Z]{1,4})$/))
      Data::Zone.new(zone_match[1])
    elsif data['loc'] && data['loc']['zone']
      Data::Zone.new(data['loc']['zone'].to_f)
    end
  end
end

._fetch(query, metric = true) ⇒ Object

use HTTParty to get the current weather



264
265
266
267
268
269
270
271
272
273
274
275
276
# File 'lib/barometer/weather_services/weather_dot_com.rb', line 264

def self._fetch(query, metric=true)
  return unless query
  puts "fetch weather.com: #{query.q}" if Barometer::debug?
  self.get(
    "http://xoap.weather.com/weather/local/#{query.q}",
    :query => { :par => @@partner_key, :key => @@license_key,
      :prod => "xoap", :link => "xoap", :cc => "*",
      :dayf => "5", :unit => (metric ? 'm' : 's')
    },
    :format => :xml,
    :timeout => Barometer.timeout
  )['weather']
end

._has_keys?Boolean

Returns:

  • (Boolean)


79
# File 'lib/barometer/weather_services/weather_dot_com.rb', line 79

def self._has_keys?; !@@partner_key.nil? && !@@license_key.nil?; end

._parse_local_time(data) ⇒ Object



104
105
106
# File 'lib/barometer/weather_services/weather_dot_com.rb', line 104

def self._parse_local_time(data)
  (data && data['loc']) ? Data::LocalTime.parse(data['loc']['tm']) : nil
end

._requires_keys?Boolean

Returns:

  • (Boolean)


80
# File 'lib/barometer/weather_services/weather_dot_com.rb', line 80

def self._requires_keys?; true; end

._source_nameObject

PRIVATE If class methods could be private, the remaining methods would be.



76
# File 'lib/barometer/weather_services/weather_dot_com.rb', line 76

def self._source_name; :weather_dot_com; end

._sunny_icon_codesObject



86
87
88
89
# File 'lib/barometer/weather_services/weather_dot_com.rb', line 86

def self._sunny_icon_codes
  codes = [19, 22, 28, 30, 32, 34, 36]
  codes.collect {|c| c.to_s}
end

._wet_icon_codesObject



82
83
84
85
# File 'lib/barometer/weather_services/weather_dot_com.rb', line 82

def self._wet_icon_codes
  codes = (0..18).to_a + [35] + (37..43).to_a + (45..47).to_a
  codes.collect {|c| c.to_s}
end

.keys=(keys) ⇒ Object

Raises:

  • (ArgumentError)


63
64
65
66
67
68
69
# File 'lib/barometer/weather_services/weather_dot_com.rb', line 63

def self.keys=(keys)
  raise ArgumentError unless keys.is_a?(Hash)
  keys.each do |key, value|
    @@partner_key = value.to_s if key.to_s.downcase == "partner"
    @@license_key = value.to_s if key.to_s.downcase == "license"
  end
end