summary refs log tree commit diff stats
path: root/lisp/dawn.el
blob: 806c42263260cf59794a654ab384ce70392d4176 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
;;; dawn.el --- Do things at dawn (and dusk) -*- lexical-binding: t; -*-

;;; Commentary:

;; There is also circadian.el, but it doesn't quite work for me.
;; This code comes mostly from https://gnu.xyz/auto_theme.html, but also
;; somewhere else (which I've forgotten) and my own brain :)

;;; Code:

(require 'calendar)
(require 'cl-lib)
(require 'solar)

(defvar dawn--dawn-timer nil
  "Timer for dawn-command.")

(defvar dawn--dusk-timer nil
  "Timer for dusk-command.")

(defvar dawn--reset-timer nil
  "Timer to reset dawn at midnight.")

(defun dawn-encode-time (f)
  "Encode fractional time F."
  (let ((hhmm (cl-floor f))
        (date (cdddr (decode-time))))
    (encode-time
     (append (list 0
                   (round (* 60 (cadr hhmm)))
                   (car hhmm)
                   )
             date))))

(defun dawn-midnight ()
  "Return the time of the /next/ midnight."
  (let ((date (cdddr (decode-time))))
    (encode-time
     (append (list 0 0 0 (1+ (car date))) (cdr date)))))

(defun dawn-sunrise ()
  "Return the time of today's sunrise."
  (dawn-encode-time (caar (solar-sunrise-sunset (calendar-current-date)))))

(defun dawn-sunset ()
  "Return the time of today's sunset."
  (dawn-encode-time (caadr (solar-sunrise-sunset (calendar-current-date)))))

(defun dawn-schedule (dawn-command dusk-command)
  "Run DAWN-COMMAND at sunrise, and DUSK-COMMAND at dusk.
RESET is an argument for internal use."
  (when (or (null calendar-longitude)
	    (null calendar-latitude))
    (user-error "`dawn' won't work without setting %s!"
		(cond ((and (null calendar-longitude)
                            (null calendar-latitude))
                       "`calendar-longitude' and `calendar-latitude'")
                      ((null calendar-longitude)
                       "`calendar-longitude'")
                      ((null calendar-latitude)
                       "`calendar-latitude'"))))
  (let ((dawn (dawn-sunrise))
        (dusk (dawn-sunset)))
    (cond
     ((time-less-p nil dawn)
      ;; If it isn't dawn yet, it's still dark.  Run DUSK-COMMAND and schedule
      ;; DAWN-COMMAND and DUSK-COMMAND for later.
      (funcall dusk-command)
      (run-at-time dawn nil dawn-command)
      (run-at-time dusk nil dusk-command))
     ((time-less-p nil dusk)
      ;; If it isn't dusk yet, it's still light.  Run DAWN-COMMAND and schedule
      ;; DUSK-COMMAND.
      (funcall dawn-command)
      (run-at-time dusk nil dusk-command))
     (t ;; Otherwise, it's past dusk, so run DUSK-COMMAND.
      (funcall dusk-command)))
    ;; Schedule a reset at midnight, to re-calculate dawn/dusk times.
    ;(unless reset)
    (run-at-time (dawn-midnight) nil
                 #'dawn-schedule dawn-command dusk-command)))

(provide 'dawn)
;;; dawn.el ends here