unofficial mirror of help-gnu-emacs@gnu.org
 help / color / mirror / Atom feed
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



  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).