Forum: Ruby Metar Weather Grabber

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
4ae3c0b56fcf66f8383ecb73cc8d956e?d=identicon&s=25 Chris Winslett (supasta)
on 2006-04-13 23:25
I don't want to pay money to get weather feeds from a bunch of different
countries.  So I took my hand at writing my own.  It is for an ajax
service that grabs the XML.

If you use this, expand on it.  If you expand on it, post it back on
here.  There are somethings I haven't gotten to yet.  The usage of the
weather codes needs to get better too.

#!/usr/bin/ruby

require 'rexml/document'
require 'open-uri'
require 'pp'

include REXML

class Weather
  attr_reader :wind, :temperature, :dew_point, :sky, :sky_icon

  def initialize(metar_string)
    @metar_string = metar_string
    @wind = self.set_wind()
    @temperature, @dew_point = self.set_temperature()
    @sky, @sky_icon = self.set_sky()
  end

  def set_wind
    sample_string = $& if @metar_string =~
/(\d{3}|VRB)[G]{0,1}\d{1,4}KT/

    direction = self.get_cardinal_direction(sample_string[0...3])
    speed =
sample_string[sample_string.rindex(/\d{1,4}KT/)..sample_string.length-3].to_i

    "#{direction} at #{speed}mph"
  end

  def get_cardinal_direction(degrees)
    case degrees.to_i
    when 0:    "Variable"
    when 1..4:      "N"
    when 5..35:     "NNE"
    when 36..55:    "NE"
    when 56..85:    "ENE"
    when 86..95:    "E"
    when 96..125:   "ESE"
    when 126..135:  "SE"
    when 136..175:  "SSE"
    when 176..185:  "S"
    when 185..215:  "SSW"
    when 216..225:  "W"
    when 226..265:  "WSW"
    when 265..275:  "W"
    when 275..295:  "WNW"
    when 296..305:  "NW"
    when 306..346:  "NNW"
    when 347..370:  "N"
    else		 "Gusty"
    end
  end

  def set_temperature
    sample_string = $&.strip if @metar_string =~  /
[M]{0,1}\d{2}\/[M]{0,1}\d{2} /

    celcius    = sample_string[0..2].to_i
    fahrenheit = ( ( celcius.to_i * 9 ) / 5 + 32 )

    dew_point_celcius       =
sample_string[3..sample_string.length-1].to_i
    dew_point_fahrenheit    = ( ( dew_point_celcius * 9 ) / 5 + 32)

    ["#{fahrenheit} F (#{celcius} C)", "#{dew_point_fahrenheit} F
(#{dew_point_celcius} C)"]
  end

  def set_sky
    sky = $&.strip if @metar_string =~
/(SKC|FEW|SCT|BKN|OVC|CLR)[CB]{0,1}/
    sky = $&.strip if @metar_string =~
/(RA|DZ|SN|GR|SQ|GS|SG|IC|PE|BR|FG|FU|HZ|VA|DU|SA|SS|DS|FC|MI|BC|DR|BL|SH|TS|FZ)\+{1}/

    weather_codes = {	"SKC"=> ["Scattered Clouds", 30],
			"FEW"=> ["Sunny"           , 32],
			"SCT"=> ["Partly Cloudy"   , 29],
			"BKN"=> ["Mostly Cloudy"   , 28],
			"OVC"=> ["Overcast"        , 26],
			"CLR"=> ["Sunny"           , 32],
			"RA"=> ["Raining"          , 40],
			"DZ"=> ["Drizzle"          , 39],
			"SN"=> ["Snow"             , 16],
			"GR"=> ["Hail"             , 35],
			"SQ"=> ["Squalls"          , nil],
			"GS"=> ["Small Hail"       , 35],
			"SG"=> ["Snow Grains"      , 15],
			"IC"=> ["Diamond Dust"     , nil],
			"PE"=> ["Ice Pellets"      , nil],
			"BR"=> ["Mist"             , nil],
			"FG"=> ["Fog"              , 20],
			"FU"=> ["Smoke"            , 22],
			"HZ"=> ["Haze"             , 21],
			"VA"=> ["Volcanic Ash"     , nil],
			"DU"=> ["Widespead dust"   , nil],
			"SA"=> ["Sand"             , nil],
			"SS"=> ["Sandstorm"        , nil],
			"DS"=> ["Duststorm"        , nil],
			"FC"=> ["Funnel Cloud"     , nil],
			"MI"=> ["Shallow"          , nil],
			"BC"=> ["Patches"          , nil],
			"DR"=> ["Drifting"         , nil],
			"BL"=> ["Blowing"          , nil],
			"SH"=> ["Showers"          , nil],
			"TS"=> ["Thunderstorm"     , 1],
			"FZ"=> ["Supercooled(Freezing)", nil],
			"+" => ["Heavy"            , nil],
			"TCU"=> ["Towering Cumulonimbs", nil]
                     }
    icon = ''
    weather_codes.each do | code, description |
      sky = sky.gsub(code, description[0])
      icon = description[1] if !description[1].nil?
    end

    [sky, icon]
  end
end

# Set up the XML document
xml_write = REXML::Document.new('<return><method/><result/></return>')
xml_write.elements["//method"].text = "updateWeather"

#Array of Cities and Local from the Weather xml information
cities_url = {"New York, NY"   =>
"ftp://weather.noaa.gov/data/observations/metar/stations/KLGA.TXT",
             "London, UK"     =>
"ftp://weather.noaa.gov/data/observations/metar/stations/EGLL.TXT"}

cities_url.each do |location, url|

  current_weather = Element.new()
  current_weather.add_element("CurrentWeather")
  current_weather.elements["//CurrentWeather"].add_attribute("label",
location)

  element_write =
current_weather.elements["//CurrentWeather[@label='"+location+"']"]

  metar   = Document.new(open(url))
  weather = Weather.new(metar.to_s.gsub("\n", " "))

  element_write.add_element("DewPoint").text          =
weather.dew_point
  element_write.add_element("Temperature").text       =
weather.temperature
  element_write.add_element("Wind").text              = weather.wind
  element_write.add_element("SkyConditions").text     = weather.sky
  element_write.add_element("SkyConditionsIcon").text = weather.sky_icon
  element_write.add_element("RelativeHumidity").text  = metar[0]
  xml_write.elements["//result"].add_element(current_weather.elements["//CurrentWeather"])
end

xml_writable = File.new("public_html/weather.xml", "w+")
xml_write.write(xml_writable, -1, true)
A9c4658e9e475e13d790ae419acf01b6?d=identicon&s=25 Simon Kröger (Guest)
on 2006-04-14 00:09
(Received via mailing list)
Chris Winslett wrote:
> I don't want to pay money to get weather feeds from a bunch of different
> countries.  So I took my hand at writing my own.  It is for an ajax
> service that grabs the XML.
>
> If you use this, expand on it.  If you expand on it, post it back on
> here.  There are somethings I haven't gotten to yet.  The usage of the
> weather codes needs to get better too.

Hi Chris,
is there something wrong with the decoded data?

----------------------------------------------------------------------
require 'open-uri'

url = 'ftp://weather.noaa.gov/data/observations/metar/decoded/KLGA.TXT'
open(url) do |f|
  weather = f.read.to_a.map {|line| line.strip.split(':')}
  label = weather.shift.first.split(',').first
  date = weather.shift.first
  puts %Q[<CurrentWeather label = "#{label}" date = "#{date}">]
  weather.each do |w|
    key = w.first.tr('()', ' ').delete(' ')
    puts %Q[  <#{key}>#{w[1].strip}</#{key}>]
  end
  puts '</CurrentWeather>'
end
----------------------------------------------------------------------

output:
----------------------------------------------------------------------
<CurrentWeather label = "New York" date = "Apr 13, 2006 - 04">
  <Wind>from the NW (320 degrees) at 9 MPH (8 KT)</Wind>
  <Visibility>10 mile(s)</Visibility>
  <Skyconditions>partly cloudy</Skyconditions>
  <Temperature>75.0 F (23.9 C)</Temperature>
  <DewPoint>35.1 F (1.7 C)</DewPoint>
  <RelativeHumidity>23%</RelativeHumidity>
  ...
</CurrentWeather>
----------------------------------------------------------------------

cheers

Simon
4ae3c0b56fcf66f8383ecb73cc8d956e?d=identicon&s=25 Christopher Winslett (Guest)
on 2006-04-14 04:14
Nope.

I guess I just wanted to learn how to use regular expressions.  I wish I
would have found those a couple of hours ago.

Thanks for the post, that will help a lot.



Simon Kröger wrote:
> Chris Winslett wrote:
>> I don't want to pay money to get weather feeds from a bunch of different
>> countries.  So I took my hand at writing my own.  It is for an ajax
>> service that grabs the XML.
>>
>> If you use this, expand on it.  If you expand on it, post it back on
>> here.  There are somethings I haven't gotten to yet.  The usage of the
>> weather codes needs to get better too.
>
> Hi Chris,
> is there something wrong with the decoded data?
>
> ----------------------------------------------------------------------
> require 'open-uri'
>
> url = 'ftp://weather.noaa.gov/data/observations/metar/decoded/KLGA.TXT'
> open(url) do |f|
>   weather = f.read.to_a.map {|line| line.strip.split(':')}
>   label = weather.shift.first.split(',').first
>   date = weather.shift.first
>   puts %Q[<CurrentWeather label = "#{label}" date = "#{date}">]
>   weather.each do |w|
>     key = w.first.tr('()', ' ').delete(' ')
>     puts %Q[  <#{key}>#{w[1].strip}</#{key}>]
>   end
>   puts '</CurrentWeather>'
> end
> ----------------------------------------------------------------------
>
> output:
> ----------------------------------------------------------------------
> <CurrentWeather label = "New York" date = "Apr 13, 2006 - 04">
>   <Wind>from the NW (320 degrees) at 9 MPH (8 KT)</Wind>
>   <Visibility>10 mile(s)</Visibility>
>   <Skyconditions>partly cloudy</Skyconditions>
>   <Temperature>75.0 F (23.9 C)</Temperature>
>   <DewPoint>35.1 F (1.7 C)</DewPoint>
>   <RelativeHumidity>23%</RelativeHumidity>
>   ...
> </CurrentWeather>
> ----------------------------------------------------------------------
>
> cheers
>
> Simon
This topic is locked and can not be replied to.