Repository navigation
feat(alarm): read-only alarm panel; arm and disarm through AUX frames (#564) - #609
Conversation
The plant owner in OpenWebNet-HA#564 (comment 5913248544) reports, quoting BTicino support, that current central-unit firmware rejects arm/disarm sent as WHO 5 frames over SCS, whichever gateway sends them. No capture shows one accepted. They arm with a WHO 9 AUX frame (e.g. *9*1*7##) that an automation programmed on the central unit maps to zones, so the frames are the installer's choice. The panel advertised arm away/home and trigger and sent *5*1*0##, *5*2*0## and *5*17*0##; the first is "activation", not arming. It now has no arm/trigger features (core refuses those services) and refuses disarm, which core cannot gate, with a translated ServiceValidationError. State handling is unchanged. The docs show a core template alarm panel that takes its state from the MyHOME panel and sends the AUX frames with myhome.send_message. The state table now maps armed_away to *5*8*## and explains WHAT 1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
fedem95
left a comment
There was a problem hiding this comment.
Read-only is the right call given #564, and the state table now matches what the F454 trace (#311) shows for WHAT 1. Code looks good: no features, disarm refused with a translated error, handle_event untouched.
A few things on the docs and around it:
- The template recipe disarms without a code. With
code_arm_required: falseand no check oncode, anyone who can reach Home Assistant disarms the burglar alarm with one tap, including from the alarm card. I'd at least say so in the doc, and ideally show the pattern, e.g.code_format: numberand aconditiononcodeindisarm:before the AUX frame. - Discovery depends on the gateway. The doc says the panel is registered by "the
*5*9*0##a disarmed panel sends when polled". On the MH202 (#564) that's true. In the F454 trace from #311, though, the system-level frames come with an empty WHERE (*5*1*##,*5*5*##,*5*7*##,*5*9*##), and MyHOME deliberately doesn't create an entity from""(OWNd#66 discussion). On that gateway the panel would only appear at the first live*5*8*0##/*5*9*0##, i.e. the first real arm or disarm after a blank start. Worth a sentence in the doc, or a follow-up to adopt the existing0panel from an empty-WHERE status. alarm_read_onlyis English-only. For it.json I'd suggest: "{name} è di sola lettura: inserisci e disinserisci l'allarme con i comandi AUX programmati sulla centrale". Happy to add it, together with the other missing Italian keys, in the follow-up to #577.
Minor: the template's state passes unknown/unavailable straight through when the MyHOME panel hasn't reported yet; the template panel logs those as invalid states. A default ({{ states(...) if states(...) in ['disarmed','armed_away','triggered'] else 'disarmed' }}, or availability) would keep the log clean.
…teway-dependent discovery Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
fedem95
left a comment
There was a problem hiding this comment.
Thanks, 1 and 2 are covered well.
CI: the coverage failure isn't from this commit. pypi_standards.yml installs OWNd from master, and OWNd#66 was merged at 14:17Z, four minutes before f7c82c3. Since then is_armed_home is always False, so alarm_control_panel.py:193 (self._attr_alarm_state = STATE_ARMED_HOME) can't be reached and the 100 % gate fails. It will fail on every open MyHOME PR, not just this one. Dropping that elif matches the new doc ("armed_home is never reported"), and this PR seems the natural place for it.
I'd revert my own suggestion on the fallback. Falling back to disarmed while the MyHOME panel is unknown/unavailable makes the template panel show "Disarmed" after every restart until the central unit reports, even if the alarm is armed. For a burglar alarm that's the wrong default. availability is the better of the two options I offered:
availability: "{{ states('alarm_control_panel.alarm_0') in ['disarmed', 'armed_away', 'triggered'] }}"
state: "{{ states('alarm_control_panel.alarm_0') }}"!secret and the code check. !secret can't be interpolated inside the template string, so {{ code == !secret … }} won't work. The whole template has to be the secret (value_template: !secret alarm_disarm_check, with alarm_disarm_check: "{{ code == '1234' }}" in secrets.yaml), or the code can be compared against a helper. Worth spelling out, since the warning tells people to do it.
… feat/alarm-read-only-aux
…ses availability OWNd#66 makes is_armed_home always False (home and away arming look the same on the bus), so the elif in handle_event could not be reached and failed the 100 % coverage gate against OWNd master. Docs, per review: the template panel is unavailable until the MyHOME panel reports instead of falling back to disarmed (which would show an armed alarm as disarmed after a restart), and the code check explains that !secret must hold the whole template. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks @fedem95, all points from both reviews are handled. The full point-by-point write-up is in #615; short version: First review
Second review
The PR description is updated to match. |
9da01ad
into
OpenWebNet-HA:v2-phase1-architecture
…il a verdict `AlarmControlPanelState(last_state.state)` accepted every core value, so a stale `armed_home` (removed in OpenWebNet-HA#609) or a transient `arming` / `pending` from .storage/core.restore_state would have been restored and left the documented template panel unavailable. Restore only `disarmed`, `armed_away` and `triggered`; anything else starts unknown. While `restored` is set, frames that name no state (`*5*1*0##` activation, `*5*11*#n##` / `*5*18*#n##` zones, `*5*5*##` battery, `*5*7*##` mains) no longer overwrite `raw_state` / `state_code`, which would have persisted a mismatched `armed_away` + `activation` pair across a second restart. A verdict frame overwrites both and clears the flag; once live, telemetry updates them as before. Tests: each restorable state, six stale or transient states, five non-verdict frames followed by a verdict. The doc lists the frames that confirm a restored state. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Problem
The plant owner in #564 (comment) reports, quoting BTicino support, that current central-unit firmware rejects arm/disarm sent as WHO 5 frames over SCS, whichever gateway sends them. No capture shows such a command being accepted. They arm with a WHO 9 AUX frame (e.g.
*9*1*7##) plus an automation programmed on the central unit; which AUX channels arm or disarm is the installer's choice.The panel still advertised arm away / arm home / trigger and sent:
*5*1*0##*5*2*0##*5*17*0##Changes
alarm_control_panel.py):ServiceValidationError(alarm_read_only) instead of sending a frame.armed_homebranch inhandle_eventand theSTATE_ARMED_HOMEconstant are gone. feat(alarm): complete WHO 5 burglar alarm implementation and gateway profiles OWNd#66 makesis_armed_homealways False (home and away arming look the same on the bus), so the branch could not be reached and failed the 100 % coverage gate against OWNd master. The other state transitions are unchanged.alarm.md: read-only state table (armed_away=*5*8*##, WHAT 1 explained,armed_homenever reported), and a note that discovery depends on the gateway: an F454 answers a poll with empty-WHERE frames, so there the panel appears at the first real arm or disarm.alarm.md: a core template alarm panel recipe that takes its state from the MyHOME panel and sends the AUX frames withmyhome.send_message. It requires a code to disarm (code_format: numberplus aconditiononcode), is unavailable until the MyHOME panel has reported (nodisarmedfallback), and explains how to keep the code insecrets.yaml:!secretmust hold the whole template.supported_functions.md, use case 7 and the README domain table (viascripts/update_supported_domains.py) no longer promise arm/disarm.alarm_read_onlyinstrings.json, synced toen.json. Italian is left to @fedem95's follow-up to fix(translations): placeholder mismatches in it/fr/nl and Italian CEN trigger names #577, as offered in the review.Breaking change
Automations that call
alarm_control_panel.alarm_arm_away/alarm_arm_home/alarm_trigger/alarm_disarmon the MyHOME panel now fail instead of sending a WHO 5 frame. Per #564 those frames did nothing on current firmware. Anyone whose central unit does accept them can still send them withmyhome.send_message, or from a template panel.Review follow-ups
Each of @fedem95's review points and how it was handled is listed in #615.
Tests
tests/test_alarm_read_only.py(new): full config-entry setup; each of the four services raises and nothing is sent to the gateway.test_component_alarm.py: features are empty, disarm raises with the translation key, status requests are unchanged, and an active-zone frame (*5*11*0##) leaves the panel's state alone.Branch merged with
v2-phase1-architecture(includes test(alarm): arm with WHAT 8, not WHAT 1 (OWNd#66 conformance) #608).Full suite against OWNd master (with Support for audio control / sound system (WHO 16)? #66): 3129 passed, 100 % coverage. Alarm tests also pass against OWNd 2.0.0b9 from PyPI (the manifest pin).
CI green; ruff clean.
V2 Architecture: no new entities;
handle_event()only loses the unreachablearmed_homebranch.🤖 Generated with Claude Code