org-timed-alerts
org-timed-alerts copied to clipboard
Orgmode notification warnings of upcoming events
- org-timed-alerts.el Receive warnings and alerts via =alert.el= for upcoming events in your day.
Ever look at your clock 10 minutes before a scheduled phone call, keep working on something else, and then not look at your clock until 2 minutes after the phone call was supposed to begin?
I do it all the time. It must stop.
=org-timed-alerts= scans your agenda files, finds any timestamps (active, deadline, or scheduled) with a time-of-day specification, and sends event warnings via =alert.el= according to whatever intervals you specify with custom alert messages.
WARNING: This package is under development. It is close to complete and stable for my daily use.
** Usage *** Install the dependencies:
- alert :: https://github.com/jwiegley/alert. Test =alert= by evaluating: =(alert "test")=. Did you see a notification? If so, proceed.
- dash.el :: https://github.com/magnars/dash.el
- org-ql :: https://github.com/alphapapa/org-ql
- ts.el :: https://github.com/alphapapa/ts.el *** Installation Clone this repository into your load path. #+begin_src emacs-lisp :results silent git clone https://github.com/legalnonsense/org-timed-alerts.git #+end_src *** Use-package example Use-package declaration with all custom variables set to the default values: #+begin_src emacs-lisp :results silent (use-package org-timed-alerts :after (org) :custom (org-timed-alerts-alert-function # 'alert) (org-timed-alerts-tag-exclusions nil) (org-timed-alerts-default-alert-props nil) (org-timed-alerts-warning-times '(-10 -5)) (org-timed-alerts-agenda-hook-p t) (org-timed-alert-final-alert-string "IT IS %alert-time\n\n%todo %headline") (org-timed-alert-warning-string (concat "%todo %headline\n at %alert-time\n " "it is now %current-time\n " "THIS IS YOUR %warning-time MINUTE WARNING")) :config (add-hook 'org-mode-hook #'org-timed-alerts-mode)) #+end_src *** Without use-package There is no reason not to use =use-package=, but if you refuse, you can minimally use: #+begin_src emacs-lisp :results silent (require 'org-timed-alerts) (add-hook 'org-mode-hook #'org-timed-alerts-mode) #+end_src Adding =(org-timed-alerts-mode)= to =org-mode-hook= will activate the alert timers the next time you run =org-agenda=. It will not add timers until you run =org-agenda=. ** Customization | Custom variables | Description | Default value | |------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------| | org-timed-alerts-todo-exclusions | List of TODO states to ignore when generating the alert list. E.g., '("DONE") | nilb | | org-timed-alerts-warning-times | List of integers representing the intervals of warnings preceding the event. E.g., '(-10 -5) means you want to be warned 10 minutes, 5 minutes, and 2 minutes before the event. =nil= means no warning. There is no difference between positive and negative numbers, i.e., 10 and -10 both mean to send an alert 10 minutes before the event. A final notification is automatically sent at the time the event begins. | '(-10 -5) | | org-timed-alert-final-alert-string | Message to display in the alert shown at the time event begins (see below) | "IT IS %alert-time\n\nTIME FOR:\n%todo %headline" | | org-timed-alert-warning-string | Message to be displayed for warnings that precede the event (see below) | "%todo %headline\n at %alert-time\n it is now %current-time\n * THIS IS YOUR %warning-time MINUTE WARNING *" |
| Less frequently needed custom variables | Description | Default value | |-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------| | org-timed-alerts-agenda-hook-p | Automatically add =org-timed-alerts-set-all-timers= to =org-agenda-hook=? If you turn this off, the minor mode is effectively meaningless and you’ll need to find another suitable way to call =org-timed-alerts-set-all-timers=. | t | | org-timed-alerts-default-alert-props | See the documentation for the function =alert=. This plist will be used to set the default for any of those properties. Any value of this list can be a function which will be called with the point at the org-heading. See description below. | nil | | org-timed-alerts-alert-command | Function to call when invoking the alert. See =alert.el= for other possibilities, e.g., =#'alert-libnotify-notify=, =#'alert-growl-notify=. Use these specific functions only if you don’t want to use the default alert specified in =alert-default-style=. | #'alert | *** alert strings =org-timed-alert-final-alert-string= and =org-timed-alert-warning-string= are strings that allow the following substitutions:
| string | substitution | |---------------+---------------------------------------------------------------------------| | %todo | the TODO state of the the heading, if any | | %headline | the headline text of the heading | | %alert-time | the time of the event | | %warning-time | the current number of minutes before the event | | %current-time | the time the alert is actually sent to the user | | %category | the category property of the org heading, or the name of the file if none |
For example, consider the heading: #+begin_src org
- TODO phone conference I don't want to have :PROPERTIES: :CATEGORY: annoying-client :END: <2020-11-23 Mon 15:45> #+end_src The following string: =%todo %headline\n at %alert-time\n it is now %current-time\n * THIS IS YOUR %warning-time MINUTE WARNING *= Will use these substitutions when it send a 5 minute warning: | string | substitution | |---------------+-----------------------------------------| | %todo | "TODO" | | %headline | "phone conference I don't want to have" | | %alert-time | "20:05" | | %warning-time | "5" | | %current-time | "20:00" | | %category | "annoying-client" |
And will display a warning that looks like this: [[./images/sample-alert.png]]
Unless the =:title= property is overridden by =org-timed-alerts-default-alert-props=, the title of an alert defaults to the =category= property of the org heading. ** Special property for custom alert intervals Any heading can set custom alert intervals by setting the property =:ORG-TIMED-ALERTS:= For example: #+begin_src org
- Lunch meeting :PROPERTIES: :ORG-TIMED-ALERTS: 5 4 3 2 1 :END: <2020-11-29 Sun 11:36> #+end_src Will override =org-timed-alerts-warning-times= and send alert notifications 5, 4, 3, 2, and 1 minute before the appointment time. ** Note about =org-timed-alerts-default-alert-props= As stated above, the value of any property can be a function that is run at the underlying org heading. If you want more advanced customization of the alert properties, you can take advantage of this. For example, suppose you wanted the title of each alert to show the text of the root heading in the tree: #+begin_src emacs-lisp :results silent (setq org-timed-alerts-default-alert-props '(:title (lambda () (save-excursion ;; Move to the root heading (while (org-up-heading-safe)) ;; Return its headline, without tags, todo, etc. (org-get-heading t t t t))))) #+end_src Or suppose you wanted to customize the icon for an alert depending on the priority of the heading: #+begin_src emacs-lisp :results silent (setq org-timed-alerts-default-alert-props '(:icon (lambda () (if (string= "A" (org-entry-get (point) "PRIORITY")) "/path/to/some/icon" "/path/to/some/other/icon")))) #+end_src ** Updating the timers =org-timed-alerts= updates itself via =org-agenda-hook=. This is fast enough that I don't notice much speed difference when generating an agenda. You can turn this off by setting =org-timed-alerts-agenda-hook-p= to nil. If you do that, you can update manually with =org-timed-alerts-set-all-timers= or find another suitable hook (the package only schedules timers for the current day, so you'll need to update at least daily and after any relevant timestamp changes).
- How it works
- Run an org-ql query to get all active timestamps, scheduled timestamps, and deadlines on the current date.
- For each of these events which has an associated time:
- Create a timer to send an alert at that time via alert.el. This alert will use the string =org-timed-alert-final-alert-string=
- Create warning timers according to the intervals specified in =org-timed-alerts-warning-times= and using the string =org-timed-alert-warning-string=
- Update all timers any time the user runs =org-agenda=. You can update manually with =org-timed-alerts-set-all-timers=. You can disable all timers with =org-timed-alerts-cancel-all-timers= or by disabling the minor mode.
- Other efforts This pacakge is meant to do what I want and and nothing more; I tried to abstract a bit so others might find it useful. I have included my notes on other similar packages. Apologies to the authors if they are not accurate.
=org-alert=. /See/ https://github.com/spegoraro/org-alert. Org-alert checks for items which are scheduled or with deadlines for the current date, and then sends notification of those items immediately and simultaneously. It will resend notifications if you run =org-alert-check=. It serves a different purpose than this package.
=org-notify=. /See/ https://code.orgmode.org/bzg/org-mode/raw/master/contrib/lisp/org-notify.el. Org-notify allows notifications to be scheduled and customized, but requires a special property to be set for each org heading for which an alert is desired. It also does not seem to use =alert.el= by default but appears it could be customized to do so. There are a lot of nice customization options here, but it asks a lot of the user with regard to setting special properties. By contrast, the goal of =org-timed-alerts= is to stay out of the way of the user by not requiring setting any special properties. In short, I feared getting this package set up for my purposes would be less enjoyable than writing a custom solution.
=org-wild-notifier=. /See/ https://github.com/akhramov/org-wild-notifier.el. Org-wild-notifier is the closest to =org-timed-alerts=. The biggest drawback I saw was the inability to customize the alert message. /See/ /https://github.com/akhramov/org-wild-notifier.el/issues/43. Otherwise, this package may serve your purposes.
- Changelog
- [2020-12-03 Thu] Add support for repeating timestamps
- [2020-12-04 Fri] Add support for excluding TODO states in =org-timed-alerts-todo-exclusions=