Air Quality Index in Melbourne is 50 the dominant pollutant is pm25
This commit is contained in:
parent
dff57a346b
commit
265ab11044
1 changed files with 69 additions and 69 deletions
138
aqi.el
138
aqi.el
|
@ -1,4 +1,4 @@
|
||||||
;;; aqi.el --- Air quality data from the World Air Quality Index. -*- lexical-binding: t; -*-
|
;;; aqi.el --- Air quality data from the World Air Quality Index -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
;; Copyright 2020 FoAM
|
;; Copyright 2020 FoAM
|
||||||
;;
|
;;
|
||||||
|
@ -72,14 +72,14 @@
|
||||||
"Clear the cached data, optionally only for a given CITY."
|
"Clear the cached data, optionally only for a given CITY."
|
||||||
(if city
|
(if city
|
||||||
(setq aqi-cached-data
|
(setq aqi-cached-data
|
||||||
(assq-delete-all city aqi-cached-data))
|
(assq-delete-all city aqi-cached-data))
|
||||||
(setq aqi-cached-data '(("None" . "None")))))
|
(setq aqi-cached-data '(("None" . "None")))))
|
||||||
|
|
||||||
(defun aqi--city-cache-update (city)
|
(defun aqi--city-cache-update (city)
|
||||||
"Add or update cached data for a given CITY."
|
"Add or update cached data for a given CITY."
|
||||||
(progn (aqi--city-cache-clear city)
|
(aqi--city-cache-clear city)
|
||||||
(push (cons city (aqi-request city))
|
(push (cons city (aqi-request city))
|
||||||
aqi-cached-data)))
|
aqi-cached-data))
|
||||||
|
|
||||||
(defun aqi--city-cache-get (city)
|
(defun aqi--city-cache-get (city)
|
||||||
"Add or update cached data for a given CITY."
|
"Add or update cached data for a given CITY."
|
||||||
|
@ -97,16 +97,16 @@
|
||||||
(defmacro aqi--make-city-raw-accessor (name aref)
|
(defmacro aqi--make-city-raw-accessor (name aref)
|
||||||
"Macro to create an accesor NAME with a 'let-alist' AREF (or function)."
|
"Macro to create an accesor NAME with a 'let-alist' AREF (or function)."
|
||||||
`(fset ,name
|
`(fset ,name
|
||||||
(lambda (city)
|
(lambda (city)
|
||||||
(aqi-request city)
|
(aqi-request city)
|
||||||
(let-alist (assoc-default city aqi-cached-data) ,aref))))
|
(let-alist (assoc-default city aqi-cached-data) ,aref))))
|
||||||
|
|
||||||
(defmacro aqi--make-city-format-accessor (name aref)
|
(defmacro aqi--make-city-format-accessor (name aref)
|
||||||
"Macro to create an accesor NAME with a 'let-alist' AREF (or function)."
|
"Macro to create an accesor NAME with a 'let-alist' AREF (or function)."
|
||||||
`(fset ,name
|
`(fset ,name
|
||||||
(lambda (city)
|
(lambda (city)
|
||||||
(aqi-request city)
|
(aqi-request city)
|
||||||
(format "%s" (let-alist (assoc-default city aqi-cached-data) ,aref)))))
|
(format "%s" (let-alist (assoc-default city aqi-cached-data) ,aref)))))
|
||||||
|
|
||||||
;; various accessors (added as needed...)
|
;; various accessors (added as needed...)
|
||||||
|
|
||||||
|
@ -115,7 +115,7 @@
|
||||||
|
|
||||||
;; Function to return the coordinates of a city (by name) as a string
|
;; Function to return the coordinates of a city (by name) as a string
|
||||||
(aqi--make-city-format-accessor 'aqi-city-lonlat
|
(aqi--make-city-format-accessor 'aqi-city-lonlat
|
||||||
(format "%s, %s" (elt .city.geo 0) (elt .city.geo 1)))
|
(format "%s, %s" (elt .city.geo 0) (elt .city.geo 1)))
|
||||||
|
|
||||||
|
|
||||||
;; API requests for AQI info
|
;; API requests for AQI info
|
||||||
|
@ -128,15 +128,15 @@
|
||||||
:params `(("token" . ,aqi-api-key))
|
:params `(("token" . ,aqi-api-key))
|
||||||
:parser 'json-read
|
:parser 'json-read
|
||||||
:success (cl-function
|
:success (cl-function
|
||||||
(lambda (&key data &allow-other-keys)
|
(lambda (&key data &allow-other-keys)
|
||||||
(pcase (assoc-default 'status data)
|
(pcase (assoc-default 'status data)
|
||||||
("ok" (push (cons city (assoc-default 'data data))
|
("ok" (push (cons city (assoc-default 'data data))
|
||||||
aqi-cached-data))
|
aqi-cached-data))
|
||||||
("error" (push (cons city (format "Request error: %s" (assoc-default 'data data)))
|
("error" (push (cons city (format "Request error: %s" (assoc-default 'data data)))
|
||||||
aqi-cached-data)))))
|
aqi-cached-data)))))
|
||||||
:error (cl-function
|
:error (cl-function
|
||||||
(lambda (&rest args &key error-thrown &allow-other-keys)
|
(lambda (&rest args &key error-thrown &allow-other-keys)
|
||||||
(message "WAQI error: %s" error-thrown)))))
|
(message "WAQI error: %s" error-thrown)))))
|
||||||
|
|
||||||
(defun aqi-request-geo (latitude longitude)
|
(defun aqi-request-geo (latitude longitude)
|
||||||
"Request details by LATITUDE and LONGITUDE from WAQI."
|
"Request details by LATITUDE and LONGITUDE from WAQI."
|
||||||
|
@ -146,11 +146,11 @@
|
||||||
:params `(("token" . ,aqi-api-key))
|
:params `(("token" . ,aqi-api-key))
|
||||||
:parser 'json-read
|
:parser 'json-read
|
||||||
:success (cl-function
|
:success (cl-function
|
||||||
(lambda (&key data &allow-other-keys)
|
(lambda (&key data &allow-other-keys)
|
||||||
(message "200: %s" data)))
|
(message "200: %s" data)))
|
||||||
:error (cl-function
|
:error (cl-function
|
||||||
(lambda (&rest args &key error-thrown &allow-other-keys)
|
(lambda (&rest args &key error-thrown &allow-other-keys)
|
||||||
(message "WAQI error: %s" error-thrown)))))
|
(message "WAQI error: %s" error-thrown)))))
|
||||||
|
|
||||||
(defun aqi-request-cached (city)
|
(defun aqi-request-cached (city)
|
||||||
"Request details for CITY from cached data or direct from WAQI."
|
"Request details for CITY from cached data or direct from WAQI."
|
||||||
|
@ -160,19 +160,19 @@
|
||||||
|
|
||||||
(defun aqi-search (name)
|
(defun aqi-search (name)
|
||||||
"Search for the nearest stations (if any) matching a given NAME."
|
"Search for the nearest stations (if any) matching a given NAME."
|
||||||
(request
|
(request
|
||||||
(format "https://api.waqi.info/search/?keyword=%s&" name)
|
(format "https://api.waqi.info/search/?keyword=%s&" name)
|
||||||
:sync t
|
:sync t
|
||||||
:params `(("token" . ,aqi-api-key))
|
:params `(("token" . ,aqi-api-key))
|
||||||
:parser 'json-read
|
:parser 'json-read
|
||||||
:success (cl-function
|
:success (cl-function
|
||||||
(lambda (&key data &allow-other-keys)
|
(lambda (&key data &allow-other-keys)
|
||||||
(pcase (assoc-default 'status data)
|
(pcase (assoc-default 'status data)
|
||||||
("ok" (message "Search: %s" (assoc-default 'data data)))
|
("ok" (message "Search: %s" (assoc-default 'data data)))
|
||||||
("error" (message "Search error: %s" (assoc-default 'data data))))))
|
("error" (message "Search error: %s" (assoc-default 'data data))))))
|
||||||
:error (cl-function
|
:error (cl-function
|
||||||
(lambda (&rest args &key error-thrown &allow-other-keys)
|
(lambda (&rest args &key error-thrown &allow-other-keys)
|
||||||
(message "WAQI error: %s" error-thrown)))))
|
(message "WAQI error: %s" error-thrown)))))
|
||||||
|
|
||||||
;; printing, formatting and presenting.
|
;; printing, formatting and presenting.
|
||||||
|
|
||||||
|
@ -180,28 +180,28 @@
|
||||||
(defun aqi-report-brief (&optional place)
|
(defun aqi-report-brief (&optional place)
|
||||||
"General air quality info from PLACE as a string."
|
"General air quality info from PLACE as a string."
|
||||||
(let ((city (if (and (string< "" place) place) place "here")))
|
(let ((city (if (and (string< "" place) place) place "here")))
|
||||||
(if aqi-use-cache
|
(if aqi-use-cache
|
||||||
(aqi-request-cached city)
|
(aqi-request-cached city)
|
||||||
(aqi-request city))
|
(aqi-request city))
|
||||||
(let-alist (aqi--city-cache-get city)
|
(let-alist (aqi--city-cache-get city)
|
||||||
(format "Air Quality Index in %s is %s and the dominant pollutant is %s%s"
|
(format "Air Quality Index in %s is %s and the dominant pollutant is %s%s"
|
||||||
.city.name .aqi .dominentpol
|
.city.name .aqi .dominentpol
|
||||||
(if aqi-use-cache " (cached)" "")))))
|
(if aqi-use-cache " (cached)" "")))))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun aqi-report-full (&optional place)
|
(defun aqi-report-full (&optional place)
|
||||||
"Detailed air quality info from PLACE as a string."
|
"Detailed air quality info from PLACE as a string."
|
||||||
(let ((city (if (and (string< "" place) place) place "here")))
|
(let ((city (if (and (string< "" place) place) place "here")))
|
||||||
(if aqi-use-cache
|
(if aqi-use-cache
|
||||||
(aqi-request-cached city)
|
(aqi-request-cached city)
|
||||||
(aqi-request city))
|
(aqi-request city))
|
||||||
(let ((data (aqi--city-cache-get city)))
|
(let ((data (aqi--city-cache-get city)))
|
||||||
;; simple typecheck -> error handling since semantic errors are cached as strings.
|
;; simple typecheck -> error handling since semantic errors are cached as strings.
|
||||||
(if (stringp data)
|
(if (stringp data)
|
||||||
(format "%s (%s)" data city)
|
(format "%s (%s)" data city)
|
||||||
(let-alist data
|
(let-alist data
|
||||||
(format
|
(format
|
||||||
"Air Quality index in %s is %s as of %s (UTC%s).
|
"Air Quality index in %s is %s as of %s (UTC%s).
|
||||||
\nDominant pollutant is %s
|
\nDominant pollutant is %s
|
||||||
PM2.5 (fine particulate matter): %s
|
PM2.5 (fine particulate matter): %s
|
||||||
PM10 (respirable particulate matter): %s
|
PM10 (respirable particulate matter): %s
|
||||||
|
@ -213,38 +213,38 @@ Air pressure: %s
|
||||||
Wind: %s
|
Wind: %s
|
||||||
\nFurther details can be found at %s
|
\nFurther details can be found at %s
|
||||||
\nData provided by %s and %s%s"
|
\nData provided by %s and %s%s"
|
||||||
.city.name
|
.city.name
|
||||||
.aqi
|
.aqi
|
||||||
.time.s
|
.time.s
|
||||||
.time.tz
|
.time.tz
|
||||||
.dominentpol
|
.dominentpol
|
||||||
.iaqi.pm25.v
|
.iaqi.pm25.v
|
||||||
.iaqi.pm10.v
|
.iaqi.pm10.v
|
||||||
.iaqi.no2.v
|
.iaqi.no2.v
|
||||||
.iaqi.co.v
|
.iaqi.co.v
|
||||||
.iaqi.t.v
|
.iaqi.t.v
|
||||||
.iaqi.h.v
|
.iaqi.h.v
|
||||||
.iaqi.p.v
|
.iaqi.p.v
|
||||||
.iaqi.wg.v
|
.iaqi.wg.v
|
||||||
.city.url
|
.city.url
|
||||||
(let-alist (elt .attributions 0) .name)
|
(let-alist (elt .attributions 0) .name)
|
||||||
(let-alist (elt .attributions 1) .name)
|
(let-alist (elt .attributions 1) .name)
|
||||||
(if aqi-use-cache " (cached)" "")))))))
|
(if aqi-use-cache " (cached)" "")))))))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun aqi-report (&optional place type)
|
(defun aqi-report (&optional place type)
|
||||||
"General air quality info from PLACE (or 'here' if no args are given) report TYPE can be 'brief' or 'full'."
|
"General air quality info from PLACE (or 'here' if no args are given) report TYPE can be 'brief' or 'full'."
|
||||||
(interactive "sName of city or monitoring station (RET for \"here\"): ")
|
(interactive "sName of city or monitoring station (RET for \"here\"): ")
|
||||||
(let* ((city (if (and (string< "" place) place) place "here"))
|
(let* ((city (if (and (string< "" place) place) place "here"))
|
||||||
(aqi-output (get-buffer-create (format "*Air Quality - %s*" city))))
|
(aqi-output (get-buffer-create (format "*Air Quality - %s*" city))))
|
||||||
(with-current-buffer aqi-output
|
(with-current-buffer aqi-output
|
||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
(erase-buffer)
|
(erase-buffer)
|
||||||
(pcase type
|
(pcase type
|
||||||
('brief (insert (aqi-report-brief city)))
|
('brief (insert (aqi-report-brief city)))
|
||||||
('full (insert (aqi-report-full city)))
|
('full (insert (aqi-report-full city)))
|
||||||
('nil (insert (aqi-report-full city)))
|
('nil (insert (aqi-report-full city)))
|
||||||
(other (warn "Unknown report type: '%s. Try using 'full or 'brief" other)))
|
(other (warn "Unknown report type: '%s. Try using 'full or 'brief" other)))
|
||||||
(goto-char (point-max))
|
(goto-char (point-max))
|
||||||
(insert ""))
|
(insert ""))
|
||||||
(display-buffer aqi-output))
|
(display-buffer aqi-output))
|
||||||
|
|
Loading…
Reference in a new issue