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.