Update Makefile, README and service file for remindme_caldav
- The Makefile now includes installation instructions for Debian/Ubuntu based systems. - The README has been updated with more detailed descriptions of the script's purpose, how it works, and how to use it. - The service file has been added to manage the remindme_caldav daemon on a systemd-based system.
This commit is contained in:
parent
740ac039dd
commit
8fe759673d
|
@ -0,0 +1,18 @@
|
||||||
|
install:
|
||||||
|
sudo apt-get update && sudo apt-get install -y python3.11 python3.11-venv
|
||||||
|
python3.11 -m venv /opt/remindme_caldav/.venv
|
||||||
|
source /opt/remindme_caldav/.venv/bin/activate && pip install --upgrade pip && pip install -r requirements.txt
|
||||||
|
cp remindme_caldav.py /opt/remindme_caldav/
|
||||||
|
sudo cp remindme_caldav.service /etc/systemd/system/
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl enable remindme_caldav.service
|
||||||
|
sudo systemctl start remindme_caldav.service
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
sudo systemctl stop remindme_caldav.service
|
||||||
|
sudo systemctl disable remindme_caldav.service
|
||||||
|
rm -rf /opt/remindme_caldav
|
||||||
|
rm /etc/systemd/system/remindme_caldav.service
|
||||||
|
|
||||||
|
clean:
|
||||||
|
deactivate
|
66
README.md
66
README.md
|
@ -1,3 +1,67 @@
|
||||||
# remindme_caldav
|
# remindme_caldav
|
||||||
|
## A Calendar Alerting Daemon
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
This script is a simple calendar alerting daemon written in Python. It monitors
|
||||||
|
.ics files for changes and sends alerts based on the events' start times,
|
||||||
|
recurrence rules, and alert triggers defined within these files. The main
|
||||||
|
purpose of this script is to provide reminders or notifications about upcoming
|
||||||
|
events.
|
||||||
|
|
||||||
|
## How it Works
|
||||||
|
The script works by parsing .ics files using the `icalendar` library, which
|
||||||
|
converts them into a Python dictionary format for easier manipulation. It then
|
||||||
|
processes each event and calculates when the next alert should be triggered
|
||||||
|
based on the event's start time, recurrence rules, and alert triggers. If an
|
||||||
|
alert is due to trigger, it sends a notification via email or XMPP (an instant
|
||||||
|
messaging protocol).
|
||||||
|
|
||||||
|
The script also monitors for changes in the directory containing .ics files
|
||||||
|
using the `watchdog` library. When a file is modified, created, or deleted, it
|
||||||
|
updates its internal list of events accordingly.
|
||||||
|
|
||||||
|
## How to Use It
|
||||||
|
This script should be used with a calendar syncing service such as vdirsyncer.
|
||||||
|
vdirsyncer can be scheduled using cron to sync regularly from the CalDav
|
||||||
|
server.
|
||||||
|
|
||||||
|
To use this script, you need Python 3 installed on your system. You can install
|
||||||
|
the required libraries by running:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
You also need a .toml configuration file with the following structure:
|
||||||
|
```toml
|
||||||
|
[app]
|
||||||
|
calendar_dir = "/path/to/your/ics/files"
|
||||||
|
email_address = "your-email@example.com"
|
||||||
|
smtp_server = "smtp.example.com"
|
||||||
|
smtp_port = 587
|
||||||
|
smtp_username = "your-username"
|
||||||
|
smtp_password = "your-password"
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
You can then run the script with:
|
||||||
|
```bash
|
||||||
|
python3 remindme_caldav.py --config /path/to/your/config.toml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
A Makefile and systemd service file is also included for Debian/Ubuntu based
|
||||||
|
systems.
|
||||||
|
|
||||||
|
This Makefile does the following:
|
||||||
|
- install: Installs Python 3.11, creates a virtual environment in
|
||||||
|
/opt/remindme_caldav/.venv, installs dependencies from requirements.txt
|
||||||
|
into this virtual environment, copies your script to /opt/remindme_caldav/,
|
||||||
|
and sets up the systemd service file.
|
||||||
|
|
||||||
|
- uninstall: Stops and disables the systemd service, removes the installation
|
||||||
|
directory (/opt/remindme_caldav/), and deletes the systemd service file.
|
||||||
|
|
||||||
|
- clean: Deactivates the virtual environment.
|
||||||
|
|
||||||
|
|
||||||
A simple script to send alerts/reminders for caldav events.
|
|
|
@ -131,15 +131,6 @@ class FileChangeHandler(FileSystemEventHandler):
|
||||||
class RecurringEventGenerator:
|
class RecurringEventGenerator:
|
||||||
"""
|
"""
|
||||||
A class to generate recurring events based on a start date and a recurrence rule.
|
A class to generate recurring events based on a start date and a recurrence rule.
|
||||||
|
|
||||||
Attributes:
|
|
||||||
dtstart (datetime): The starting date of the event series.
|
|
||||||
rrule (rrule): The recurrence rule for the event series.
|
|
||||||
|
|
||||||
Methods:
|
|
||||||
__init__(self, dtstart, rrule): Initializes the class with a start date and a recurrence rule.
|
|
||||||
generate(self): Generates the recurring events based on the start date and recurrence rule.
|
|
||||||
Returns a dictionary containing information about the recurring events.
|
|
||||||
"""
|
"""
|
||||||
def __init__(self, dtstart, rrule):
|
def __init__(self, dtstart, rrule):
|
||||||
self.dtstart = dtstart
|
self.dtstart = dtstart
|
||||||
|
@ -212,15 +203,6 @@ class CalendarParser:
|
||||||
def parse_calendar(self, cal_str):
|
def parse_calendar(self, cal_str):
|
||||||
"""
|
"""
|
||||||
Parse a calendar string and process each event.
|
Parse a calendar string and process each event.
|
||||||
|
|
||||||
Args:
|
|
||||||
cal_str (str): The iCalendar string to be parsed.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
dict: A dictionary containing information about the processed events.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
RuntimeError: If there are no dates returned for an event or if there is an error calculating the event hash.
|
|
||||||
"""
|
"""
|
||||||
# Parse the calendar
|
# Parse the calendar
|
||||||
cal = self.parse_icalendar(cal_str)
|
cal = self.parse_icalendar(cal_str)
|
||||||
|
@ -261,15 +243,6 @@ class CalendarParser:
|
||||||
def parse_icalendar(self, cal_str):
|
def parse_icalendar(self, cal_str):
|
||||||
"""
|
"""
|
||||||
Parse a calendar string into an iCalendar object.
|
Parse a calendar string into an iCalendar object.
|
||||||
|
|
||||||
Args:
|
|
||||||
cal_str (str): The iCalendar string to be parsed.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Calendar: An iCalendar object representing the parsed calendar.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
RuntimeError: If there is an error parsing the calendar.
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return Calendar.from_ical(cal_str)
|
return Calendar.from_ical(cal_str)
|
||||||
|
@ -279,12 +252,6 @@ class CalendarParser:
|
||||||
def process_event(self, event):
|
def process_event(self, event):
|
||||||
"""
|
"""
|
||||||
Process an event from a parsed calendar and extract relevant information.
|
Process an event from a parsed calendar and extract relevant information.
|
||||||
|
|
||||||
Args:
|
|
||||||
event (Event): An iCalendar event object to be processed.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
dict: A dictionary containing the extracted event information.
|
|
||||||
"""
|
"""
|
||||||
event_info = {
|
event_info = {
|
||||||
"uid": None,
|
"uid": None,
|
||||||
|
@ -307,15 +274,6 @@ class CalendarParser:
|
||||||
def dtstart_to_datetime(self, dtstart):
|
def dtstart_to_datetime(self, dtstart):
|
||||||
"""
|
"""
|
||||||
Convert a date or datetime object into a datetime object with UTC timezone.
|
Convert a date or datetime object into a datetime object with UTC timezone.
|
||||||
|
|
||||||
Args:
|
|
||||||
dtstart (date/datetime): The date or datetime to be converted.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
datetime: A datetime object representing the input date or datetime in UTC timezone.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
RuntimeError: If there is an error converting the input to a datetime object.
|
|
||||||
"""
|
"""
|
||||||
# Ensure dates are always as datetime
|
# Ensure dates are always as datetime
|
||||||
try:
|
try:
|
||||||
|
@ -329,16 +287,6 @@ class CalendarParser:
|
||||||
def remove_exdates(self, exdates, recur_dates):
|
def remove_exdates(self, exdates, recur_dates):
|
||||||
"""
|
"""
|
||||||
Remove dates from a list of recurring event dates that are in the exdate list.
|
Remove dates from a list of recurring event dates that are in the exdate list.
|
||||||
|
|
||||||
Args:
|
|
||||||
exdates (list): A list of datetime objects representing excluded dates.
|
|
||||||
recur_dates (list): A list of datetime objects representing recurring event dates.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
list: A list of datetime objects representing the remaining recurring event dates after removing the exdate dates.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
RuntimeError: If there is an error processing the exdates.
|
|
||||||
"""
|
"""
|
||||||
if exdates != []:
|
if exdates != []:
|
||||||
try:
|
try:
|
||||||
|
@ -355,12 +303,6 @@ class CalendarParser:
|
||||||
def process_valarm(self, event):
|
def process_valarm(self, event):
|
||||||
"""
|
"""
|
||||||
Process VALARM components from an iCalendar event and extract trigger times.
|
Process VALARM components from an iCalendar event and extract trigger times.
|
||||||
|
|
||||||
Args:
|
|
||||||
event (Event): An iCalendar event object to be processed.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
list: A list of datetime objects representing the extracted trigger times.
|
|
||||||
"""
|
"""
|
||||||
valarms = []
|
valarms = []
|
||||||
for subcomponent in event.walk("valarm"):
|
for subcomponent in event.walk("valarm"):
|
||||||
|
@ -371,7 +313,7 @@ class CalendarParser:
|
||||||
|
|
||||||
def get_next_alert(event, current_time):
|
def get_next_alert(event, current_time):
|
||||||
"""
|
"""
|
||||||
This function returns the next alert that should be processed based on the current time.
|
Returns the next alert that should be processed based on the current time.
|
||||||
"""
|
"""
|
||||||
event_dates = event["event_dates"]
|
event_dates = event["event_dates"]
|
||||||
valarm_deltas = event["valarms"]
|
valarm_deltas = event["valarms"]
|
||||||
|
@ -387,7 +329,7 @@ def get_next_alert(event, current_time):
|
||||||
|
|
||||||
def process_alert(current_time, next_alert, next_event, event, config):
|
def process_alert(current_time, next_alert, next_event, event, config):
|
||||||
"""
|
"""
|
||||||
This function processes a given alert and passes it to a messaging client.
|
Processes a given alert and passes it to a messaging client.
|
||||||
"""
|
"""
|
||||||
if current_time >= next_alert and current_time < next_alert + dt.timedelta(seconds=15):
|
if current_time >= next_alert and current_time < next_alert + dt.timedelta(seconds=15):
|
||||||
if len(event["alert_history"]) == 0:
|
if len(event["alert_history"]) == 0:
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Calendar Alerting Daemon
|
||||||
|
After=network.target
|
||||||
|
StartLimitIntervalSec=0
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
Restart=always
|
||||||
|
RestartSec=1
|
||||||
|
User=root
|
||||||
|
ExecStart=/opt/remindme_caldav/.venv/bin/python3 /opt/remindme_caldav/remindme_caldav.py --config /etc/remindme_caldav/config.toml
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
|
Loading…
Reference in New Issue