Skip to content
Open
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
6 changes: 4 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,11 @@ jobs:
# them via --with is the explicit, discovery-friendly form (a bare `pytest
# <dir>` doesn't honour a test file's own inline deps). `markdown` (a MkDocs
# dep, not in the base env) is needed by test_mkdocs_slug.py, which pins _slug()
# against Python-Markdown's real toc slugify.
# against Python-Markdown's real toc slugify. `wled` is the frenck/python-wled
# library HA's WLED integration uses; test_wled_json_shape.py parses the
# device /json vector through its Device.from_dict to pin the wire contract.
- name: pytest
run: uv run --with pytest --with pyserial --with markdown pytest test/python -q
run: uv run --with pytest --with pyserial --with markdown --with wled pytest test/python -q

js:
runs-on: ubuntu-latest
Expand Down
12 changes: 12 additions & 0 deletions docs/backlog/backlog-core.md
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,18 @@ with the [DevicesModule command half](#devicesmodule-interop-plugins-the-command

**Open question — Homebridge example maps both `setBrightness` and `setHSV`.** In `homebridge-mqttthing`'s `lightbulb`, HSV's *value* (V) already carries HomeKit's Brightness characteristic, so mapping both topic pairs may double-drive brightness (mqttthing's docs lean toward using one or the other). The [MQTT § Homebridge example](../moonmodules/core/services.md#mqtt) currently lists both, to show the device's full topic surface. Resolve on hardware: flash a board, run Homebridge + mqttthing with that config, and check whether the Home-app brightness slider misbehaves — if it does, drop the two `brightness` topics from the example; if not, it's a non-issue. (Flagged by CodeRabbit; parked here rather than changing the doc on an untested hunch.)

### HA update entity via MQTT discovery — release check (open follow-up)

**Discovery config + install command wiring — shipped.** [`MqttModule`](../../src/core/MqttModule.cpp) now publishes a second HA-discovery component at `homeassistant/update/projectMM_<mac6>/config` (same haDiscovery gate, same MAC-stable id, same device card as the light), state on `<prefix>/update/state`, and subscribes to `<prefix>/update/set`. HA renders a *"Firmware: <version>"* card in the diagnostic section of the device panel. An install command routes to `platform::http_fetch_to_ota` with the release-artifact URL built from the payload version + `kFirmwareName` (`https://github.com/MoonModules/projectMM/releases/download/v<version>/firmware-<key>-v<version>.bin`), reusing the same OTA task the `/api/firmware/url` route drives.

**Still to build — device-side release check.** `installed_version` and `latest_version` are equal today (both `MM_VERSION`), so HA renders the entity as up-to-date and the Install button is disabled. What's missing is a periodic poll of `https://api.github.com/repos/MoonModules/projectMM/releases/latest`: at boot (~30 s post-network-up) and every 24 h thereafter, fetch the release JSON, extract `tag_name`, and if newer than `MM_VERSION` call `MqttModule::publishUpdateState()` with the updated `latest_version` (the publish path is already there — only the caller is missing). ~2 KB per check.

Two blockers, both platform-layer:
- **`platform::http_fetch_to_ota` is OTA-shaped** — it writes bytes into the next OTA partition; there's no general "HTTPS GET into a buffer" seam. A small `platform::http_fetch_to_buffer(url, buf, cap, statusBuf, size_out)` next to it — ~30 lines wrapping `esp_http_client` on ESP32, a libcurl / URLSession stub on desktop — is the right home for this.
- **JSON parsing on-device** — the existing `mm::json` scalar helpers are flat and key-order-independent; a `releases/latest` payload uses a nested `assets[]` array which the current helpers don't walk. Either extend them (~30 lines to walk one level of array), or scan for the `tag_name` string directly with `strstr` for this one caller.

Once both land, add a `ReleaseCheckModule` (or a small extension inside NetworkModule / FirmwareUpdateModule — decide when building) that owns the poll timer + last-seen version cache and calls into `MqttModule::publishUpdateState()`. ~50 additional lines.

## Testing

### Additional test coverage (pending)
Expand Down
8 changes: 7 additions & 1 deletion docs/moonmodules/core/services.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,8 @@ The topic prefix is `projectMM/<mac>` — a **stable** identifier (the last 6 he
| set → device | `projectMM/563cfe/hsv/set` | `h,s,v` (hue `0`–`359`, sat/val `0`–`100`) |
| device → get | `projectMM/563cfe/hsv/get` | `h,s,v` |
| device → get | `projectMM/563cfe/name` | the friendly `deviceName` (retained) |
| device → get | `projectMM/563cfe/update/state` | `{"installed_version":…,"latest_version":…,"release_url":…,"title":…}` (retained; HA update entity) |
| set → device | `projectMM/563cfe/update/set` | target version string (empty = install latest); triggers OTA against the matching GitHub release asset |

The HomeKit colour wheel has no "palette" concept, so `hsv/set`'s hue+saturation pick the **nearest palette** (each built-in palette has a representative colour; the closest one is selected) and the value drives brightness — the colour wheel becomes a natural palette selector.

Expand All @@ -200,7 +202,11 @@ The HomeKit colour wheel has no "palette" concept, so `hsv/set`'s hue+saturation
}
```

Home Assistant does not need MQTT: it adopts the device through its built-in WLED integration over the existing WLED `/json` API.
Home Assistant adopts the device two ways, both zero-config:
- **MQTT auto-discovery** — with `haDiscovery` on (the default) and a broker set, the device announces itself on `homeassistant/light/projectMM_<mac6>/config` and HA auto-creates a wired entity (on/off + brightness + HSV). Richer state, retained across reboots.
- **WLED integration** — HA's built-in WLED integration discovers the device over the WLED `/json` API projectMM already serves; on/off + brightness work with no broker.

Both can be on at once. Setup walkthrough (including exposing HA to Apple Home via HA's HomeKit Bridge, no Homebridge needed) in the [Home Assistant recipe](../../usecases/home-automation.md#home-assistant).

## File Manager — details

Expand Down
Loading
Loading