Caldav
by @chakyiu
Manage CalDAV calendars and events, with special support for Radicale server. Use when the user wants to create, update, delete, or query calendar events, ma...
clawhub install caldav-skillπ About This Skill
name: caldav description: Manage CalDAV calendars and events, with special support for Radicale server. Use when the user wants to create, update, delete, or query calendar events, manage calendars, or configure/administer a Radicale CalDAV server. homepage: https://github.com/python-caldav/caldav metadata: clawdbot: emoji: "π " requires: bins: ["python3"] env: []
CalDAV & Radicale Management
Interact with CalDAV servers (calendars, events, todos) and manage Radicale server configurations.
Overview
CalDAV is a protocol for accessing and managing calendaring information (RFC 4791). Radicale is a lightweight CalDAV/CardDAV server. This skill enables:
Prerequisites
Python Library
Install the caldav library:
pip install caldav
For async support:
pip install caldav[async]
Environment Variables (Recommended)
Store credentials securely in environment or config:
export CALDAV_URL="http://localhost:5232"
export CALDAV_USER="your_username"
export CALDAV_PASSWORD="your_password"
Or use a config file at ~/.config/caldav/config.json:
{
"url": "http://localhost:5232",
"username": "your_username",
"password": "your_password"
}
Scripts
Calendar Operations
# List all calendars
python3 {baseDir}/scripts/calendars.py listCreate a new calendar
python3 {baseDir}/scripts/calendars.py create --name "Work Calendar" --id workDelete a calendar
python3 {baseDir}/scripts/calendars.py delete --id workGet calendar info
python3 {baseDir}/scripts/calendars.py info --id work
Event Operations
# List events (all calendars, next 30 days)
python3 {baseDir}/scripts/events.py listList events from specific calendar
python3 {baseDir}/scripts/events.py list --calendar workList events in date range
python3 {baseDir}/scripts/events.py list --start 2024-01-01 --end 2024-01-31Create an event
python3 {baseDir}/scripts/events.py create \
--calendar work \
--summary "Team Meeting" \
--start "2024-01-15 14:00" \
--end "2024-01-15 15:00" \
--description "Weekly sync"Create all-day event
python3 {baseDir}/scripts/events.py create \
--calendar personal \
--summary "Birthday" \
--start 2024-02-14 \
--alldayUpdate an event
python3 {baseDir}/scripts/events.py update \
--uid "event-uid-here" \
--summary "Updated Title"Delete an event
python3 {baseDir}/scripts/events.py delete --uid "event-uid-here"Search events by text
python3 {baseDir}/scripts/events.py search --query "meeting"
Todo Operations
# List todos
python3 {baseDir}/scripts/todos.py list [--calendar name]Create a todo
python3 {baseDir}/scripts/todos.py create \
--calendar work \
--summary "Complete report" \
--due "2024-01-20"Complete a todo
python3 {baseDir}/scripts/todos.py complete --uid "todo-uid-here"Delete a todo
python3 {baseDir}/scripts/todos.py delete --uid "todo-uid-here"
Radicale Server Management
# Check Radicale status
python3 {baseDir}/scripts/radicale.py statusList users (from htpasswd file)
python3 {baseDir}/scripts/radicale.py users listAdd user
python3 {baseDir}/scripts/radicale.py users add --username newuserView Radicale config
python3 {baseDir}/scripts/radicale.py config showValidate Radicale config
python3 {baseDir}/scripts/radicale.py config validateCheck storage integrity
python3 {baseDir}/scripts/radicale.py storage verify
Direct HTTP/DAV Operations
For low-level operations, use curl with CalDAV:
# Discover principal URL
curl -u user:pass -X PROPFIND \
-H "Depth: 0" \
-H "Content-Type: application/xml" \
-d ' ' \
http://localhost:5232/List calendars
curl -u user:pass -X PROPFIND \
-H "Depth: 1" \
-H "Content-Type: application/xml" \
-d ' ' \
http://localhost:5232/user/Query events by time range
curl -u user:pass -X REPORT \
-H "Depth: 1" \
-H "Content-Type: application/xml" \
-d '
' \
http://localhost:5232/user/calendar/Create calendar (MKCALENDAR)
curl -u user:pass -X MKCALENDAR \
-H "Content-Type: application/xml" \
-d '
New Calendar
' \
http://localhost:5232/user/new-calendar/
Radicale Configuration
Config File Location
Radicale looks for config in:
/etc/radicale/config (system-wide)~/.config/radicale/config (user)--config or RADICALE_CONFIG envKey Configuration Sections
[server]
hosts = localhost:5232
max_connections = 20
max_content_length = 100000000
timeout = 30
ssl = False[auth]
type = htpasswd
htpasswd_filename = /etc/radicale/users
htpasswd_encryption = autodetect
[storage]
filesystem_folder = /var/lib/radicale/collections
[rights]
type = owner_only
Authentication Types
| Type | Description |
|------|-------------|
| none | No authentication (development only!) |
| denyall | Deny all (default since 3.5.0) |
| htpasswd | Apache htpasswd file |
| remote_user | WSGI-provided username |
| http_x_remote_user | Reverse proxy header |
| ldap | LDAP/AD authentication |
| dovecot | Dovecot auth socket |
| imap | IMAP server authentication |
| oauth2 | OAuth2 authentication |
| pam | PAM authentication |
Creating htpasswd Users
# Create new file with SHA-512
htpasswd -5 -c /etc/radicale/users user1Add another user
htpasswd -5 /etc/radicale/users user2
Running as Service (systemd)
# Enable and start
sudo systemctl enable radicale
sudo systemctl start radicaleCheck status
sudo systemctl status radicaleView logs
journalctl -u radicale -f
iCalendar Format Quick Reference
Events use iCalendar (RFC 5545) format:
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp//CalDAV Client//EN
BEGIN:VEVENT
UID:unique-id@example.com
DTSTAMP:20240115T120000Z
DTSTART:20240115T140000Z
DTEND:20240115T150000Z
SUMMARY:Team Meeting
DESCRIPTION:Weekly sync
LOCATION:Conference Room
END:VEVENT
END:VCALENDAR
Common Properties
| Property | Description |
|----------|-------------|
| UID | Unique identifier |
| DTSTART | Start time |
| DTEND | End time |
| DTSTAMP | Creation/modification time |
| SUMMARY | Event title |
| DESCRIPTION | Event description |
| LOCATION | Location |
| RRULE | Recurrence rule |
| EXDATE | Excluded dates |
| ATTENDEE | Participant |
| ORGANIZER | Event organizer |
| STATUS | CONFIRMED/TENTATIVE/CANCELLED |
Date Formats
# DateTime with timezone
DTSTART:20240115T140000Z ; UTC (Z suffix)
DTSTART;TZID=America/New_York:20240115T090000All-day event
DTSTART;VALUE=DATE:20240214DateTime local (floating)
DTSTART:20240115T140000
Troubleshooting
Connection Issues
# Test basic connectivity
curl -v http://localhost:5232/Check with authentication
curl -v -u user:pass http://localhost:5232/Verify CalDAV support
curl -X OPTIONS http://localhost:5232/ -I | grep -i dav
Common Errors
| Error | Cause | Solution |
|-------|-------|----------|
| 401 Unauthorized | Wrong credentials | Check htpasswd file |
| 403 Forbidden | Rights restriction | Check [rights] config |
| 404 Not Found | Wrong URL path | Check principal/calendar path |
| 409 Conflict | Resource exists | Use different UID |
| 415 Unsupported Media Type | Wrong Content-Type | Use text/calendar |
Debug Mode
Run Radicale with debug logging:
python3 -m radicale --debug
Python API Quick Reference
from caldav import DAVClientConnect
client = DAVClient(
url="http://localhost:5232",
username="user",
password="pass"
)Get principal
principal = client.principal()List calendars
for cal in principal.calendars():
print(f"Calendar: {cal.name} ({cal.url})")Create calendar
cal = principal.make_calendar(name="My Calendar", cal_id="my-cal")Create event
cal.save_event(
dtstart="2024-01-15 14:00",
dtend="2024-01-15 15:00",
summary="Meeting"
)Query events by date range
events = cal.date_search(
start="2024-01-01",
end="2024-01-31"
)
for event in events:
print(event.vobject_instance.vevent.summary.value)Get event by UID
event = cal.event_by_uid("event-uid")Delete event
event.delete()Create todo
todo = cal.save_todo(
summary="Task",
due="2024-01-20"
)
Workflow Examples
Create Recurring Event
python3 {baseDir}/scripts/events.py create \
--calendar work \
--summary "Weekly Standup" \
--start "2024-01-15 09:00" \
--end "2024-01-15 09:30" \
--rrule "FREQ=WEEKLY;BYDAY=MO,WE,FR"
Export Calendar to ICS
# Via curl
curl -u user:pass http://localhost:5232/user/calendar/ > calendar.icsVia script
python3 {baseDir}/scripts/calendars.py export --id work --output work.ics
Sync with Git (Radicale)
Configure Radicale to version changes:
[storage]
hook = git add -A && (git diff --cached --quiet || git commit -m "Changes by \"%(user)s\"")
Initialize git in storage folder:
cd /var/lib/radicale/collections
git init
git config user.email "radicale@localhost"
βοΈ Configuration
Python Library
Install the caldav library:
pip install caldav
For async support:
pip install caldav[async]
Environment Variables (Recommended)
Store credentials securely in environment or config:
export CALDAV_URL="http://localhost:5232"
export CALDAV_USER="your_username"
export CALDAV_PASSWORD="your_password"
Or use a config file at ~/.config/caldav/config.json:
{
"url": "http://localhost:5232",
"username": "your_username",
"password": "your_password"
}
π Tips & Best Practices
Connection Issues
# Test basic connectivity
curl -v http://localhost:5232/Check with authentication
curl -v -u user:pass http://localhost:5232/Verify CalDAV support
curl -X OPTIONS http://localhost:5232/ -I | grep -i dav
Common Errors
| Error | Cause | Solution |
|-------|-------|----------|
| 401 Unauthorized | Wrong credentials | Check htpasswd file |
| 403 Forbidden | Rights restriction | Check [rights] config |
| 404 Not Found | Wrong URL path | Check principal/calendar path |
| 409 Conflict | Resource exists | Use different UID |
| 415 Unsupported Media Type | Wrong Content-Type | Use text/calendar |
Debug Mode
Run Radicale with debug logging:
python3 -m radicale --debug