So my warmup for today was to rewrite my old org-mode agenda notification code to use Emacs lisp instead of Python. The aim of this code is to check your org-mode agenda for any headings with DEADLINEs and create a vcalendar for each, and then send them to your phone via Clickatell.

To use it, save the code into your Emacs lib path, and then in your .emacs you'll want something like:

(require 'org-agenda-sms)

(setq org-agenda-sms-username "")
(setq org-agenda-sms-password "hunter2")
(setq org-agenda-sms-api-key "")
(setq org-agenda-sms-phone "")

(run-at-time "7am" nil 'org-agenda-sms)

The contents of org-agenda-sms.el is below:

;;
;; Org-agenda-sms.el
;; Allows Emacs to SMS you a vcalendar of appointments each day
;; Written by Zane Ashby (http://www.demonastery.org)
;;
;; Usage: (run-at-time "07am" nil 'org-agenda-sms)
;;

(defvar org-agenda-sms-username nil "Clickatell username for SMS")
(defvar org-agenda-sms-password nil "Clickatell password for SMS")
(defvar org-agenda-sms-api-key nil "Clickatell API key for SMS")
(defvar org-agenda-sms-phone nil "Phone number for SMS")

;;;###autoload
(defun org-agenda-sms-build-vcal (header timestamp)
  "Builds a vcalendar from a header and timestamp"
  (let ((vcal-template "BEGIN:VCALENDAR
VERSION:1.0
BEGIN:VEVENT
CATEGORIES:APPOINTMENT
DTSTART:%s
DTEND:%s
SUMMARY:%s
DESCRIPTION:%s
END:VEVENT
END:VCALENDAR")
        (time (format-time-string "%Y-%m-%d %H%M"
               (apply 'encode-time (org-parse-time-string timestamp)))))
    (format vcal-template time time header header)))

;;;###autoload
(defun org-agenda-sms-send (text &optional type)
  "Send an SMS vcalendar provided by \"text\""
  (let* ((text (url-hexify-string text))
         (url-format "https://api.clickatell.com/http/sendmsg?user=%s&password=%s&api_id=%s&to=%s&msg_type=%s&text=%s")
         (url (format url-format org-agenda-sms-username org-agenda-sms-password org-agenda-sms-api-key org-agenda-sms-phone (if type type "SMS_NOKIA_VCAL") text)))
    (message "Retrieving api.clickatell.com/http/sendmsg..")
    (url-retrieve-synchronously url)))

;;;###autoload
(defun org-agenda-sms ()
  "Check for appointments in org-agenda and SMS as vcalendar to phone"
  (org-map-entries
   (lambda ()
     (let ((heading (clean-org-heading (nth 4 (org-heading-components))))
           (props (org-entry-properties)))
       (cond
        ((assoc "DEADLINE" props)
         (org-agenda-sms-send (org-agenda-sms-build-vcal heading (cdr (assoc "DEADLINE" props)))))
        ((assoc "SCHEDULED" props)
         (org-agenda-sms-send (org-agenda-sms-build-vcal heading (cdr (assoc "SCHEDULED" props)))))
        ((assoc "TIMESTAMP" props)
         (org-agenda-sms-send (org-agenda-sms-build-vcal heading (cdr (assoc "TIMESTAMP" props))))))))
   "TIMESTAMP<=\"<+1d>\"|DEADLINE<=\"<+1d>\"|SCHEDULED<=\"<+1d>\""
   'agenda))

(provide 'org-agenda-sms)

Seems to work for me, but as always your mileage may vary ;)


(Maybe) Related posts: