Examples: Overdue Penalties - ad-ha/kidschores-ha GitHub Wiki
Version: v0.5.0 Difficulty: Beginner Prerequisites: None (uses KidsChores services only)
Automatically apply point penalties when chores become overdue. Creates accountability and motivates timely completion without constant parent reminders.
Note
New in v0.5.0: Periodic Badges now include sophisticated penalty systems built-in. If you're tracking daily/weekly completion patterns, consider using Periodic Badges with Strict Mode and penalties instead of custom automations. This automation pattern is still useful for specific use cases not covered by badges.
What You'll Learn:
- State change trigger patterns (Pending → Overdue)
- Fixed vs variable penalty amounts
- Notification integration
- Grace period implementation
Tip
Penalties work best when paired with positive reinforcement (bonuses for on-time completion). Balance stick with carrot!
- Parent fatigue: Constantly nagging about overdue chores
- Inconsistent consequences: Forget to apply penalties
- Delayed feedback: Kid doesn't connect overdue chore to consequence
- Negotiation battles: Kid argues about penalty fairness
- Immediate feedback: Penalty applied moment chore becomes overdue
- Consistency: Same consequence every time (no favoritism)
- Self-accountability: Kids track due dates to avoid penalties
- Parent neutrality: "The system applied penalty, not me"
Chore State Sensors:
-
sensor.kc_<kid>_chore_<chore_name>_statereports current state - State changes:
Pending→Overduewhen due date passes
Overdue Binary Sensors:
-
binary_sensor.kc_<kid>_chore_<chore_name>_overdueturnsonwhen overdue - Turns
offwhen chore approved or reset
Service: kidschores.apply_penalty
Parameters:
-
kid_name(required): Which kid to penalize -
amount(required): Point deduction (positive integer) -
reason(optional): Description for penalty log
Effect: Immediately deducts points from kid's balance.
Use Case: Apply -10 points when any chore becomes overdue.
alias: "Penalty: Overdue Chore (-10 Points)"
description: "Deduct 10 points when chore becomes overdue"
triggers:
# Trigger when chore state changes to Overdue
- trigger: state
entity_id:
- sensor.sarah_kidschores_chore_make_bed_state # ⚠️ Replace with your chore state sensors
- sensor.sarah_kidschores_chore_homework_state
- sensor.sarah_kidschores_chore_dishes_state
- sensor.alex_kidschores_chore_feed_dog_state
- sensor.alex_kidschores_chore_clean_room_state
to: "Overdue"
conditions: []
actions:
# Extract kid name and chore name from entity ID
- variables:
entity_parts: "{{ trigger.entity_id.split('_') }}"
kid_name: "{{ entity_parts[1] | title }}" # kc_sarah_chore... → Sarah
chore_name: >-
{% set parts = trigger.entity_id.split('_chore_')[1].split('_state')[0].split('_') %}
{{ parts | join(' ') | title }} # make_bed_state → Make Bed
# Apply fixed penalty
- action: kidschores.apply_penalty
data:
kid_name: "{{ kid_name }}"
amount: 10 # ⚠️ Adjust penalty amount
reason: "Overdue: {{ chore_name }}"
# Optional: Notify kid
- action: notify.mobile_app_{{ kid_name.lower() }}_phone # ⚠️ Replace with your notify service
data:
title: "⏰ Chore Overdue"
message: >-
{{ chore_name }} is overdue!
Penalty: -10 points
New balance: {{ states('sensor.kc_' ~ kid_name.lower() ~ '_points') }} points
mode: queued # Allow multiple simultaneous penalties
max: 10| Parameter | What to Change | Example |
|---|---|---|
entity_id (triggers) |
Chore state sensors to monitor | sensor.sarah_kidschores_chore_homework_state |
amount |
Penalty points (fixed value) |
10 (or 5, 20, etc.) |
| Notify service | Your notification integration | notify.mobile_app_sarah_phone |
- Developer Tools → States
-
Search:
sensor.kc_(all KidsChores sensors) -
Filter:
_state(state sensors only) -
Identify: Match chore names to entity IDs
- Example: "Homework" →
sensor.sarah_kidschores_chore_homework_state
- Example: "Homework" →
Use Case: Apply penalty proportional to chore points (20% of original points).
Fixed Penalty Issues:
- -10 points harsh for low-value chore (5 points)
- -10 points trivial for high-value chore (50 points)
Proportional Benefits:
- Fair scaling (20% loss regardless of chore value)
- Matches chore importance
alias: "Penalty: Overdue Chore (20% of Points)"
description: "Deduct 20% of chore points when overdue"
triggers:
- trigger: state
entity_id:
- sensor.sarah_kidschores_chore_make_bed_state
- sensor.sarah_kidschores_chore_homework_state
- sensor.sarah_kidschores_chore_dishes_state
to: "Overdue"
conditions: []
actions:
- variables:
entity_parts: "{{ trigger.entity_id.split('_') }}"
kid_name: "{{ entity_parts[1] | title }}"
chore_name: >-
{% set parts = trigger.entity_id.split('_chore_')[1].split('_state')[0].split('_') %}
{{ parts | join(' ') | title }}
# Get chore points from points sensor
chore_points_sensor: >-
sensor.kc_{{ kid_name.lower() }}_chore_{{ chore_name.lower().replace(' ', '_') }}_points
chore_points: "{{ states(chore_points_sensor) | int(0) }}"
# Calculate 20% penalty (minimum 1 point)
penalty_amount: "{{ [1, (chore_points * 0.2) | round(0) | int] | max }}"
# Apply proportional penalty
- action: kidschores.apply_penalty
data:
kid_name: "{{ kid_name }}"
amount: "{{ penalty_amount }}"
reason: "Overdue: {{ chore_name }} (-{{ penalty_amount }} of {{ chore_points }} points)"
# Notify with penalty breakdown
- action: notify.mobile_app_{{ kid_name.lower() }}_phone
data:
title: "⏰ Chore Overdue"
message: >-
{{ chore_name }} is overdue!
Chore value: {{ chore_points }} points
Penalty (20%): -{{ penalty_amount }} points
New balance: {{ states('sensor.kc_' ~ kid_name.lower() ~ '_points') }} points
mode: queued
max: 10# Step 1: Get chore points
chore_points: "{{ states('sensor.sarah_chore_homework_kidschores_points') | int(0) }}"
# Example: 25 points
# Step 2: Calculate 20%
penalty_raw: "{{ chore_points * 0.2 }}"
# Example: 25 * 0.2 = 5.0
# Step 3: Round to integer
penalty_rounded: "{{ penalty_raw | round(0) | int }}"
# Example: 5
# Step 4: Ensure minimum 1 point (avoid 0 penalty)
penalty_amount: "{{ [1, penalty_rounded] | max }}"
# Example: max(1, 5) = 5Use Case: Give kid 30-minute grace period after due date before applying penalty. Accounts for minor timing issues or clock sync delays.
Without Grace:
- Due at 6:00 PM, kid completes at 6:02 PM → penalty applied
- Harsh for minor delays
- Discourages near-completion attempts
With Grace:
- Due at 6:00 PM, penalty at 6:30 PM
- Kid has buffer to finish
- Reduces frustration
alias: "Penalty: Overdue Chore with Grace Period"
description: "Wait 30 minutes after overdue before applying penalty"
triggers:
- trigger: state
entity_id:
- sensor.sarah_kidschores_chore_homework_state
- sensor.sarah_kidschores_chore_dishes_state
to: "Overdue"
conditions: []
actions:
- variables:
entity_parts: "{{ trigger.entity_id.split('_') }}"
kid_name: "{{ entity_parts[1] | title }}"
chore_name: >-
{% set parts = trigger.entity_id.split('_chore_')[1].split('_state')[0].split('_') %}
{{ parts | join(' ') | title }}
# Grace period notification (warning)
- action: notify.mobile_app_{{ kid_name.lower() }}_phone
data:
title: "⚠️ Chore Overdue - Grace Period"
message: >-
{{ chore_name }} is overdue!
You have 30 minutes to complete before penalty (-10 points).
# Wait 30 minutes
- delay:
minutes: 30 # ⚠️ Adjust grace period
# Check if still overdue (kid might have completed during grace period)
- if:
- condition: state
entity_id: "{{ trigger.entity_id }}"
state: "Overdue"
then:
# Apply penalty (still overdue)
- action: kidschores.apply_penalty
data:
kid_name: "{{ kid_name }}"
amount: 10
reason: "Overdue after grace period: {{ chore_name }}"
# Final penalty notification
- action: notify.mobile_app_{{ kid_name.lower() }}_phone
data:
title: "❌ Penalty Applied"
message: >-
{{ chore_name }} penalty: -10 points
Complete chore to prevent future penalties.
New balance: {{ states('sensor.kc_' ~ kid_name.lower() ~ '_points') }}
else:
# Kid completed during grace period (no penalty)
- action: notify.mobile_app_{{ kid_name.lower() }}_phone
data:
title: "✅ Penalty Avoided"
message: >-
{{ chore_name }} completed during grace period!
No penalty applied. Great job!
mode: queued
max: 5| Grace Period | Best For | Avoid For |
|---|---|---|
| 5-15 min | Time-sensitive chores (bedtime, school prep) | Daily routine tasks |
| 30-60 min | Standard chores (homework, cleaning) | Multi-day projects |
| 2-4 hours | Flexible chores (lawn mowing, car washing) | Recurring high-frequency tasks |
Use Case: Increase penalty for each day chore remains overdue. Motivates prompt correction.
- Day 1: -5 points (gentle reminder)
- Day 2: -10 points (moderate consequence)
- Day 3+: -20 points/day (serious consequence)
alias: "Penalty: Escalating Daily for Overdue Chores"
description: "Increase penalty each day chore remains overdue"
triggers:
- trigger: time
at: "09:00:00" # Check daily at 9 AM
conditions:
# At least one overdue chore exists
- condition: numeric_state
entity_id: sensor.sarah_overdue_kidschores_chores_count
above: 0
actions:
# Check each chore's overdue duration
- repeat:
for_each:
- sensor.sarah_kidschores_chore_homework_state
- sensor.sarah_kidschores_chore_dishes_state
- sensor.sarah_kidschores_chore_clean_room_state
sequence:
- if:
- condition: state
entity_id: "{{ repeat.item }}"
state: "Overdue"
then:
- variables:
chore_name: >-
{% set parts = repeat.item.split('_chore_')[1].split('_state')[0].split('_') %}
{{ parts | join(' ') | title }}
due_date_sensor: >-
sensor.sarah_kidschores_chore_{{ chore_name.lower().replace(' ', '_') }}_due_date
days_overdue: >-
{% set due = states(due_date_sensor) | as_datetime %}
{% if due %}
{{ (now() - due).days }}
{% else %}
0
{% endif %}
# Escalating penalty calculation
penalty_amount: >-
{% if days_overdue == 1 %}
5
{% elif days_overdue == 2 %}
10
{% else %}
20
{% endif %}
# Apply escalating penalty
- action: kidschores.apply_penalty
data:
kid_name: "Sarah"
amount: "{{ penalty_amount }}"
reason: "Day {{ days_overdue }} overdue: {{ chore_name }}"
# Escalating notification
- action: notify.mobile_app_sarah_phone
data:
title: "⏰ Day {{ days_overdue }} Overdue"
message: >-
{{ chore_name }} penalty: -{{ penalty_amount }} points
{% if days_overdue >= 3 %}
⚠️ Penalty increases each day!
{% endif %}
New balance: {{ states('sensor.sarah_kidschores_points') }}
mode: singleFlat Penalty Problem:
- Kid might tolerate constant -10/day
- No motivation to complete quickly
Escalating Penalty Benefits:
- Creates urgency (penalty grows daily)
- Rewards prompt correction (lower penalty)
- Prevents chronic overdue chores
Use Case: Waive penalty for first overdue occurrence (per chore per week/month). Builds trust before enforcement.
alias: "Penalty: First Offense Forgiveness"
description: "Warn on first overdue, penalize on subsequent"
triggers:
- trigger: state
entity_id:
- sensor.sarah_kidschores_chore_homework_state
to: "Overdue"
conditions: []
actions:
- variables:
chore_name: "Homework" # ⚠️ Hardcoded for clarity (can extract from entity ID)
kid_name: "Sarah"
# Check penalty counter (requires input_number helper)
penalty_counter: input_number.sarah_homework_penalty_kidschores_count
offenses_this_week: "{{ states(penalty_counter) | int(0) }}"
- choose:
# First offense: Warning only
- conditions:
- condition: template
value_template: "{{ offenses_this_week == 0 }}"
sequence:
# Increment counter
- action: input_number.set_value
target:
entity_id: "{{ penalty_counter }}"
data:
value: 1
# Warning notification
- action: notify.mobile_app_sarah_phone
data:
title: "⚠️ First Overdue Warning"
message: >-
{{ chore_name }} is overdue.
This is your first offense this week - no penalty.
Next overdue will result in -10 points.
# Subsequent offenses: Apply penalty
- conditions:
- condition: template
value_template: "{{ offenses_this_week > 0 }}"
sequence:
# Increment counter
- action: input_number.set_value
target:
entity_id: "{{ penalty_counter }}"
data:
value: "{{ offenses_this_week + 1 }}"
# Apply penalty
- action: kidschores.apply_penalty
data:
kid_name: "Sarah"
amount: 10
reason: "Repeat overdue: {{ chore_name }} (offense {{ offenses_this_week + 1 }})"
# Penalty notification
- action: notify.mobile_app_sarah_phone
data:
title: "❌ Penalty Applied"
message: >-
{{ chore_name }} penalty: -10 points
(Offense {{ offenses_this_week + 1 }} this week)
New balance: {{ states('sensor.sarah_kidschores_points') }}
mode: singleCreate Input Number Helper (one per kid-chore pair):
- Settings → Devices & Services → Helpers
- Add Helper → Number
-
Configuration:
- Name:
KidsChores Sarah Homework Penalty Count - Entity ID:
input_number.sarah_homework_penalty_kidschores_count - Minimum:
0 - Maximum:
100 - Step:
1 - Display mode:
box
- Name:
Reset Counter Weekly:
alias: "Reset: Weekly Penalty Counters"
triggers:
- trigger: time
at: "00:00:00"
weekday: mon # Reset every Monday
actions:
- action: input_number.set_value
target:
entity_id:
- input_number.sarah_homework_penalty_kidschores_count
- input_number.sarah_dishes_penalty_kidschores_count
data:
value: 0
mode: singlePotential Causes:
- Chore not actually overdue (check due date)
- Kid name mismatch (capitalization matters)
- Automation disabled or not triggering
Debugging Steps:
-
Verify Overdue State:
- Developer Tools → States
- Find
sensor.sarah_kidschores_chore_homework_state - Confirm state =
"Overdue"(not "Claimed" or "Approved")
-
Test Service Manually:
# Developer Tools → Services action: kidschores.apply_penalty data: kid_name: "Sarah" amount: 10 reason: "Test penalty"
- If fails → kid name incorrect or service unavailable
- If succeeds → automation trigger issue
-
Check Automation Traces:
- Settings → Automations & Scenes → Select automation
- Click "Traces" → View last run
- Verify trigger fired when state changed to "Overdue"
Cause: Automation triggering on every state evaluation (not just change to Overdue).
Solution: Add from condition to ensure trigger only on change:
triggers:
- trigger: state
entity_id: sensor.sarah_kidschores_chore_homework_state
to: "Overdue"
from: # ⚠️ Add this
- "Pending"
- "Claimed"Cause: Delay not waiting long enough or automation restarting.
Solution: Change mode to single (prevents restarts):
mode: single # Completes full sequence before retriggeringCause: Notify service entity ID incorrect or service unavailable.
Debugging Steps:
-
Test Notification Manually:
action: notify.mobile_app_sarah_phone data: message: "Test notification"
-
Check Notify Service Name:
- Developer Tools → Services
- Search
notify. - Find correct service name (varies by mobile app)
Fair and Predictable:
- ✅ Clearly communicate penalty rules to kids
- ✅ Apply consistently (no exceptions without reason)
- ✅ Start with small penalties (adjust based on behavior)
Avoid:
- ❌ Excessive penalties (demotivates)
- ❌ Retroactive penalties (kid didn't know rule)
- ❌ Penalty without warning (surprise punishments)
| Chore Value | Recommended Penalty | Reasoning |
|---|---|---|
| 5-10 pts | -2 to -5 points | ~50% loss (significant but fair) |
| 15-25 pts | -5 to -10 points | ~33% loss (motivating) |
| 30-50 pts | -10 to -20 points | ~25% loss (serious consequence) |
| 50+ pts | -20 to -30 points | ~33% loss (scales with importance) |
General Rule: Penalty = 20-50% of chore value
Punishment vs Reinforcement:
- Penalties alone: Discouraging, focus on negative
- Rewards alone: No consequences for failure
- Balanced approach: Penalties for overdue + bonuses for on-time
Positive Reinforcement Automation:
alias: "Bonus: On-Time Completion"
description: "Award bonus points for completing before due date"
triggers:
- trigger: state
entity_id: sensor.sarah_kidschores_chore_homework_state
to: "Approved"
conditions:
# Approved before due date
- condition: template
value_template: >-
{% set due = states('sensor.sarah_kidschores_chore_homework_due_date') | as_datetime %}
{{ due and now() < due }}
actions:
- action: kidschores.apply_bonus
data:
kid_name: "Sarah"
amount: 5 # Bonus for early completion
reason: "On-time: Homework"Transparency:
- Show kids penalty automation in dashboard
- Explain logic (due date → overdue → penalty)
- Review penalty history weekly
Dashboard Card:
type: markdown
content: >-
## Overdue Penalty Rules
- **Grace Period**: 30 minutes after due date
- **First Penalty**: -10 points
- **Daily Increase**: +5 points/day
- **Maximum**: -20 points/day
Complete chores on time to avoid penalties!Shared Chores:
- Penalty applies to kid whose instance is overdue
- Other kids unaffected (Independent tracking)
Shared First:
- Penalty only applies if NO kid completes (entire chore overdue)
- Individual kid penalties inappropriate (race mechanic)
Multi-Approval:
- Each kid has separate due date (can be different)
- Penalty applies per kid independently
kidschores.reset_overdue_chores Service:
- Resets chore to Pending/Claimed (depending on criteria)
- Does NOT reverse penalties already applied
- Use case: Manual forgiveness after discussion
Penalty After Reset:
# Reset chore to Pending (parent forgives overdue)
- action: kidschores.reset_overdue_chores
data:
chore_name: "Homework"
kid_name: "Sarah"
# Optionally refund penalty (manual bonus)
- action: kidschores.apply_bonus
data:
kid_name: "Sarah"
amount: 10 # Refund previous penalty
reason: "Forgiven: Homework overdue reset"Negative Balance Prevention:
# Check balance before applying penalty
conditions:
- condition: template
value_template: >-
{{ states('sensor.sarah_kidschores_points') | int > 10 }}
# Only penalize if balance > penalty amount
actions:
- action: kidschores.apply_penalty
data:
kid_name: "Sarah"
amount: 10Why Prevent Negative:
- Negative balance demotivates ("I can never recover")
- Creates debt mentality
- Consider minimum balance (e.g., 0 points floor)
-
Services Reference -
apply_penalty,reset_overdue_choresservice documentation - Configuration: Points System - Points balance, bonuses, penalties
- Chore Status and Recurrence Handling - Overdue state logic