Trying to write some code that does what wmWeather does for wm.
Example output for LSZH:
Explaining LSZH 110220Z 06008KT 030V100 5000 -SN FEW020 BKN026 M06/M11 Q1022 8829//99 NOSIG
Location: LSZH
Time: 02:20 UTC
Wind direction: 060°
Wind speed: 08 knots, 15 km/h
Wind variability: 030° to 100°
Not handled: 5000
Weather Group: light snow
Clouds: few at 2000 ft
Clouds: broken at 2600 ft
Temperature: -6 °C
Dew Point: -11 °C
Wind Chill: -12 °C
QNH: 1022 hPa
Not handled: 8829//99
Not handled: NOSIGAnd here is the code. Note that this uses the HttpGet function. Contributors: AlexSchroeder, UlfJasper, DougGerecht?
(defvar metar-report-location nil
"Location of the current buffer.")(make-variable-buffer-local 'metar-report-location)
(defun metar-report (location)
"Return a weather report based on the location indicator.
This LOCATION is a four letter code that is unique to a weather
station. Practically all airports have one. The code \"LSZH\", for
example, is for the airport in Zürich, Switzerland. In order to find a station near you, see
http://www.nws.noaa.gov/tg/siteloc.shtml. Note that you can use only
the stations that have a four letter code. For an explanation of the METAR report returned, see
http://www.ofcm.gov/fmh-1/fmh1.htm. For the wind chill calculation, see
http://www.nws.noaa.gov/om/windchill/index.shtml."
(interactive "sLocation: ")
(unless (string-match "^[A-Z]\\{4\\}$" location)
(error "Location must be a four uppercase letter code"))
;; Primitive HTML GET for the current situation
;; Example: http://weather.noaa.gov/cgi-bin/mgetmetar.pl?cccc=LSZH
(let ((proc (http-get (format "http://weather.noaa.gov/cgi-bin/mgetmetar.pl?cccc=%s"
location) nil
'metar-report-print
1.0)))
(set-buffer (process-buffer proc))
(setq metar-report-location location))) (defun metar-report-knots-to-kmh (knots)
"Convert KNOTS to km/h and return it as a string."
(unless (numberp knots)
(setq knots (string-to-number knots)))
(concat (number-to-string (round (* knots 1.852))) " km/h")) (defun metar-report-wind-chill (celsius knots)
"Return wind-chill based on TEMPERATURE in Celsius and WINDSPEED in knots."
;; Formula uses Wind Chill Temperature Index for Winter 2001-2002.
;; This is the official formula using miles and Farenheit.
(let* ((farenheit (+ 32 (* 1.8 celsius)))
(mph (* 1.1507794 knots))
;; Wind Chill(°F)=35.74+.6215T-35.75(V**0.16)+.4275T(V**0.16)
;; Where T is the Air Temperature in °F
;; and V is the Wind Speed in mph.
(chill (+ 35.74
(* .6215 farenheit)
(* -35.75 (expt mph 0.16))
(* .4275 farenheit (expt mph 0.16)))))
;; Return Celsius
(concat (number-to-string (round (/ (- chill 32) 1.8))) " °C"))) ;; Test Data: -10F, 40mph => -43F, dh. SOLL: -41.666667C
;; Parameter umformen: -23.333333C, 34.75905 knots => (metar-report-wind-chill -23.333333 34.75905)
;; Test Data: 35F, 55mph => 18F, dh. SOLL: -7.7777778C
;; Parameter umformen: 1.6666667C, 47.793693 knots => (metar-report-wind-chill 1.6666667 47.793693) (defun metar-report-print (proc str)
"Sentinel for `metar-report'."
(set-buffer (process-buffer proc))
(goto-char (point-min))
;; Search for result
;; Example: LSZH 102320Z 06006KT 030V100 4000 -SN FEW021 BKN025 M06/M10 Q1021 8829//99 NOSIG
(when (search-forward (concat "\n" metar-report-location " "))
(let* ((line (buffer-substring (line-beginning-position) (line-end-position)))
(items (split-string (buffer-substring (line-beginning-position) (line-end-position))))
(in-remark nil)
knots)
(when items
(erase-buffer)
(insert "Explaining " line "\n\n")
(dolist (item items)
(if in-remark
(insert item " ")
(cond ((string-match "^[A-Z]\\{4\\}$" item)
(insert "Location: " item))
((string-match "^\\([0-9]\\{6\\}\\)Z$" item)
(let ((hour (substring item 2 4))
(minute (substring item 4 6)))
(insert "Time: " hour ":" minute " UTC")))
;; Examples: 08KT, 112KT, 27020G35KT, VRB03KT, 00000KT
((string-match "^\\([0-9][0-9][0-9]\\|VRB\\)\\(\\([1-9][0-9]+\\|0[1-9]\\)G\\)?\\([1-9][0-9]+\\|0[1-9]\\)KT$" item)
(let* ((direction (match-string 1 item))
(gust (match-string 3 item))
(speed (match-string 4 item)))
(setq knots (string-to-number speed))
(insert "Wind direction: "
(cond ((string= direction "VRB") "variable")
((string= direction "000") "calm")
(t (concat direction "°")))
"\n"
"Wind speed: "
speed " knots, "
(metar-report-knots-to-kmh speed))
(when gust
(insert ", gusts at " gust " knots, "
(metar-report-knots-to-kmh gust)))))
;; Example: 180V240
((string-match "^\\([0-9][0-9][0-9]\\)V\\([0-9][0-9][0-9]\\)$" item)
(let ((from (match-string 1 item))
(to (match-string 2 item)))
(insert "Wind variability: "
(concat from "°") " to " (concat to "°"))))
;; Example: -SHRA
((string-match "^[-+]?\\([A-Z][A-Z]\\)+$" item)
(insert "Weather Group: ")
(cond ((= (aref item 0) ?-)
(insert " light")
(setq item (substring item 1)))
((= (aref item 0) ?+)
(insert " heavy")
(setq item (substring item 1)))
(t
(insert " moderate")))
(let (key
text
(table '(("VC" . "in the vicinity")
("MI" . "shallow")
("PR" . "partial")
("BC" . "patches")
("DR" . "low drifting")
("BL" . "blowing")
("SH" . "showers")
("TS" . "thunderstorms")
("FZ" . "freezing")
("DZ" . "drizzle")
("RA" . "rain")
("SN" . "snow")
("SG" . "snow grains")
("IC" . "ice crystals")
("PL" . "ice pellets")
("GR" . "hail")
("GS" . "small hail and/or snow pellets")
("UP" . "unknown precipitation")
("BR" . "mist")
("FG" . "fog")
("FU" . "smoke")
("VA" . "volcanic ash")
("DU" . "widespread dust")
("SA" . "sand")
("HZ" . "haze")
("PY" . "spray")
("PO" . "well developed dust/sand whirls")
("SQ" . "sqalls")
("FC" . "funnel cloud, tornado, or waterspout")
("SS" . "sandstorm")
("DS" . "duststorm"))))
(while (not (string= item ""))
(setq key (substring item 0 2)
text (cdr (assoc (substring item 0 2) table))
item (substring item 2))
(if text
(insert " " text)
(insert " (unknown key: " key ")")))))
;; Examples: 04/M02, 02/
((string-match "^\\(M\\)?\\([0-9][0-9]\\)/\\(M\\)?\\([0-9][0-9]\\)?$" item)
(let ((temp (match-string 2 item))
(dew (match-string 4 item)))
(when temp
(setq temp (string-to-number temp))
(when (match-string 1 item)
(setq temp (* -1 temp)))
(insert "Temperature: " (number-to-string temp) " °C"))
(when dew
(setq dew (string-to-number dew))
(when (match-string 3 item)
(setq dew (* -1 dew)))
(insert "\nDew Point: " (number-to-string dew) " °C"))
(when (and temp knots)
(insert "\nWind Chill: " (metar-report-wind-chill temp knots)))))
;; Example 75SM
((string-match "^\\([0-9]+\\)SM$" item)
(insert "Visibility: " (match-string 1 item) " statute miles"))
;; Example A3015
((string-match "^A\\([0-9][0-9]\\)\\([0-9][0-9]\\)$" item)
(insert "Altimeter: " (match-string 1 item) "."
(match-string 2 item)))
;; Example FEW080 BKN050
((string-match "^\\(FEW\\|SCT\\|BKN\\|OVC\\)\\([0-9][0-9][0-9]\\)$" item)
(let* ((table '(("FEW" . "few")
("SCT" . "scattered")
("BKN" . "broken")
("OVC" . "overcast")))
(amount (cdr (assoc (match-string 1 item) table))))
(insert (format "Clouds: %s at %d ft" amount
(* 100 (string-to-number
(match-string 2 item)))))))
;; Example Q2000
((string-match "^Q\\([0-9][0-9][0-9][0-9]\\)$" item)
(insert (format "QNH: %d hPa"
(string-to-number (match-string 1 item)))))
;; Example RMK AO2 SLP197 ACSL DSNT NW T01281044 $
((string-match "^RMK$" item)
(insert "Remark: ")
(setq in-remark t))
;; The Rest
(t (insert "Not handled: " item)))
(if (not in-remark) (newline)))))
(switch-to-buffer (current-buffer)))))For Terminal Aerodrome Forecast (TAF) forecast, you can reuse the sentinel. All you need to do is use another URL.
Example:
(defun taf-report (location)
"Return a weather forecast based on the location indicator.
This LOCATION is a four letter code that is unique to a weather
station. Practically all airports have one. The code \"LSZH\", for
example, is for the airport in Zürich, Switzerland. In order to find a station near you, see
http://www.nws.noaa.gov/tg/siteloc.shtml. Note that you can use only
the stations that have a four letter code. For an explanation of the Terminal Aerodrome Forecast (TAF) report
returned, see http://www.ofcm.gov/fmh-1/fmh1.htm. For the wind chill calculation, see
http://www.nws.noaa.gov/om/windchill/index.shtml."
(interactive "sLocation: ")
(unless (string-match "^[A-Z]\\{4\\}$" location)
(error "Location must be a four uppercase letter code"))
;; Primitive HTML GET for the Terminal Aerodrome Forecast (TAF) forecast
;; Example: http://weather.noaa.gov/cgi-bin/mgettaf.pl?cccc=LSZH
(let ((proc (http-get (format "http://weather.noaa.gov/cgi-bin/mgettaf.pl?cccc=%s"
location)
nil
'metar-report-print
1.0)))
(set-buffer (process-buffer proc))
(setq metar-report-location location)))See also RainOrShine.