Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 65 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
- [Chores & Rewards](#chores--rewards)
- [Chore Scheduling](#chore-scheduling)
- [Bonus Points System](#bonus-points-system)
- [Penalties](#penalties)
- [Dashboard Cards](#dashboard-cards)
- [Services](#services)
- [Completion Sounds](#completion-sounds)
Expand Down Expand Up @@ -243,6 +244,48 @@ Leave empty to use persistent notifications only.

---

## Penalties

Deduct points from a child for unwanted behaviour — the flip side of the reward system.

### How It Works

1. Create named penalties (e.g. "Not going to bed = 10 points") via the **Penalties Card** or the `taskmate.add_penalty` service
2. Open the Penalties Card, select the child, and tap **Apply** on the relevant penalty
3. Points are deducted immediately and logged in the activity feed as `Penalty: <name>`

### Penalties Card

```yaml
type: custom:taskmate-penalties-card
entity: sensor.taskmate_overview
title: Penalties # optional
```

- Select the child using the tabs at the top (hidden if only one child)
- Tap **Apply** to deduct points instantly — the tile flashes and a toast confirms the action
- Tap the **pencil icon** to enter edit mode: add new penalties, edit name/points/icon/description, or delete

### Managing Penalties via Services

```yaml
# Create a penalty
service: taskmate.add_penalty
data:
name: "Not going to bed"
points: 10
description: "Refused bedtime after two warnings" # optional
icon: mdi:bed-clock # optional, any MDI icon

# Apply a penalty to a child
service: taskmate.apply_penalty
data:
penalty_id: abc12345 # see Finding IDs
child_id: a8c8376a
```

---

## Dashboard Cards

> **Header colours:** Every card has a configurable `header_color` option in the visual editor, with its own vibrant default. Change it to match your dashboard theme or differentiate kid vs parent cards.
Expand All @@ -264,6 +307,7 @@ Leave empty to use persistent notifications only.
| [Points Graph Card](#points-graph-card) | Parents | Points over time, multi-child line graph |
| [Reward Progress Card](#reward-progress-card) | Kids | Full-screen motivational reward display |
| [Leaderboard Card](#leaderboard-card) | Both | Competitive ranking by points, streak, or weekly |
| [Penalties Card](#penalties-card) | Parents | Apply point-deduction penalties |

---

Expand Down Expand Up @@ -513,9 +557,22 @@ show_streak: true
show_weekly: true
header_color: "#b7950b"
```

---


### Penalties Card

Parent-facing card for applying point-deduction penalties. Select the child using tabs, then tap **Apply** next to the relevant penalty. Tap the pencil icon to add, edit, or delete penalty definitions.

```yaml
type: custom:taskmate-penalties-card
entity: sensor.taskmate_overview
title: Penalties
header_color: "#e74c3c"
```

---

## Services

TaskMate exposes services you can call from automations, scripts, or Developer Tools.
Expand All @@ -531,6 +588,12 @@ TaskMate exposes services you can call from automations, scripts, or Developer T
| `taskmate.add_points` | `child_id`, `points`, `reason` | Manually add points to a child |
| `taskmate.remove_points` | `child_id`, `points`, `reason` | Manually remove points from a child |
| `taskmate.set_chore_order` | `child_id`, `chore_order` | Set the chore display order for a child |
| `taskmate.add_penalty` | `name`, `points`, `description`\*, `icon`\* | Create a new penalty definition |
| `taskmate.update_penalty` | `penalty_id`, `name`\*, `points`\*, `description`\*, `icon`\* | Update an existing penalty |
| `taskmate.remove_penalty` | `penalty_id` | Delete a penalty definition |
| `taskmate.apply_penalty` | `penalty_id`, `child_id` | Apply a penalty — deducts points immediately |

\* optional

**Example — award bonus points from an automation:**

Expand Down
56 changes: 56 additions & 0 deletions RELEASE_NOTES_v2.1.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# TaskMate v2.1.0

## What's New

### Penalty System

The flip side of rewards — deduct points for unwanted behaviour without having to guess an amount each time.

Create named penalties (e.g. **"Not going to bed"**, **"Too much screen time"**, **"Talking back"**) with a fixed point deduction, then apply them to a child with a single tap. The deduction is logged in the activity feed so you always have a record.

**New `taskmate-penalties-card`**

- Child selector tabs at the top (hidden when there's only one child)
- Each penalty shows its icon, name, and point cost in a red badge
- Tap **Apply** → points deducted instantly, tile flashes red, toast confirms the action
- Toggle **edit mode** (pencil icon) to add, rename, or delete penalties

**4 new services for automation / scripting**

| Service | Description |
|---------|-------------|
| `taskmate.add_penalty` | Create a new penalty definition |
| `taskmate.update_penalty` | Update an existing penalty's name, points, or icon |
| `taskmate.remove_penalty` | Delete a penalty definition |
| `taskmate.apply_penalty` | Apply a penalty to a child (deducts points immediately) |

Example:

```yaml
service: taskmate.apply_penalty
data:
penalty_id: abc12345
child_id: a8c8376a
```

---

## Bug Fixes

- **Crash deleting a chore** — The config flow called a non-existent method (`async_delete_chore`) instead of the correct `async_remove_chore`. Deleting a chore from Settings now works correctly.

- **Crash when settings contain invalid values** — If a setting like `weekend_multiplier` or `perfect_week_bonus` was somehow saved as a non-numeric string, `float()`/`int()` would throw and take the entire sensor offline. These conversions now fall back to their defaults gracefully.

- **Crash in chore availability check** — `is_chore_available_for_child` caught `ValueError` when parsing a stored date string, but not `TypeError`. If the stored value was `None` or a non-string, slicing it raised an unhandled `TypeError`. Fixed to catch both.

- **Reward rejection bypassed storage API** — `async_reject_reward` was directly writing to `storage._data["reward_claims"]` instead of going through the storage layer. Added `remove_reward_claim()` to `TaskMateStorage` and updated the coordinator to use it.

- **Double dict lookup for child names** — A fragile `a and b or c` pattern was used to look up the same child dict key twice in the sensor. Replaced with a clean single lookup.

---

## Upgrade Notes

No migration needed. Penalties are stored in a new `penalties` key in the TaskMate data store — existing data is untouched.

After upgrading, hard-refresh your browser (**Cmd+Shift+R** / **Ctrl+Shift+R**) to load the new card JavaScript.
Loading