From a5ee4ca735986e43aa6fc8b6e4e562ad4eb6dbb4 Mon Sep 17 00:00:00 2001 From: Chuck <33324927+ChuckBuilds@users.noreply.github.com> Date: Wed, 2 Sep 2026 21:50:25 -0400 Subject: [PATCH] docs(pomodoro-timer): give every setting its config.json key The README documented all 46 settings by their web-UI label only -- "Font", "Burndown Indicator", "How Paused Looks" -- so none of the JSON keys appeared anywhere. Anyone editing config/config.json directly, or reading a key back out of a log line, had no way to map one to the other. Every table now carries the key beside the label. Two claims corrected while checking them against the core's config template: "enabled" is the toggle in the tab header, not a field in the form, and the advanced settings are grouped into a collapsed "Advanced Settings" section rather than hidden behind a toggle. The plugin was also missing from the root README's plugin listing entirely, so it gains a Productivity section. update_readme_previews.py now looks for a plugin-local assets/hero.png as well as docs/assets//hero.png, since this plugin ships its own renderer and keeps its images beside the plugin. No functional change; check_plugin.py passes 8/8 with all four goldens matching. Co-Authored-By: Claude Opus 5 --- README.md | 6 ++ plugins.json | 4 +- plugins/pomodoro-timer/README.md | 117 ++++++++++++++++----------- plugins/pomodoro-timer/manifest.json | 10 ++- scripts/update_readme_previews.py | 25 +++++- 5 files changed, 109 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 9fae8532..4f11209a 100644 --- a/README.md +++ b/README.md @@ -145,6 +145,12 @@ curl -X POST http://your-pi-ip:5000/api/v3/plugins/install \ | [MQTT Notifications](./plugins/mqtt-notifications/) | HomeAssistant notifications via MQTT | | | [On Air Light](./plugins/on-air/) | Broadcast ON AIR tally light, triggered remotely via MQTT / Home Assistant | | +### Productivity (1) + +| Plugin | Description | Preview | +|--------|-------------|---------| +| [Pomodoro Timer](./plugins/pomodoro-timer/) | Focus/break timer with MQTT control and Home Assistant discovery | pomodoro-timer on an LED panel | + ### Custom (3) | Plugin | Description | Preview | diff --git a/plugins.json b/plugins.json index f900d57c..7fddaac5 100644 --- a/plugins.json +++ b/plugins.json @@ -1165,10 +1165,10 @@ "plugin_path": "plugins/pomodoro-timer", "stars": 0, "downloads": 0, - "last_updated": "2026-07-29", + "last_updated": "2026-09-02", "verified": true, "screenshot": "", - "latest_version": "1.3.4", + "latest_version": "1.3.5", "icon": "fa-hourglass-half" } ] diff --git a/plugins/pomodoro-timer/README.md b/plugins/pomodoro-timer/README.md index 9d5a0a14..5566e3f2 100644 --- a/plugins/pomodoro-timer/README.md +++ b/plugins/pomodoro-timer/README.md @@ -153,62 +153,89 @@ durations you configured. ## Plugin Configuration +Settings are edited in the plugin's tab in the LEDMatrix web UI. The **Field** +column is the label you see there; the **Key** is the same setting as it appears +in `config/config.json` under `pomodoro-timer`, which is what you need if you +edit the file directly or read it back in a log line. The full schema is +[`config_schema.json`](config_schema.json). + ### Timer -| Field | Default | Description | -|---|---|---| -| **Work Session (minutes)** | `25` | Length of a focus session. Also settable live from Home Assistant. | -| **Short Break (minutes)** | `5` | Break after each work session. | -| **Long Break (minutes)** | `15` | Break after a full set of work sessions. | -| **Sessions Before Long Break** | `4` | How many work sessions make a set — this is the number of dots on screen. | -| **Auto-Start Breaks** | `true` | Roll straight into the break when work ends. Off makes the break wait for a Start/Resume. | -| **Auto-Start Next Work Session** | `false` | Roll straight back into work when a break ends. Off by default so you decide when to go again. | -| **Start Timer When Plugin Is Enabled** | `false` | Begin a work session as soon as the plugin loads. Handy without MQTT. | +| Field | Key | Default | Description | +|---|---|---|---| +| *(header toggle)* | `enabled` | `true` | Master switch. It is the toggle in the tab's header rather than a field in the form. Off removes the timer from the rotation entirely. | +| **Work Session (minutes)** | `work_minutes` | `25` | Length of a focus session (1–180). Also settable live from Home Assistant. | +| **Short Break (minutes)** | `short_break_minutes` | `5` | Break after each work session (1–60). | +| **Long Break (minutes)** | `long_break_minutes` | `15` | Break after a full set of work sessions (1–120). | +| **Sessions Before Long Break** | `sessions_before_long_break` | `4` | How many work sessions make a set (1–12) — this is the number of dots on screen. | +| **Auto-Start Breaks** | `auto_start_breaks` | `true` | Roll straight into the break when work ends. Off makes the break wait for a Start/Resume. | +| **Auto-Start Next Work Session** | `auto_start_work` | `false` | Roll straight back into work when a break ends. Off by default so you decide when to go again. | +| **Start Timer When Plugin Is Enabled** | `auto_start_on_enable` | `false` | Begin a work session as soon as the plugin loads. Handy without MQTT. | ### MQTT -| Field | Default | Description | -|---|---|---| -| **Enable MQTT Control** | `true` | Connect to a broker so the timer can be driven remotely. | -| **Broker Address** | `localhost` | IP or hostname of your MQTT broker. | -| **Broker Port** | `1883` | Use 8883 for TLS. | -| **Username / Password** | *(blank)* | Leave blank for an anonymous broker. | -| **Command Topic** | `ledmatrix/pomodoro/set` | Everything the plugin publishes is derived from this topic's base. | -| **State Topic** | `ledmatrix/pomodoro/state` | `ON` while a session is active, `OFF` when idle. | -| **Enable Home Assistant Auto-Discovery** | `true` | Announce the device to HA over MQTT. | -| **HA Discovery Prefix** | `homeassistant` | Only change this if you changed it in HA. | -| **Device Name in Home Assistant** | `LED Matrix — Pomodoro` | How the device is labelled in HA. | -| **State Publish Interval (seconds)** | `1` | How often the countdown is published while running. Raise it to cut broker traffic — state *changes* are always published immediately. | +| Field | Key | Default | Description | +|---|---|---|---| +| **Enable MQTT Control** | `mqtt_enabled` | `true` | Connect to a broker so the timer can be driven remotely. | +| **Broker Address** | `mqtt_host` | `localhost` | IP or hostname of your MQTT broker. | +| **Broker Port** | `mqtt_port` | `1883` | Use 8883 for TLS. | +| **Username / Password** | `mqtt_username`
`mqtt_password` | *(blank)* | Leave blank for an anonymous broker. The password is marked secret, so the web UI masks it. | +| **Command Topic** | `command_topic` | `ledmatrix/pomodoro/set` | Everything the plugin publishes is derived from this topic's base. | +| **State Topic** | `state_topic` | `ledmatrix/pomodoro/state` | `ON` while a session is active, `OFF` when idle. | +| **Enable Home Assistant Auto-Discovery** | `ha_discovery` | `true` | Announce the device to HA over MQTT. | +| **HA Discovery Prefix** | `discovery_prefix` | `homeassistant` | Only change this if you changed it in HA. | +| **Device Name in Home Assistant** | `device_name` | `LED Matrix — Pomodoro` | How the device is labelled in HA. | +| **State Publish Interval (seconds)** | `publish_interval_seconds` | `1` | How often the countdown is published while running (1–60). Raise it to cut broker traffic — state *changes* are always published immediately. | ### Appearance -| Field | Default | Description | -|---|---|---| -| **Countdown Color** | `phase` | `phase` colors the countdown by what's running; `fixed` always uses the Countdown Text Color. | -| **Colour Theme** | `classic` | `classic` uses the individual phase colours below. `calm` overrides them with a softer palette — warm terracotta, sage, soft indigo. | -| **Work / Short Break / Long Break Color** | red / green / blue | Phase colors. | -| **Idle / Paused Color** | grey / amber | Used when nothing is running and when paused. | -| **How Paused Looks** | `amber` | `amber` switches the countdown to the Paused Colour. `desaturate` keeps the phase's own hue but drains it, so a held timer reads as halted without changing which phase you're in. | -| **Countdown Text Color** | white | Only used when Countdown Color is `fixed`. | -| **Background Color** | black | Panel background. | -| **Countdown Digits** | `seven_segment` | `seven_segment` draws clock-radio style segments sized to the panel. `pixel` uses the display's pixel font. | -| **Show Unlit Segments** | `false` | Faintly light the unlit segments, like a real LED clock. Authentic, but it costs legibility — every digit gains a faint `8` behind it. Ignored when the stroke is only one pixel wide, where the effect would just be noise. | -| **Burndown Indicator** | `perimeter` | `perimeter` drains a ring around the edge of the panel; `bar` empties a bar along the bottom; `segments` puts out a row of blocks one at a time; `none` hides it. | -| **Show Phase Label** | `true` | The phase name above the countdown. | -| **Show Session Dots** | `true` | One pip per session in the set. Completed are solid, upcoming are hollow, and the one you're in is picked out. | -| **Pulse the Current Session Dot** | `true` | Slowly blink the pip for the session you're in, so the row reads as "two done, on the third" rather than just a count. | -| **Work / Short Break / Long Break / Idle / Paused Label** | `FOCUS` / `BREAK` / `LONG BREAK` / `POMODORO` / `PAUSED` | The on-screen text for each state. Blank the Paused Label to keep showing the phase name while paused. | -| **Font** | *(blank)* | Path to a TTF relative to the LEDMatrix root, e.g. `assets/fonts/PressStart2P-Regular.ttf`. Blank uses the display's default font. | -| **Font Size (px)** | `0` | Fix the countdown height in pixels. `0` sizes it automatically to the panel. | +| Field | Key | Default | Description | +|---|---|---|---| +| **Countdown Color** | `color_mode` | `phase` | `phase` colors the countdown by what's running; `fixed` always uses the Countdown Text Color. | +| **Colour Theme** | `color_theme` | `classic` | `classic` uses the individual phase colours below. `calm` overrides them with a softer palette — warm terracotta, sage, soft indigo. | +| **Work / Short Break / Long Break Color** | `work_color`
`short_break_color`
`long_break_color` | red / green / blue | Phase colors, each `[r, g, b]`. | +| **Idle / Paused Color** | `idle_color`
`paused_color` | grey / amber | Used when nothing is running and when paused. | +| **How Paused Looks** | `paused_style` | `amber` | `amber` switches the countdown to the Paused Colour. `desaturate` keeps the phase's own hue but drains it, so a held timer reads as halted without changing which phase you're in. | +| **Countdown Text Color** | `time_color` | white | Only used when Countdown Color is `fixed`. | +| **Background Color** | `background_color` | black | Panel background. | +| **Countdown Digits** | `digit_style` | `seven_segment` | `seven_segment` draws clock-radio style segments sized to the panel. `pixel` uses the display's pixel font. | +| **Show Unlit Segments** | `show_ghost_segments` | `false` | Faintly light the unlit segments, like a real LED clock. Authentic, but it costs legibility — every digit gains a faint `8` behind it. Ignored when the stroke is only one pixel wide, where the effect would just be noise. | +| **Burndown Indicator** | `progress_style` | `perimeter` | `perimeter` drains a ring around the edge of the panel; `bar` empties a bar along the bottom; `segments` puts out a row of blocks one at a time; `none` hides it. | +| **Show Phase Label** | `show_phase_label` | `true` | The phase name above the countdown. | +| **Show Session Dots** | `show_session_dots` | `true` | One pip per session in the set. Completed are solid, upcoming are hollow, and the one you're in is picked out. | +| **Pulse the Current Session Dot** | `pulse_active_pip` | `true` | Slowly blink the pip for the session you're in, so the row reads as "two done, on the third" rather than just a count. | +| **Work / Short Break / Long Break / Idle / Paused Label** | `work_label`
`short_break_label`
`long_break_label`
`idle_label`
`paused_label` | `FOCUS` / `BREAK` / `LONG BREAK` / `POMODORO` / `PAUSED` | The on-screen text for each state, up to 24 characters. Blank the Paused Label to keep showing the phase name while paused. | +| **Font** | `font_path` | *(blank)* | Path to a TTF relative to the LEDMatrix root, e.g. `assets/fonts/PressStart2P-Regular.ttf`. Blank uses the display's default font. | +| **Font Size (px)** | `font_size` | `0` | Fix the countdown height in pixels. `0` sizes it automatically to the panel. | ### Behavior -| Field | Default | Description | -|---|---|---| -| **Hold the Display While Running** | `true` | Take over the matrix while a session is active instead of rotating. Off lets the timer take a normal turn in the rotation. | -| **Phase-Change Alert (seconds)** | `8` | How long the timer grabs the display when a phase ends. `0` disables it. | -| **Flash on Phase Change** | `true` | Flash the panel during that alert. | -| **Display Duration (seconds)** | `10` | Time on screen per rotation cycle when it isn't holding the display. | +| Field | Key | Default | Description | +|---|---|---|---| +| **Hold the Display While Running** | `pin_while_running` | `true` | Take over the matrix while a session is active instead of rotating. Off lets the timer take a normal turn in the rotation. | +| **Phase-Change Alert (seconds)** | `alert_seconds` | `8` | How long the timer grabs the display when a phase ends. `0` disables it. | +| **Flash on Phase Change** | `alert_flash` | `true` | Flash the panel during that alert. | +| **Display Duration (seconds)** | `display_duration` | `10` | Time on screen per rotation cycle when it isn't holding the display. | + +Fine-tuning settings are collected into a collapsed **Advanced Settings** +section below the main fields in the web UI. They are listed above alongside +everything else. + +### A minimal configuration + +```json +{ + "pomodoro-timer": { + "enabled": true, + "work_minutes": 25, + "short_break_minutes": 5, + "long_break_minutes": 15, + "sessions_before_long_break": 4, + "mqtt_enabled": true, + "mqtt_host": "homeassistant.local" + } +} +``` --- diff --git a/plugins/pomodoro-timer/manifest.json b/plugins/pomodoro-timer/manifest.json index 1a58c1ec..3db444b7 100644 --- a/plugins/pomodoro-timer/manifest.json +++ b/plugins/pomodoro-timer/manifest.json @@ -1,7 +1,7 @@ { "id": "pomodoro-timer", "name": "Pomodoro Timer", - "version": "1.3.4", + "version": "1.3.5", "author": "ChuckBuilds", "description": "A configurable Pomodoro focus/break timer for your matrix. Set the work and break lengths, then start, pause, skip, or reset it over MQTT \u2014 with Home Assistant auto-discovery so the whole timer shows up as a device with no YAML.", "entry_point": "manager.py", @@ -22,6 +22,12 @@ ">=2.0.0" ], "versions": [ + { + "released": "2026-09-02", + "version": "1.3.5", + "notes": "Documentation. Every setting in the README now carries its config.json key alongside the web-UI label, so the tables can be used when editing the file directly rather than only when clicking through the form; all 46 schema properties are covered. Corrects two claims: 'enabled' is the tab's header toggle rather than a form field, and the advanced settings appear in a collapsed 'Advanced Settings' section. No functional change.", + "ledmatrix_min_version": "2.0.0" + }, { "released": "2026-08-15", "version": "1.3.4", @@ -88,7 +94,7 @@ "license": "GPL-3.0", "homepage": "https://github.com/ChuckBuilds/ledmatrix-plugins/tree/main/plugins/pomodoro-timer", "config_schema": "config_schema.json", - "last_updated": "2026-07-29", + "last_updated": "2026-09-02", "stars": 0, "downloads": 0, "verified": true, diff --git a/scripts/update_readme_previews.py b/scripts/update_readme_previews.py index 2893b2b9..c30ed356 100644 --- a/scripts/update_readme_previews.py +++ b/scripts/update_readme_previews.py @@ -4,7 +4,8 @@ The "Available Plugins" tables in ``README.md`` carry a thumbnail of each plugin's hero screenshot. This script rewrites that column from what is actually on disk: a plugin gets a thumbnail once -``docs/assets//hero.png`` exists, and an empty cell until then. +``docs/assets//hero.png`` (or ``plugins//assets/hero.png``, +for plugins that ship their own renderer) exists, and an empty cell until then. Run it after adding a plugin's README screenshots:: @@ -40,14 +41,30 @@ SEPARATOR = "|--------|-------------|---------|" +def hero_path(plugin_id: str) -> str | None: + """Where this plugin's hero image lives, as a repo-relative URL. + + Most plugins render theirs into ``docs/assets//``. A few carry their own + renderer and keep the image beside the plugin, so look there too rather than + leaving those rows blank. + """ + shared = ASSETS_ROOT / plugin_id / "hero.png" + if shared.is_file(): + return f"./docs/assets/{plugin_id}/hero.png" + local = REPO_ROOT / "plugins" / plugin_id / "assets" / "hero.png" + if local.is_file(): + return f"./plugins/{plugin_id}/assets/hero.png" + return None + + def preview_cell(plugin_id: str) -> str: """The Preview cell for one plugin: a thumbnail, or empty if none yet.""" - hero = ASSETS_ROOT / plugin_id / "hero.png" - if not hero.is_file(): + hero = hero_path(plugin_id) + if hero is None: return " " return ( f' ' - f'{plugin_id} on an LED panel ' )