Skip to content

[Feature]: Schedule OTA update for sleepy/battery devices #12

@tashda

Description

@tashda

What problem does this solve?

OTA updates for battery-powered devices (remotes, battery sensors, some Legrand devices) almost always fail because the device is asleep and unreachable when the user taps Update. Today the only workaround is to physically press a button on the device at the exact moment the OTA request is sent, to wake it up long enough to start the transfer. This is awkward for remotes that aren't on hand and impossible for embedded sensors.

The original headline I had in mind was "Force Update" — but after investigating, there is no way to force a sleepy Zigbee End Device awake from the coordinator side. The radio is off by spec until the device itself polls its parent. Z2M's docs even confirm the button-press trick is the canonical workaround:

"For battery powered end-devices you may need to trigger them by e.g. pushing a button right before checking for an OTA."
Z2M OTA docs

However, Z2M already exposes the right primitive for this: schedule. It tells Z2M "next time this device wakes up on its own and asks for an image, give it one." This is persisted in the coordinator's database, survives Z2M restart, retries automatically forever, and adds a scheduled state to the device's update field. The Z2M web frontend already wires this up.

What would you like Shellbee to do?

Add Schedule update and Cancel scheduled update actions to the OTA UI, alongside the existing "Check for updates" and "Update now" actions. Surface the new scheduled state in device cards.

MQTT plumbing (already in Z2M, no bridge changes needed):

  • Schedule: POST bridge/request/device/ota_update/schedule payload {"id": "<friendlyName>"}
  • Unschedule: POST bridge/request/device/ota_update/unschedule payload {"id": "<friendlyName>"}
  • Downgrade variant: bridge/request/device/ota_update/schedule/downgrade
  • New device state: update.state can be scheduled (joins idle | available | updating)

UX behavior:

  • Battery devices (power_source: "Battery"): primary CTA becomes Schedule update. Show a hint: "This device is battery-powered. After scheduling, press a button on the device to trigger the update." Secondary action: Update now (kept as an escape hatch for users who want to try the immediate path or are about to physically wake the device).
  • Mains-powered devices: primary CTA stays Update now. Schedule still available as a secondary option.
  • Scheduled state: device card shows a "Scheduled" badge. OTA list view includes a Scheduled section. Tapping a scheduled device exposes Cancel scheduled update.
  • Optimistic UI: tapping Schedule should immediately show Scheduled badge while waiting for bridge/response/device/ota_update/schedule (consistent with the optimistic remove/rename pattern already used in Shellbee).

Reference implementation:

The Z2M web frontend (zigbee2mqtt-windfront) already implements this in src/pages/OtaPage.tsx — the actOnFilteredSelected handler wires all four topics: check, update, schedule, unschedule. Mirror its terminology for consistency (translation keys live under i18n namespace "ota").

Does the Z2M web frontend already do this?

Yes — and Shellbee should match it. See OtaPage.tsx / OtaControlGroup.tsx / OtaUpdateButton.tsx in zigbee2mqtt-windfront.

Alternatives you've considered

  • "Force Update" button that loops update requests — wouldn't help. The device still has to wake up on its own; spamming update from the coordinator just wastes bandwidth and times out repeatedly.
  • Keep doing the manual button-press workaround — works but unergonomic for remotes that are stored away or sensors that don't have buttons.
  • Wait for Z2M / firmware to add a wake-on-rx mechanism — not coming. This is a fundamental Zigbee protocol property for sleepy ZEDs.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions