-
-
Notifications
You must be signed in to change notification settings - Fork 34
Examples: Calendar Scheduling
Version: v0.5.0 Difficulty: Advanced Prerequisites: Home Assistant calendar integration (Google, Local, iCloud, etc.)
Automatically set chore due dates based on calendar events. Perfect for tasks with variable schedules that change weekly or monthly (trash pickup days, lawn mowing based on weather, seasonal chores).
What You'll Learn:
- Calendar event lookup with date range
- Dynamic due date assignment using
kidschores.set_chore_due_date - Event name matching strategies
- Automation logging for debugging
Note
This is NOT a built-in KidsChores feature but a custom integration pattern using Home Assistant's calendar services. Should work with any calendar integration.
- Manually update chore due dates when schedules change
- Edit KidsChores configuration every time trash day shifts
- Remember to update automations for seasonal changes
- Single Source of Truth: Calendar controls chore schedules
- Easy Updates: Change calendar event β chore due date updates automatically
- Recurring Events: Leverage calendar recurrence for repeating chores
- Family Coordination: Everyone sees the schedule in shared calendar
- Trigger: Automation runs on schedule (daily, weekly, etc.)
- Lookup: Searches calendar for next occurrence of specific event
- Extract: Gets event start time
-
Apply: Sets chore due date using
kidschores.set_chore_due_dateservice - Log: Records result for debugging
- Date Range: Configurable lookahead window (7, 14, 21, 30 days)
- Event Name: Exact or partial string matching
- First Match: Uses earliest event found in range
Use Case: Trash pickup day varies weekly (Monday week 1, Tuesday week 2). Calendar event "Garbage Night" set by city/HOA.
-
Add Calendar to Home Assistant:
- Settings β Devices & Services β Add Integration
- Search for your calendar provider (Google, Local Calendar, etc.)
- Authorize and configure
-
Create Calendar Event:
- Event Title: "Garbage Night" (use unique name)
- Recurrence: Weekly (adjust date each week as needed)
- Set time: Evening before pickup (e.g., 8 PM night before)
-
Create Chore in KidsChores:
- Chore Name: "Take Out Trash"
- Assign to kid(s)
- Set recurrence (optional - due date will override)
alias: "Calendar: Set Trash Chore Due Date"
description: "Update trash chore due date from calendar event"
triggers:
- trigger: time
at: "08:00:00" # Run daily at 8 AM
conditions: []
actions:
# Step 1: Query calendar for upcoming events
- target:
entity_id: calendar.household_chores # β οΈ Replace with your calendar entity
data:
start_date_time: "{{ now().isoformat() }}"
end_date_time: "{{ (now() + timedelta(days=21)).isoformat() }}" # β οΈ Adjust lookahead window
response_variable: calendar_events
action: calendar.get_events
alias: "Fetch calendar events (next 21 days)"
# Step 2: Find first event matching name and extract start time
- variables:
calendar_event_name: "Garbage Night" # β οΈ Replace with your event name
next_event_start_timestamp: >-
{% set ns = namespace(event=None) %}
{% for key, value in calendar_events.items() %}
{% for event in value.events %}
{% if calendar_event_name in event.summary %}
{% set ns.event = event %}
{% break %}
{% endif %}
{% endfor %}
{% endfor %}
{% if ns.event.start is defined and ns.event.start not in [none, 'unknown', 'unavailable'] %}
{{ ns.event.start | as_datetime | as_timestamp }}
{% else %}
{{ none }}
{% endif %}
alias: "Extract event start time"
# Step 3: Log result for debugging
- action: logbook.log
metadata: {}
data:
name: "Trash Chore Scheduler"
entity_id: "{{ this.entity_id }}"
message: >-
{% if next_event_start_timestamp not in [none, 'unknown', 'unavailable'] %}
Found event: {{ next_event_start_timestamp | timestamp_custom('%Y-%m-%d %H:%M:%S', true) }}
{% else %}
Event not found in next 21 days
{% endif %}
alias: "Log calendar lookup result"
# Step 4: Set chore due date if event found
- if:
- condition: template
value_template: "{{ next_event_start_timestamp not in [none, 'unknown', 'unavailable'] }}"
then:
- action: kidschores.set_chore_due_date
metadata: {}
data:
chore_name: "Take Out Trash" # β οΈ Replace with your chore name
due_date: >-
{{ next_event_start_timestamp | timestamp_custom('%Y-%m-%dT%H:%M:%S.000Z', true) }}
alias: "Update chore due date"
mode: single| Parameter | What to Change | Example |
|---|---|---|
entity_id (calendar query) |
Your calendar entity ID | calendar.household_chores |
timedelta(days=21) |
Lookahead window (days to search) |
7 for weekly, 30 for monthly |
calendar_event_name |
Exact or partial event title | "Garbage Night" |
chore_name |
KidsChores chore name to update | "Take Out Trash" |
Trigger at
|
When automation runs daily |
"08:00:00" (8 AM) |
Good Event Names (Unique):
- β "Garbage Night Chore"
- β "Trash Pickup Reminder"
- β "Weekly Waste Collection"
Bad Event Names (Too Generic):
- β "Trash" (might match unrelated events)
- β "Garbage" (could match "Take Garbage Out to Curb", "Garbage Disposal Repair")
- β "Chore" (would match every chore-related event)
Matching Logic: Uses in operator (substring match)
{ % if calendar_event_name in event.summary % } # Matches partial stringsUse Case: Multiple chores scheduled via different calendar events (lawn mowing, pool cleaning, garden watering).
Create separate automations for each chore-calendar pair to maintain clarity and independent scheduling.
Lawn Mowing Automation:
alias: "Calendar: Set Lawn Mowing Due Date"
triggers:
- trigger: time
at: "06:00:00" # Run at 6 AM
actions:
- target:
entity_id: calendar.household_chores
data:
start_date_time: "{{ now().isoformat() }}"
end_date_time: "{{ (now() + timedelta(days=14)).isoformat() }}" # 2 weeks lookahead
response_variable: calendar_events
action: calendar.get_events
- variables:
calendar_event_name: "Mow Lawn Day"
next_event_start_timestamp: >-
{% set ns = namespace(event=None) %}
{% for key, value in calendar_events.items() %}
{% for event in value.events %}
{% if calendar_event_name in event.summary %}
{% set ns.event = event %}
{% break %}
{% endif %}
{% endfor %}
{% endfor %}
{% if ns.event.start is defined and ns.event.start not in [none, 'unknown', 'unavailable'] %}
{{ ns.event.start | as_datetime | as_timestamp }}
{% else %}
{{ none }}
{% endif %}
- if:
- condition: template
value_template: "{{ next_event_start_timestamp not in [none, 'unknown', 'unavailable'] }}"
then:
- action: kidschores.set_chore_due_date
data:
chore_name: "Mow Lawn"
due_date: "{{ next_event_start_timestamp | timestamp_custom('%Y-%m-%dT%H:%M:%S.000Z', true) }}"
mode: singlePool Cleaning Automation: (Same structure, different event name and chore)
alias: "Calendar: Set Pool Cleaning Due Date"
triggers:
- trigger: time
at: "07:00:00"
actions:
# ... (same calendar query structure)
- variables:
calendar_event_name: "Pool Service Day" # Different event
# ... (same extraction logic)
- if:
# ... (same condition)
then:
- action: kidschores.set_chore_due_date
data:
chore_name: "Clean Pool" # Different chore
due_date: "{{ next_event_start_timestamp | timestamp_custom('%Y-%m-%dT%H:%M:%S.000Z', true) }}"
mode: singleUse Case: Set chore due date exactly when calendar event starts (no daily polling).
Limitation: Requires calendar integration that supports event triggers (Google Calendar, Local Calendar).
alias: "Calendar Event: Set Trash Due Date on Event Start"
description: "Triggered when 'Garbage Night' event starts"
triggers:
- trigger: calendar
event: start
entity_id: calendar.household_chores
conditions:
- condition: template
value_template: "{{ 'Garbage Night' in trigger.calendar_event.summary }}"
actions:
- action: kidschores.set_chore_due_date
data:
chore_name: "Take Out Trash"
due_date: "{{ trigger.calendar_event.start }}"
- action: logbook.log
data:
name: "Trash Chore Scheduler"
message: "Set due date from calendar event: {{ trigger.calendar_event.start }}"
entity_id: "{{ this.entity_id }}"
mode: singleAdvantages:
- β Instant updates (no polling delay)
- β Simpler logic (no lookahead search)
- β Automatic on event start
Disadvantages:
- β Requires calendar integration with event triggers
- β Only sets due date when event starts (not in advance)
- β Can't set due date days before event
| Chore Frequency | Recommended Lookahead | Reasoning |
|---|---|---|
| Daily (variable) | 7 days | Catch changes for upcoming week |
| Weekly | 14-21 days | Handle schedule variations (holidays, etc.) |
| Bi-weekly | 30 days | Ensure next occurrence found |
| Monthly | 45-60 days | Account for month-end variations |
| Seasonal/Irregular | 90+ days | Find next occurrence regardless of frequency |
Why Not Search Further?:
- Longer searches = more API calls (performance impact)
- Calendar integrations may have query limits
- Unnecessary for frequent tasks
Trigger Frequency:
- Daily tasks: Run automation once daily (morning)
- Weekly tasks: Run 2-3x per week
- Monthly tasks: Run weekly
Potential Causes:
- Event name doesn't match (check spelling/capitalization)
- Event outside lookahead window
- Calendar not syncing with Home Assistant
Debugging Steps:
# Add diagnostic logging before main logic
- action: logbook.log
data:
name: "Calendar Debug"
message: >-
Searching for: "{{ calendar_event_name }}"
Calendar events found: {{ calendar_events | length }}
Date range: {{ now().isoformat() }} to {{ (now() + timedelta(days=21)).isoformat() }}Potential Causes:
- Chore name doesn't match KidsChores configuration
- Timestamp format incorrect
- Service call failing silently
Debugging Steps:
- Check Developer Tools β States β search for chore sensor
- Verify chore name in KidsChores: Settings β Integrations β KidsChores β Configure
- Test service manually in Developer Tools β Services:
action: kidschores.set_chore_due_date data: chore_name: "Take Out Trash" due_date: "2025-02-15T20:00:00.000Z"
Cause: Timestamp not in ISO 8601 format with UTC timezone.
Solution: Use exact filter format:
{
{
next_event_start_timestamp | timestamp_custom('%Y-%m-%dT%H:%M:%S.000Z',
true),
},
}Breakdown:
-
%Y-%m-%d= Date (2025-02-15) -
T= ISO separator -
%H:%M:%S= Time (20:00:00) -
.000Z= Milliseconds + UTC indicator -
true= Use UTC timezone
Cause: Event name matching multiple calendar entries.
Solution: Make event name more specific:
# Too generic
calendar_event_name: "Trash"
# More specific
calendar_event_name: "Garbage Night Chore"
# Or use exact match instead of substring:
{% if event.summary == calendar_event_name %} # Exact match onlySeparate Calendar for Chores (Recommended):
- Create dedicated "Household Chores" calendar
- Prevents conflicts with personal/work events
- Easier to share with family
Event Naming Convention:
- Prefix chore events: "CHORE: Trash Night", "CHORE: Mow Lawn"
- Use consistent format for easy filtering
- Include location if relevant: "Trash (Curbside)", "Trash (Alley)"
Folder Organization:
- Create "Calendar Automations" folder in Home Assistant
- Name pattern: "Calendar: [Chore Name] Scheduler"
- Group related automations (all trash, all lawn, etc.)
Documentation:
- Comment automation YAML with event name and chore mappings
- Keep list of calendar-to-chore pairings in automation description
- Document trigger frequency and lookahead window
Calendar Query Limits:
- Don't query calendar too frequently (respect API limits)
- Google Calendar: ~1000 requests/day/user
- Local Calendar: No strict limit but impacts database
Optimal Trigger Schedule:
# Good: Daily for weekly chores
triggers:
- trigger: time
at: "08:00:00"
# Better: 3x weekly for weekly chores
triggers:
- trigger: time
at: "08:00:00"
weekday: [mon, wed, fri]
# Avoid: Hourly (unnecessary API calls)
triggers:
- trigger: time_pattern
hours: "*" # β Too frequentLimitation: kidschores.set_chore_due_date cannot specify individual kids for Shared chores.
Solution: Calendar sets due date for entire shared chore (all assigned kids).
# This works for Shared chores
- action: kidschores.set_chore_due_date
data:
chore_name: "Take Out Trash" # Shared by Sarah and Alex
due_date: "{{ next_event_start_timestamp | timestamp_custom('%Y-%m-%dT%H:%M:%S.000Z', true) }}"
# β οΈ Do NOT include kid_name for Shared chores (will fail)Feature: Set due dates per kid using kid_name parameter.
# Different kids, same chore, different due dates
- action: kidschores.set_chore_due_date
data:
chore_name: "Clean Room"
due_date: "2025-02-15T18:00:00.000Z"
kid_name: "Sarah" # Only Sarah's due date updated
- action: kidschores.set_chore_due_date
data:
chore_name: "Clean Room"
due_date: "2025-02-16T18:00:00.000Z"
kid_name: "Alex" # Alex gets different due dateOne-Time Chores:
- Due date applies once
- After approval, due date clears automatically
- Perfect for calendar-based seasonal tasks
Recurring Chores:
- Due date overrides recurrence pattern temporarily
- After approval, chore resets per recurrence settings
- Calendar event can override next occurrence
-
Services Reference -
set_chore_due_dateservice documentation - Chore Configuration Guide - Recurrence and scheduling settings
- Chore Advanced Features - Shared chores, completion criteria
- Home Assistant Calendar Integration - https://www.home-assistant.io/integrations/calendar/
π Getting Started
βοΈ Configuration
- Kids & Parents
- Chores
- Chores - Advanced
- Rewards
- Points System
- Badges - Cumulative
- Badges - Periodic
- Notifications
π§ Services & Examples
π Advanced Topics
- Dashboard Integration
- Access Control
- Badge Gamification
- Badge Cumulative - Advanced
- Badge Periodic - Advanced
π Technical Reference
π©βπ§ Troubleshooting