mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
Owner's report 2026-08-04: «в настройках "открыть\закрыть", а по нажатию по-прежнему инфо-карточка». Diagnosed on his own config, not guessed. The two curtain markers in the office (`.storage/houseplan.config`) carry `tap_action: "cover"` exactly as the dialog wrote it — so saving was never the problem. The devices are Aqara «Roller shade driver E1», and their entity registry reads: cover.shtory_v_kabinete_sprava hidden_by: integration switch.shtory_..._reverse_direction visible sensor.shtory_..._motor_state visible binary_sensor.shtory_..._running visible + battery / temperature / linkquality diagnostic `primaryEntity` ranks visible above hidden (that tier loop is deliberate — a TRV's anti-scaling switch must not outrank the head that heats), and inside a tier `switch` outranks `cover`. So the marker's primary was `switch.*_reverse_direction`, `_clickDevice` handed the domain `switch` to `resolveTapAction`, and `want === 'cover'` with `domain !== 'cover'` degrades to 'info' — the info card the owner kept getting. The dialog meanwhile went on offering the action, because `_bindingCoverTap` had always looked at EVERY entity of the device. The two checks disagreed about what the device is. Fixed the way the climate temperature already does it: what a device DOES is not always what its primary entity is. `coverEntityOf(entIds)` (logic.ts) returns the first `cover.*` among all of the marker's entities; `_clickDevice` uses it as the entity the tap acts on whenever the explicit action is 'cover', and reads the domain, the device_class and the current state off it, then calls the service on it. So the guarded classes still degrade: a garage door's `cover.*` is found the same way and `resolveTapAction` still answers 'info'. `_bindingCoverTap` now goes through the same helper, so the option offered and the action taken can no longer disagree about WHICH cover. No cover at all on the device: `coverEid` is null, nothing changes, still the info card. demo/smoke_cover_not_primary.mjs builds the owner's device entity for entity (hidden cover + visible reverse-direction switch + diagnostics), asserts the premise (the primary IS the switch), then goes end to end: open the marker dialog, pick «Open/close», save through _saveMarker, let the card rebuild the marker from that config, tap — cover.open_cover on cover.office_curtain, then close_cover, then stop_cover while travelling, and the service switch is never called. A garage device_class on the same cover calls nothing, shows the info card and is not offered in the dialog. Before the fix four of its checks are red. Unit: coverEntityOf over the same entity list, empty/null input, two covers (first wins) and a `sensor.cover_position` decoy.