Error processing request
Parameters
CONTENT_LENGTH | 0 |
REQUEST_METHOD | GET |
REQUEST_URI | /revision/Metar+data?V=10 |
QUERY_STRING | V=10 |
CONTENT_TYPE | |
DOCUMENT_URI | /revision/Metar+data |
DOCUMENT_ROOT | /var/www/nikit/nikit/nginx/../docroot |
SCGI | 1 |
SERVER_PROTOCOL | HTTP/1.1 |
HTTPS | on |
REMOTE_ADDR | 172.69.6.125 |
REMOTE_PORT | 44866 |
SERVER_PORT | 4443 |
SERVER_NAME | wiki.tcl-lang.org |
HTTP_HOST | wiki.tcl-lang.org |
HTTP_CONNECTION | Keep-Alive |
HTTP_ACCEPT_ENCODING | gzip, br |
HTTP_X_FORWARDED_FOR | 3.128.197.221 |
HTTP_CF_RAY | 885fef9af8e2616b-ORD |
HTTP_X_FORWARDED_PROTO | https |
HTTP_CF_VISITOR | {"scheme":"https"} |
HTTP_ACCEPT | */* |
HTTP_USER_AGENT | Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; [email protected]) |
HTTP_CF_CONNECTING_IP | 3.128.197.221 |
HTTP_CDN_LOOP | cloudflare |
HTTP_CF_IPCOUNTRY | US |
Body
Error
Unknow state transition: LINE -> END
-code
1
-level
0
-errorstack
INNER {returnImm {Unknow state transition: LINE -> END} {}} CALL {my render_wikit {Metar data} {[jdc] 22-jun-2007
**Metar data package**
[METAR] data can be obtained from http://www.noaa.org/ using ftp. This package can query data from the NOAA server and parse METAR data (obtained with this package or otherwise).
----
[KPV] See also [TclWeather] and [A Very Simple Weather App] both of which download and parse METAR data.
----
package provide tclmetar 0.1
package require ftp
namespace eval ::tclmetar {
variable ftpsock
variable metar_keys {abbrev raw year month day hour minute corrected winddir winddirstr windspeed windgust windvarfrom windvarfromstr windvarto windvartostr temperature dewpoint airpressure cloudstype cloudsheight toweringcumulus cumulonimbus weather visibility}
}
proc ::tclmetar::get_winddirstr { winddir } {
if { [string is integer -strict $winddir] } {
set wsi [expr {int(($winddir+11.25)/22.5)}]
return [lindex {N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW N} $wsi]
}
return $winddir
}
proc ::tclmetar::parse_wind { f wd winddirnm winddirstrnm ws windspeednm wg windgustnm wu } {
upvar $winddirnm winddir
upvar $winddirstrnm winddirstr
upvar $windspeednm windspeed
upvar $windgustnm windgust
set winddir [string trimleft $wd "0"]
if { [string length $winddir] == 0 } {
set winddir 0
}
set windspeed [string trimleft $ws "0"]
if { [string length $windspeed] == 0 } {
set windspeed 0
}
set windgust [string trimleft [string range $wg 1 end] "0"]
if { [string length $windgust] == 0 } {
set windgust 0
}
switch -exact -- $wu {
"KT" {
set windspeed [expr {round($windspeed * 1.852)}]
set windgust [expr {round($windgust * 1.852)}]
}
"MPS" {
set windspeed [expr {round($windspeed * 3.6)}]
set windgust [expr {round($windgust * 3.6)}]
}
"KMH" {
}
}
set winddirstr [get_winddirstr $winddir]
return
}
proc ::tclmetar::parse_wind_variability { wvf windvarfromnm windvarfromstrnm wvt windvartonm windvartostrnm } {
upvar $windvarfromnm windvarfrom
upvar $windvartonm windvarto
upvar $windvarfromstrnm windvarfromstr
upvar $windvartostrnm windvartostr
set windvarfrom [string trimleft $wvf "0"]
if { [string length $windvarfrom] == 0 } {
set windvarfrom 0
}
set windvarfromstr [get_winddirstr $windvarfrom]
set windvarto [string trimleft $wvt "0"]
if { [string length $windvarto] == 0 } {
set windvarto 0
}
set windvartostr [get_winddirstr $windvarto]
return
}
proc ::tclmetar::parse_temperature { f tempnm } {
upvar $tempnm temp
if { [string match "M*" $f] } {
set temp -[string trimleft [string range $f 1 end] "0"]
if { [string equal $temp "-"] } {
set temp "0"
}
} else {
set temp [string trimleft $f "0"]
if { [string length $temp] == 0 } {
set temp "0"
}
}
}
proc ::tclmetar::parse_air_pressure { pv airpressurenm pu } {
upvar $airpressurenm airpressure
switch -exact -- $pu {
"A" {
set airpressure [string trimleft [string range $pv 0 1] "0"].[string range $pv 2 3]
set airpressure [expr {$airpressure * 0.033864}]
}
"Q" {
set airpressure [expr {[string trimleft $pv "0"] / 1000.0}]
}
}
return
}
proc ::tclmetar::parse_clouds { ct cloudstypenm ch cloudsheightnm cbtcu toweringcumulusnm cumulonimbusnm } {
upvar $cloudstypenm cloudstype
upvar $cloudsheightnm cloudsheight
upvar $toweringcumulusnm toweringcumulus
upvar $cumulonimbusnm cumulonimbus
switch -exact -- $ct {
SKC -
CLR -
NSC {
if { [string equal $cloudstype "<unknown>"] } {
set cloudstype SKC
} else {
lappend cloudstype SKC
}
}
FEW -
SCT -
BKN -
OVC {
if { [string equal $cloudstype "<unknown>"] } {
set cloudstype $ct
} else {
lappend cloudstype $ct
}
}
}
set ch [string trimleft $ch "0"]
if { [string length $ch] == 0 } {
set ch "0"
}
if { [string equal $cloudsheight "<unknown>"] } {
set cloudsheight [expr {$ch * 30.48}]
} else {
lappend cloudsheight [expr {$ch * 30.48}]
}
switch -exact -- $cbtcu {
CB {
set toweringcumulus 0
set cumulonimbus 1
}
TCU {
set toweringcumulus 1
set cumulonimbus 0
}
default {
set toweringcumulus 0
set cumulonimbus 0
}
}
return
}
proc ::tclmetar::parse_weather { int vic desc wea weathernm } {
upvar $weathernm weather
set wl [list $int $vic $desc $wea]
if { [string equal $weather "<unknown>"] } {
set weather [list $wl]
} else {
lappend weather $wl
}
return
}
proc ::tclmetar::parse_international_visibility { m visibilitynm } {
upvar $visibilitynm visibility
set visibility [string trimleft $m "0"]
if { [string length $visibility] == 0 } {
set visibility 0
}
return
}
proc ::tclmetar::parse_american_visibility { v1 v2 prevf visibilitynm } {
upvar $visibilitynm visibility
if { ([string length $v2] == 0) || [string equal $v2 "0"] } {
set v2 1
}
append v2 ".0"
if { ![string is integer -strict $prevf] } {
set prevf 0
}
set visibility [expr {($prevf + $v1/$v2) * 1609.34}]
return
}
proc ::tclmetar::parse { metarl mi_abbrev } {
set ar(abbrev) $mi_abbrev
set ar(raw) $metarl
set ar(year) "<unknown>"
set ar(month) "<unknown>"
set ar(day) "<unknown>"
set ar(hour) "<unknown>"
set ar(minute) "<unknown>"
set ar(corrected) "<unknown>" ;# bool
set ar(winddir) "<unknown>" ;# 0 = north, 90 = east
set ar(winddirstr) "<unknown>"
set ar(windspeed) "<unknown>" ;# in km/h
set ar(windgust) "<unknown>" ;# in km/h
set ar(windvarfrom) "<unknown>" ;# 0 = north, 90 = east
set ar(windvarfromstr) "<unknown>" ;# 0 = north, 90 = east
set ar(windvarto) "<unknown>" ;# 0 = north, 90 = east
set ar(windvartostr) "<unknown>" ;# 0 = north, 90 = east
set ar(temperature) "<unknown>" ;# in degrees Celcius
set ar(dewpoint) "<unknown>" ;# in degrees Celcius
set ar(airpressure) "<unknown>" ;# in bar
set ar(cloudstype) "<unknown>" ;# list of SKC (sky clear) | FEW | SCT (scattered) | BKN (broken) | OVC (overcast) | CAVOK
set ar(cloudsheight) "<unknown>" ;# list of heights in meter | CAVOK
set ar(toweringcumulus) "<unknown>" ;# bool
set ar(cumulonimbus) "<unknown>" ;# bool
set ar(weather) "<unknown>" ;# in metar abbreviations
set ar(visibility) "<unknown>" ;# in meter
set prevf ""
set mi_abbrev_found 0
foreach f $metarl {
ach f $metarl {
if { [string equal $mi_abbrev $f] } {
set mi_abbrev_found 1
continue
}
}
if { !$mi_abbrev_found && [regexp {([0-9]{4})/([0-9]{2})/([0-9]{2})} $f m y m d] } {
set ar(year) [string trimleft $y "0"]
set ar(month) [string trimleft $m "0"]
set ar(day) [string trimleft $d "0"]
} elseif { !$mi_abbrev_found && [regexp {([0-9]{2}):([0-9]{2})} $f ma h m] } {
set ar(hour) [string trimleft $h "0"]
if { [string length $ar(hour)] == 0 } {
set ar(hour) 0
}
set ar(minute) [string trimleft $m "0"]
if { [string length $ar(minute)] == 0 } {
set ar(minute) 0
}
} elseif { !$mi_abbrev_found } {
continue
} elseif { [string match "RMK*" $f] || [string match "TEMP*" $f] || [string match "NOSIG*" $f] } {
break
} elseif { [regexp {([0-9][0-9])([0-9][0-9])([0-9][0-9])Z} $f ma d h m] } {
# Date/time field
set ar(day) [string trimleft $d "0"]
set ar(hour) [string trimleft $h "0"]
if { [string length $ar(hour)] == 0 } {
set ar(hour) 0
}
set ar(minute) [string trimleft $m "0"]
if { [string length $ar(minute)] == 0 } {
set ar(minute) 0
}
} elseif { [string equal "COR" $f] } {
set ar(corrected) 1
} elseif { [string equal "AUT" $f] } {
set ar(corrected) 0
} elseif { [string match {R[0-9][0-9][LCR]*} $f] } {
# Runway visibility still to be added
} elseif { [regexp {([0-9]{3}|VRB)([0-9]{2,3})(G[0-9]{2,3})?(KT|KMH|MPS)} $f m wd ws wg wu] } {
# Wind field
parse_wind $f $wd ar(winddir) ar(winddirstr) $ws ar(windspeed) $wg ar(windgust) $wu
} elseif { [regexp {([0-9]{3})V([0-9]{3})} $f m wvf wvt] } {
# Wind variability
parse_wind_variability $wvf ar(windvarfrom) ar(windvarfromstr) $wvt ar(windvarto) ar(windvartostr)
} elseif { [regexp {^(M?[0-9][0-9])/+(M?[0-9][0-9])$} $f m temp dewp] } {
# Temperature field
parse_temperature $temp ar(temperature)
parse_temperature $dewp ar(dewpoint)
} elseif { [regexp {(A|Q)([0-9]{4})} $f m pu pv] } {
# Altimeter settings field
parse_air_pressure $pv ar(airpressure) $pu
} elseif { [regexp {(SKC|FEW|SCT|BKN|OVC|CLR|NSC)([0-9]{3})?(CB|TCU)?} $f m ct ch cbtcu] } {
# Clouds field
parse_clouds $ct ar(cloudstype) $ch ar(cloudsheight) $cbtcu ar(toweringcumulus) ar(cumulonimbus)
} elseif { [string equal $f "CAVOK"] } {
set ar(cloudstype) "CAVOK"
set ar(cloudsheight) "CAVOK"
set ar(cumulonimbus) 0
set ar(toweringcumulus) 0
set ar(visibility) 9999
} elseif { [regexp {([\+\-]?)(VC)?(MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PI|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DU|PO|FC|\+FC)} $f m int vic desc wea] } {
# Weather field
parse_weather $int $vic $desc $wea ar(weather)
while { 1 } {
set f [string range $f [string length $m] end]
if { ![regexp {([\+\-]?)(VC)?(MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PI|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DU|PO|FC|\+FC)} $f m int vic desc wea] } {
break
}
parse_weather $int $vic $desc $wea ar(weather)
}
} elseif { [regexp {[0-9]{4}} $f m ] } {
# International visibility field
parse_international_visibility $m ar(visibility)
} elseif { [regexp {^([0-9]{1,2})/?([0-9]{0,2})SM$} $f m v1 v2] } {
# American visibility field
parse_american_visibility $v1 $v2 $prevf ar(visibility)
}
# Visibility directions still to be added
set prevf $f
}
return [array get ar]
}
proc ::tclmetar::get_time { arnm } {
upvar $arnm ar
set y $ar(year)
while { [string length $y] < 4 } {
set y "0$y"
}
set M $ar(month)
while { [string length $M] < 2 } {
set M "0$M"
}
set d $ar(day)
while { [string length $d] < 2 } {
set d "0$d"
}
set h $ar(hour)
while { [string length $h] < 2 } {
set h "0$h"
}
set h "T$h"
set m $ar(minute)
while { [string length $m] < 2 } {
set m "0$m"
}
set s "00"
set mt [clock scan "$y$M$d$h$m$s" -gmt true]
return $mt
}
proc ::tclmetar::ftpopen { ftpserver ftpuser ftppassword ftpdir } {
variable ftpsock
set ftpsock [ftp::Open $ftpserver $ftpuser $ftppassword]
ftp::Cd $ftpsock $ftpdir
return
}
proc ::tclmetar::ftpget { mfile } {
variable ftpsock
set mdata ""
set rt [ftp::Get $ftpsock $mfile -variable mdata]
if { [string length $rt] && $rt } {
set mdata [string map {\n " " \r " " \t " "} [string trim $mdata]]
return [eval list [split $mdata]]
} else {
return -code error "Could not download file '$mfile'"
}
}
proc ::tclmetar::ftpclose { } {
variable ftpsock
ftp::Close $ftpsock
}
proc ::tclmetar::get_metar_data { mi_abbrev } {
set ftpserver tgftp.nws.noaa.gov
set ftpdir data/observations/metar/stations
set ftpuser anonymous
set ftppassword anonymous
set tVerbose $ftp::VERBOSE
set ::ftp::VERBOSE 0
::log::lvSuppress error
tclmetar::ftpopen $ftpserver $ftpuser $ftppassword $ftpdir
set rt [catch {tclmetar::ftpget $mi_abbrev.TXT} mi_data]
tclmetar::ftpclose
set ::ftp::VERBOSE $tVerbose
if { $rt } {
return -code error $mi_data
}
if { [catch {tclmetar::parse $mi_data $mi_abbrev} rl] } {
return -code error $rl
}
return $rl
}
======
**Initialisation**
After a
======
package require tclmetar
======
the package is ready for use.
**Available data**
+++
abbrev METAR station abbreviation
raw Unparsed METAR data as obtained from the NOAA server
year Year part of date on which METAR data was collected
month Month part of date on which METAR data was collected
day Day part of date on which METAR data was collected
hour Hour part of date on which METAR data was collected
minute Minute part of date on which METAR data was collected
corrected Indication if METAR data was correct before upload to NOAA server by METAR Station of not
winddir Wind direction, 0 = north, 90 = east, ...
winddirstr String representation of wind direction (N, NNE, NE, ENE, E, ESE, SE, SSE, S, SSW, SW, WSW, W, WNW, NW, NNW, N)
windspeed Wind speed, in km/h
windgust Wind gusts, in km/h
windvarfrom Variable wind direction ''from'' this direction, 0 = north, 90 = east, ...
windvarfromstr String representation of wind variability ''from''
windvarto Variable wind direction ''to'' this direction, 0 = north, 90 = east, ...
windvartostr String representation of wind variability ''to''
temperature Temperature, in degrees Celcius
dewpoint Temperatur, in degrees Celcius
airpressure Air-pressure, in bar
cloudstype Clouds-type, list of SKC (sky clear), FEW (few), SCT (scattered), BKN (broken), OVC (overcast), CAVOK (ceiling and visibility OK)
cloudsheight List of clouds-heights in meter or CAVOK
toweringcumulus Boolean indicating if this type of clouds is present near the METAR station
cumulonimbus Boolean indicating if this type of clouds is present near the METAR station
weather Weather in METAR abbreviations
visibility Horizontal visibility at ground level, in meter
+++
**::tclmetar::get_metar_data**
Command:
===
::tclmetar::get_metar_data ''metarStationCode''
===
This command will query the METAR data for the specified ''metarStationCode'' and return the parsed result as a list of key/value pairs suitable for use with [array set].
The following script will query METAR data for all METAR stations specified on the command line:
======
package require tclmetar
foreach m $argv {
if { [catch {::tclmetar::get_metar_data $m} wl] } {
puts "Could not get METAR info for '$m'"
} else {
puts "Weather for $m:"
array set a $wl
parray a
unset a
}
}
======
======
> tclsh test.tcl EBBR KJFK
Weather for EBBR:
a(abbrev) = EBBR
a(airpressure) = 1.008
a(cloudsheight) = 1158.24
a(cloudstype) = SCT
a(corrected) = <unknown>
a(cumulonimbus) = 0
a(day) = 22
a(dewpoint) = 10
a(hour) = 11
a(minute) = 20
a(month) = 6
a(raw) = 2007/06/22 11:20 EBBR 221120Z 20011KT 170V240 9999 SCT038 20/10 Q1008 TEMPO 5000 SHRA FEW020CB BKN030
a(temperature) = 20
a(toweringcumulus) = 0
a(visibility) = 9999
a(weather) = <unknown>
a(winddir) = 200
a(winddirstr) = SSW
a(windgust) = 0
a(windspeed) = 20
a(windvarfrom) = 170
a(windvarfromstr) = S
a(windvarto) = 240
a(windvartostr) = WSW
a(year) = 2007
Weather for KJFK:
a(abbrev) = KJFK
a(airpressure) = 1.01016312
a(cloudsheight) = 3657.6
a(cloudstype) = FEW
a(corrected) = <unknown>
a(cumulonimbus) = 0
a(day) = 22
a(dewpoint) = 11
a(hour) = 10
a(minute) = 51
a(month) = 6
a(raw) = 2007/06/22 10:51 KJFK 221051Z 30016KT 10SM FEW120 19/11 A2983 RMK AO2 SLP102 T01890111 {$}
a(temperature) = 19
a(toweringcumulus) = 0
a(visibility) = 16093.4
a(weather) = <unknown>
a(winddir) = 300
a(winddirstr) = WNW
a(windgust) = 0
a(windspeed) = 30
a(windvarfrom) = <unknown>
a(windvarfromstr) = <unknown>
a(windvarto) = <unknown>
a(windvartostr) = <unknown>
a(year) = 2007
======
----
weather data
----
[Category Science]} regexp2} CALL {my render {Metar data} {[jdc] 22-jun-2007
**Metar data package**
[METAR] data can be obtained from http://www.noaa.org/ using ftp. This package can query data from the NOAA server and parse METAR data (obtained with this package or otherwise).
----
[KPV] See also [TclWeather] and [A Very Simple Weather App] both of which download and parse METAR data.
----
package provide tclmetar 0.1
package require ftp
namespace eval ::tclmetar {
variable ftpsock
variable metar_keys {abbrev raw year month day hour minute corrected winddir winddirstr windspeed windgust windvarfrom windvarfromstr windvarto windvartostr temperature dewpoint airpressure cloudstype cloudsheight toweringcumulus cumulonimbus weather visibility}
}
proc ::tclmetar::get_winddirstr { winddir } {
if { [string is integer -strict $winddir] } {
set wsi [expr {int(($winddir+11.25)/22.5)}]
return [lindex {N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW N} $wsi]
}
return $winddir
}
proc ::tclmetar::parse_wind { f wd winddirnm winddirstrnm ws windspeednm wg windgustnm wu } {
upvar $winddirnm winddir
upvar $winddirstrnm winddirstr
upvar $windspeednm windspeed
upvar $windgustnm windgust
set winddir [string trimleft $wd "0"]
if { [string length $winddir] == 0 } {
set winddir 0
}
set windspeed [string trimleft $ws "0"]
if { [string length $windspeed] == 0 } {
set windspeed 0
}
set windgust [string trimleft [string range $wg 1 end] "0"]
if { [string length $windgust] == 0 } {
set windgust 0
}
switch -exact -- $wu {
"KT" {
set windspeed [expr {round($windspeed * 1.852)}]
set windgust [expr {round($windgust * 1.852)}]
}
"MPS" {
set windspeed [expr {round($windspeed * 3.6)}]
set windgust [expr {round($windgust * 3.6)}]
}
"KMH" {
}
}
set winddirstr [get_winddirstr $winddir]
return
}
proc ::tclmetar::parse_wind_variability { wvf windvarfromnm windvarfromstrnm wvt windvartonm windvartostrnm } {
upvar $windvarfromnm windvarfrom
upvar $windvartonm windvarto
upvar $windvarfromstrnm windvarfromstr
upvar $windvartostrnm windvartostr
set windvarfrom [string trimleft $wvf "0"]
if { [string length $windvarfrom] == 0 } {
set windvarfrom 0
}
set windvarfromstr [get_winddirstr $windvarfrom]
set windvarto [string trimleft $wvt "0"]
if { [string length $windvarto] == 0 } {
set windvarto 0
}
set windvartostr [get_winddirstr $windvarto]
return
}
proc ::tclmetar::parse_temperature { f tempnm } {
upvar $tempnm temp
if { [string match "M*" $f] } {
set temp -[string trimleft [string range $f 1 end] "0"]
if { [string equal $temp "-"] } {
set temp "0"
}
} else {
set temp [string trimleft $f "0"]
if { [string length $temp] == 0 } {
set temp "0"
}
}
}
proc ::tclmetar::parse_air_pressure { pv airpressurenm pu } {
upvar $airpressurenm airpressure
switch -exact -- $pu {
"A" {
set airpressure [string trimleft [string range $pv 0 1] "0"].[string range $pv 2 3]
set airpressure [expr {$airpressure * 0.033864}]
}
"Q" {
set airpressure [expr {[string trimleft $pv "0"] / 1000.0}]
}
}
return
}
proc ::tclmetar::parse_clouds { ct cloudstypenm ch cloudsheightnm cbtcu toweringcumulusnm cumulonimbusnm } {
upvar $cloudstypenm cloudstype
upvar $cloudsheightnm cloudsheight
upvar $toweringcumulusnm toweringcumulus
upvar $cumulonimbusnm cumulonimbus
switch -exact -- $ct {
SKC -
CLR -
NSC {
if { [string equal $cloudstype "<unknown>"] } {
set cloudstype SKC
} else {
lappend cloudstype SKC
}
}
FEW -
SCT -
BKN -
OVC {
if { [string equal $cloudstype "<unknown>"] } {
set cloudstype $ct
} else {
lappend cloudstype $ct
}
}
}
set ch [string trimleft $ch "0"]
if { [string length $ch] == 0 } {
set ch "0"
}
if { [string equal $cloudsheight "<unknown>"] } {
set cloudsheight [expr {$ch * 30.48}]
} else {
lappend cloudsheight [expr {$ch * 30.48}]
}
switch -exact -- $cbtcu {
CB {
set toweringcumulus 0
set cumulonimbus 1
}
TCU {
set toweringcumulus 1
set cumulonimbus 0
}
default {
set toweringcumulus 0
set cumulonimbus 0
}
}
return
}
proc ::tclmetar::parse_weather { int vic desc wea weathernm } {
upvar $weathernm weather
set wl [list $int $vic $desc $wea]
if { [string equal $weather "<unknown>"] } {
set weather [list $wl]
} else {
lappend weather $wl
}
return
}
proc ::tclmetar::parse_international_visibility { m visibilitynm } {
upvar $visibilitynm visibility
set visibility [string trimleft $m "0"]
if { [string length $visibility] == 0 } {
set visibility 0
}
return
}
proc ::tclmetar::parse_american_visibility { v1 v2 prevf visibilitynm } {
upvar $visibilitynm visibility
if { ([string length $v2] == 0) || [string equal $v2 "0"] } {
set v2 1
}
append v2 ".0"
if { ![string is integer -strict $prevf] } {
set prevf 0
}
set visibility [expr {($prevf + $v1/$v2) * 1609.34}]
return
}
proc ::tclmetar::parse { metarl mi_abbrev } {
set ar(abbrev) $mi_abbrev
set ar(raw) $metarl
set ar(year) "<unknown>"
set ar(month) "<unknown>"
set ar(day) "<unknown>"
set ar(hour) "<unknown>"
set ar(minute) "<unknown>"
set ar(corrected) "<unknown>" ;# bool
set ar(winddir) "<unknown>" ;# 0 = north, 90 = east
set ar(winddirstr) "<unknown>"
set ar(windspeed) "<unknown>" ;# in km/h
set ar(windgust) "<unknown>" ;# in km/h
set ar(windvarfrom) "<unknown>" ;# 0 = north, 90 = east
set ar(windvarfromstr) "<unknown>" ;# 0 = north, 90 = east
set ar(windvarto) "<unknown>" ;# 0 = north, 90 = east
set ar(windvartostr) "<unknown>" ;# 0 = north, 90 = east
set ar(temperature) "<unknown>" ;# in degrees Celcius
set ar(dewpoint) "<unknown>" ;# in degrees Celcius
set ar(airpressure) "<unknown>" ;# in bar
set ar(cloudstype) "<unknown>" ;# list of SKC (sky clear) | FEW | SCT (scattered) | BKN (broken) | OVC (overcast) | CAVOK
set ar(cloudsheight) "<unknown>" ;# list of heights in meter | CAVOK
set ar(toweringcumulus) "<unknown>" ;# bool
set ar(cumulonimbus) "<unknown>" ;# bool
set ar(weather) "<unknown>" ;# in metar abbreviations
set ar(visibility) "<unknown>" ;# in meter
set prevf ""
set mi_abbrev_found 0
foreach f $metarl {
ach f $metarl {
if { [string equal $mi_abbrev $f] } {
set mi_abbrev_found 1
continue
}
}
if { !$mi_abbrev_found && [regexp {([0-9]{4})/([0-9]{2})/([0-9]{2})} $f m y m d] } {
set ar(year) [string trimleft $y "0"]
set ar(month) [string trimleft $m "0"]
set ar(day) [string trimleft $d "0"]
} elseif { !$mi_abbrev_found && [regexp {([0-9]{2}):([0-9]{2})} $f ma h m] } {
set ar(hour) [string trimleft $h "0"]
if { [string length $ar(hour)] == 0 } {
set ar(hour) 0
}
set ar(minute) [string trimleft $m "0"]
if { [string length $ar(minute)] == 0 } {
set ar(minute) 0
}
} elseif { !$mi_abbrev_found } {
continue
} elseif { [string match "RMK*" $f] || [string match "TEMP*" $f] || [string match "NOSIG*" $f] } {
break
} elseif { [regexp {([0-9][0-9])([0-9][0-9])([0-9][0-9])Z} $f ma d h m] } {
# Date/time field
set ar(day) [string trimleft $d "0"]
set ar(hour) [string trimleft $h "0"]
if { [string length $ar(hour)] == 0 } {
set ar(hour) 0
}
set ar(minute) [string trimleft $m "0"]
if { [string length $ar(minute)] == 0 } {
set ar(minute) 0
}
} elseif { [string equal "COR" $f] } {
set ar(corrected) 1
} elseif { [string equal "AUT" $f] } {
set ar(corrected) 0
} elseif { [string match {R[0-9][0-9][LCR]*} $f] } {
# Runway visibility still to be added
} elseif { [regexp {([0-9]{3}|VRB)([0-9]{2,3})(G[0-9]{2,3})?(KT|KMH|MPS)} $f m wd ws wg wu] } {
# Wind field
parse_wind $f $wd ar(winddir) ar(winddirstr) $ws ar(windspeed) $wg ar(windgust) $wu
} elseif { [regexp {([0-9]{3})V([0-9]{3})} $f m wvf wvt] } {
# Wind variability
parse_wind_variability $wvf ar(windvarfrom) ar(windvarfromstr) $wvt ar(windvarto) ar(windvartostr)
} elseif { [regexp {^(M?[0-9][0-9])/+(M?[0-9][0-9])$} $f m temp dewp] } {
# Temperature field
parse_temperature $temp ar(temperature)
parse_temperature $dewp ar(dewpoint)
} elseif { [regexp {(A|Q)([0-9]{4})} $f m pu pv] } {
# Altimeter settings field
parse_air_pressure $pv ar(airpressure) $pu
} elseif { [regexp {(SKC|FEW|SCT|BKN|OVC|CLR|NSC)([0-9]{3})?(CB|TCU)?} $f m ct ch cbtcu] } {
# Clouds field
parse_clouds $ct ar(cloudstype) $ch ar(cloudsheight) $cbtcu ar(toweringcumulus) ar(cumulonimbus)
} elseif { [string equal $f "CAVOK"] } {
set ar(cloudstype) "CAVOK"
set ar(cloudsheight) "CAVOK"
set ar(cumulonimbus) 0
set ar(toweringcumulus) 0
set ar(visibility) 9999
} elseif { [regexp {([\+\-]?)(VC)?(MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PI|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DU|PO|FC|\+FC)} $f m int vic desc wea] } {
# Weather field
parse_weather $int $vic $desc $wea ar(weather)
while { 1 } {
set f [string range $f [string length $m] end]
if { ![regexp {([\+\-]?)(VC)?(MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PI|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DU|PO|FC|\+FC)} $f m int vic desc wea] } {
break
}
parse_weather $int $vic $desc $wea ar(weather)
}
} elseif { [regexp {[0-9]{4}} $f m ] } {
# International visibility field
parse_international_visibility $m ar(visibility)
} elseif { [regexp {^([0-9]{1,2})/?([0-9]{0,2})SM$} $f m v1 v2] } {
# American visibility field
parse_american_visibility $v1 $v2 $prevf ar(visibility)
}
# Visibility directions still to be added
set prevf $f
}
return [array get ar]
}
proc ::tclmetar::get_time { arnm } {
upvar $arnm ar
set y $ar(year)
while { [string length $y] < 4 } {
set y "0$y"
}
set M $ar(month)
while { [string length $M] < 2 } {
set M "0$M"
}
set d $ar(day)
while { [string length $d] < 2 } {
set d "0$d"
}
set h $ar(hour)
while { [string length $h] < 2 } {
set h "0$h"
}
set h "T$h"
set m $ar(minute)
while { [string length $m] < 2 } {
set m "0$m"
}
set s "00"
set mt [clock scan "$y$M$d$h$m$s" -gmt true]
return $mt
}
proc ::tclmetar::ftpopen { ftpserver ftpuser ftppassword ftpdir } {
variable ftpsock
set ftpsock [ftp::Open $ftpserver $ftpuser $ftppassword]
ftp::Cd $ftpsock $ftpdir
return
}
proc ::tclmetar::ftpget { mfile } {
variable ftpsock
set mdata ""
set rt [ftp::Get $ftpsock $mfile -variable mdata]
if { [string length $rt] && $rt } {
set mdata [string map {\n " " \r " " \t " "} [string trim $mdata]]
return [eval list [split $mdata]]
} else {
return -code error "Could not download file '$mfile'"
}
}
proc ::tclmetar::ftpclose { } {
variable ftpsock
ftp::Close $ftpsock
}
proc ::tclmetar::get_metar_data { mi_abbrev } {
set ftpserver tgftp.nws.noaa.gov
set ftpdir data/observations/metar/stations
set ftpuser anonymous
set ftppassword anonymous
set tVerbose $ftp::VERBOSE
set ::ftp::VERBOSE 0
::log::lvSuppress error
tclmetar::ftpopen $ftpserver $ftpuser $ftppassword $ftpdir
set rt [catch {tclmetar::ftpget $mi_abbrev.TXT} mi_data]
tclmetar::ftpclose
set ::ftp::VERBOSE $tVerbose
if { $rt } {
return -code error $mi_data
}
if { [catch {tclmetar::parse $mi_data $mi_abbrev} rl] } {
return -code error $rl
}
return $rl
}
======
**Initialisation**
After a
======
package require tclmetar
======
the package is ready for use.
**Available data**
+++
abbrev METAR station abbreviation
raw Unparsed METAR data as obtained from the NOAA server
year Year part of date on which METAR data was collected
month Month part of date on which METAR data was collected
day Day part of date on which METAR data was collected
hour Hour part of date on which METAR data was collected
minute Minute part of date on which METAR data was collected
corrected Indication if METAR data was correct before upload to NOAA server by METAR Station of not
winddir Wind direction, 0 = north, 90 = east, ...
winddirstr String representation of wind direction (N, NNE, NE, ENE, E, ESE, SE, SSE, S, SSW, SW, WSW, W, WNW, NW, NNW, N)
windspeed Wind speed, in km/h
windgust Wind gusts, in km/h
windvarfrom Variable wind direction ''from'' this direction, 0 = north, 90 = east, ...
windvarfromstr String representation of wind variability ''from''
windvarto Variable wind direction ''to'' this direction, 0 = north, 90 = east, ...
windvartostr String representation of wind variability ''to''
temperature Temperature, in degrees Celcius
dewpoint Temperatur, in degrees Celcius
airpressure Air-pressure, in bar
cloudstype Clouds-type, list of SKC (sky clear), FEW (few), SCT (scattered), BKN (broken), OVC (overcast), CAVOK (ceiling and visibility OK)
cloudsheight List of clouds-heights in meter or CAVOK
toweringcumulus Boolean indicating if this type of clouds is present near the METAR station
cumulonimbus Boolean indicating if this type of clouds is present near the METAR station
weather Weather in METAR abbreviations
visibility Horizontal visibility at ground level, in meter
+++
**::tclmetar::get_metar_data**
Command:
===
::tclmetar::get_metar_data ''metarStationCode''
===
This command will query the METAR data for the specified ''metarStationCode'' and return the parsed result as a list of key/value pairs suitable for use with [array set].
The following script will query METAR data for all METAR stations specified on the command line:
======
package require tclmetar
foreach m $argv {
if { [catch {::tclmetar::get_metar_data $m} wl] } {
puts "Could not get METAR info for '$m'"
} else {
puts "Weather for $m:"
array set a $wl
parray a
unset a
}
}
======
======
> tclsh test.tcl EBBR KJFK
Weather for EBBR:
a(abbrev) = EBBR
a(airpressure) = 1.008
a(cloudsheight) = 1158.24
a(cloudstype) = SCT
a(corrected) = <unknown>
a(cumulonimbus) = 0
a(day) = 22
a(dewpoint) = 10
a(hour) = 11
a(minute) = 20
a(month) = 6
a(raw) = 2007/06/22 11:20 EBBR 221120Z 20011KT 170V240 9999 SCT038 20/10 Q1008 TEMPO 5000 SHRA FEW020CB BKN030
a(temperature) = 20
a(toweringcumulus) = 0
a(visibility) = 9999
a(weather) = <unknown>
a(winddir) = 200
a(winddirstr) = SSW
a(windgust) = 0
a(windspeed) = 20
a(windvarfrom) = 170
a(windvarfromstr) = S
a(windvarto) = 240
a(windvartostr) = WSW
a(year) = 2007
Weather for KJFK:
a(abbrev) = KJFK
a(airpressure) = 1.01016312
a(cloudsheight) = 3657.6
a(cloudstype) = FEW
a(corrected) = <unknown>
a(cumulonimbus) = 0
a(day) = 22
a(dewpoint) = 11
a(hour) = 10
a(minute) = 51
a(month) = 6
a(raw) = 2007/06/22 10:51 KJFK 221051Z 30016KT 10SM FEW120 19/11 A2983 RMK AO2 SLP102 T01890111 {$}
a(temperature) = 19
a(toweringcumulus) = 0
a(visibility) = 16093.4
a(weather) = <unknown>
a(winddir) = 300
a(winddirstr) = WNW
a(windgust) = 0
a(windspeed) = 30
a(windvarfrom) = <unknown>
a(windvarfromstr) = <unknown>
a(windvarto) = <unknown>
a(windvartostr) = <unknown>
a(year) = 2007
======
----
weather data
----
[Category Science]}} CALL {my revision {Metar data}} CALL {::oo::Obj1321618 process revision/Metar+data} CALL {::oo::Obj1321616 process}
-errorcode
NONE
-errorinfo
Unknow state transition: LINE -> END
while executing
"error $msg"
(class "::Wiki" method "render_wikit" line 6)
invoked from within
"my render_$default_markup $N $C $mkup_rendering_engine"
(class "::Wiki" method "render" line 8)
invoked from within
"my render $name $C"
(class "::Wiki" method "revision" line 31)
invoked from within
"my revision $page"
(class "::Wiki" method "process" line 56)
invoked from within
"$server process [string trim $uri /]"
-errorline
4