From: Eshel Yaron <me@eshelyaron.com>
To: John Haman <mail@johnhaman.org>
Cc: help-gnu-emacs@gnu.org
Subject: Re: Package critique: modeline for air quality information
Date: Fri, 01 Sep 2023 11:38:27 +0200 [thread overview]
Message-ID: <m1ttsexmgc.fsf@eshelyaron.com> (raw)
In-Reply-To: <m1jztaejth.fsf@johnhaman.org> (John Haman's message of "Thu, 31 Aug 2023 21:58:02 -0400")
Hello John,
John Haman <mail@johnhaman.org> writes:
> I wrote a package that adds local air quality statistics to the
> mode-line.
Cool!
>
> https://github.com/jthaman/air-quality/blob/main/air-quality.el
>
> If you are so inclined, I'd like some thoughts on the code. It's
> short, but I'm trying to get better at Emacs Lisp (at least this week,
> while I'm on vacation...)
>
My suggestion would be to set this up as a global minor mode. Also, you
may want to define your "public variables" as user options, so they can
be customized with `M-x customize` and friends. Something along the
lines of:
diff --git a/air-quality.el b/air-quality.el
index 1781515..533ce1b 100644
--- a/air-quality.el
+++ b/air-quality.el
@@ -6,7 +6,7 @@ ;;; air-quality.el --- Air quality modeline indicator and reporting tool -*- le
;; URL: https://github.com/jthaman/air-quality
;; Version: 0.1
;; Package-Requires: ((emacs "27.1"))
-;; Keywords: bling
+;; Keywords: convenience
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
@@ -21,35 +21,44 @@ ;;; air-quality.el --- Air quality modeline indicator and reporting tool -*- le
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
-;;; Package Imports
-(require 'url)
-(require 'json)
-(require 'cl-lib)
-
-
;;; Commentary:
+
;; Add information about local air quality to the modeline. Air Quality
;; information is downloaded from the Open Weather Map Air Pollution API.
-
;;; Code:
+;;;; Package Imports
+
+(require 'url)
+(require 'json)
+(require 'cl-lib)
+
+;;;; User options
-;;; Public Variables
-(defvar air-quality-open-weather-api-key nil
- "A string. API key for Open Weather Map.")
+(defgroup air-quality nil
+ "Air quality mode-line indicator."
+ :group 'mode-line)
+
+(defcustom air-quality-open-weather-api-key nil
+ "API key for Open Weather Map."
+ :type '(choice (const :tag "Unset" nil)
+ (string :tag "Your API key")))
(defvar air-quality-refresh-interval 60
+ ;; XXX - turn into a defcustom
"An integer. Number of minutes between refreshes of air quality information.")
(defvar air-quality-latitude nil
+ ;; XXX - likewise
"A float. Your latitude.")
(defvar air-quality-longitude nil
+ ;; XXX - likewise
"A float. Your longitude.")
+;;;; Private Variables
-;;; Private Variables
(defvar air-quality--timer nil)
(defvar air-quality--co nil "Carbon Monoxide level (micrograms per cubic-meter).")
@@ -62,30 +71,44 @@ (defvar air-quality--pm10 nil "PM 10 level (micrograms per cubic-meter).")
(defvar air-quality--nh3 nil "Ammonia level (micrograms per cubic-meter).")
(defvar air-quality--level nil "Overall Air Quality (AQI).")
-(defun air-quality--make-forecast-call (key lat lon)
- "Create an API request for the future forecast of Air Quality information from Open Weather Map."
- (concat "http://api.openweathermap.org/data/2.5/air_pollution/forecast?lat="
- (number-to-string lat)
- "&lon="
- (number-to-string lon)
- "&appid="
- key))
-
-(defun air-quality--make-api-call (key lat lon)
- "Create an API request to Open Weather Map."
- (concat "http://api.openweathermap.org/data/2.5/air_pollution?lat="
- (number-to-string lat)
- "&lon="
- (number-to-string lon)
- "&appid="
- key))
-
-(defvar air-quality--index-alist '((1 . "Good")
- (2 . "Fair")
- (3 . "Moderate")
- (4 . "Poor")
- (5 . "Very Poor")))
-
+(defun air-quality--make-api-call (key latitude longitude)
+ "Return Open Weather Map URL for LATITUDE and LONGITUDE with API key KEY."
+ (url-parse-make-urlobj
+ "https" nil nil "api.openweathermap.org" nil
+ (concat "/data/2.5/air_pollution/?"
+ (url-build-query-string `(("lat" ,latitude)
+ ("lon" ,longitude)
+ ("appid" ,key))))))
+
+(defconst air-quality--index-alist '((1 . "Good")
+ (2 . "Fair")
+ (3 . "Moderate")
+ (4 . "Poor")
+ (5 . "Very Poor")))
+
+(defvar air-quality-indicator
+ '(:eval
+ (propertize (concat " " (alist-get air-quality--level
+ air-quality--index-alist))
+ 'face 'mode-line-buffer-id
+ 'help-echo (format "Carbon Monoxide: %d µg/m³
+Nitrogen Oxide: %d µg/m³
+Nitrogen Dioxide: %d µg/m³
+Ozone: %d µg/m³
+Sulfur Dioxide: %d µg/m³
+PM 2.5: %d µg/m³
+PM 10: %d µg/m³
+Ammonia: %d µg/m³"
+ air-quality--co
+ air-quality--no
+ air-quality--no2
+ air-quality--o3
+ air-quality--so2
+ air-quality--pm2_5
+ air-quality--pm10
+ air-quality--nh3)
+ 'mouse-face 'mode-line-highlight)))
+(put 'air-quality-indicator 'risky-local-variable t)
(defun air-quality--get-update ()
"Query Open Weather for air quality information."
@@ -93,7 +116,7 @@ (defun air-quality--get-update ()
(air-quality--make-api-call air-quality-open-weather-api-key
air-quality-latitude
air-quality-longitude)
- (lambda (events)
+ (lambda (_events)
(goto-char url-http-end-of-headers)
(let ((json-object-type 'plist)
(json-key-type 'symbol)
@@ -108,57 +131,24 @@ (defun air-quality--get-update ()
(setq air-quality--pm2_5 (plist-get components 'pm2_5))
(setq air-quality--pm10 (plist-get components 'pm10))
(setq air-quality--nh3 (plist-get components 'nh3))
- (setq air-quality--level (cadadr (aref (plist-get result 'list) 0)))
- (air-quality--set-indicator)
- (run-with-idle-timer 1 nil #'air-quality--append-modeline)
- )))))
-
-(defun air-quality--set-indicator ()
- (defvar-local air-quality-indicator
- (list (propertize (concat " " (alist-get air-quality--level air-quality--index-alist))
- 'face 'mode-line-buffer-id
- 'help-echo (purecopy (format "Carbon Monoxide: %d µg/m³
-Nitrogen Oxide: %d µg/m³
-Nitrogen Dioxide: %d µg/m³
-Ozone: %d µg/m³
-Sulfur Dioxide: %d µg/m³
-PM 2.5: %d µg/m³
-PM 10: %d µg/m³
-Ammonia: %d µg/m³"
- air-quality--co
- air-quality--no
- air-quality--no2
- air-quality--o3
- air-quality--so2
- air-quality--pm2_5
- air-quality--pm10
- air-quality--nh3))
- 'mouse-face 'mode-line-highlight
- )))
- (put 'air-quality-indicator 'risky-local-variable t))
-
-
-(defun air-quality--append-modeline ()
- (unless (cl-find '(:eval air-quality-indicator) mode-line-format :test 'equal)
- (setq-default mode-line-format
- (reverse (append '((:eval air-quality-indicator)) (reverse mode-line-format))))))
+ (setq air-quality--level (cadadr (aref (plist-get result 'list) 0))))))))
;;;###autoload
-(defun air-quality-setup-modeline ()
-
- ;; This could be better...
- ;; if no timer, start one
- (if (null air-quality--timer)
- (setq air-quality--timer
- (run-with-timer 0 (* 60 air-quality-refresh-interval) #'air-quality--get-update))
- ;; otherwise, cancel the timer and start one
- (progn
- (cancel-timer air-quality--timer)
- (setq air-quality--timer
- (run-with-timer 0 (* 60 air-quality-refresh-interval) #'air-quality--get-update))
- )))
-
+(define-minor-mode air-quality-mode
+ "Minor mode for displaying air quality information in the mode line."
+ :group 'air-quality
+ :global t
+ (if air-quality-mode
+ (progn
+ ;; XXX - check that air-quality-open-weather-api-key,
+ ;; air-quality-latitude and air-quality-longitude are set
+ (add-to-list 'mode-line-misc-info 'air-quality-indicator t )
+ (setq air-quality--timer
+ (run-with-timer 0 (* 60 air-quality-refresh-interval)
+ #'air-quality--get-update)))
+ (setq mode-line-misc-info (delq 'air-quality-indicator mode-line-misc-info))
+ (cancel-timer air-quality--timer))
+ (force-mode-line-update))
(provide 'air-quality)
-
;;; air-quality.el ends here
> --
> Dr. John Haman
> Maryland, USA
next prev parent reply other threads:[~2023-09-01 9:38 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-09-01 1:58 Package critique: modeline for air quality information John Haman
2023-09-01 9:38 ` Eshel Yaron [this message]
2023-09-01 10:49 ` John Haman
2023-09-01 11:57 ` Eshel Yaron
2023-09-01 13:46 ` John Haman
2023-09-01 15:12 ` tpeplt
2023-09-02 21:24 ` Emanuel Berg
2023-09-03 16:42 ` John Haman
2023-09-04 1:15 ` Emanuel Berg
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=m1ttsexmgc.fsf@eshelyaron.com \
--to=me@eshelyaron.com \
--cc=help-gnu-emacs@gnu.org \
--cc=mail@johnhaman.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).