UUID re-pair orphans — silent fail po výměně baterky

Otevřu okno v jídelně, čistička vzduchu pokračuje v běhu. Měla by se vypnout — flow trigger na alarm_contact open už rok funguje bez problémů. Ale dnes ne. Žádný error v UI, žádný alert, prostě silent fail.

Po výměně baterky v Door/Window Sensor Jidelna1 před týdnem získal Homey zařízení nové UUID. Tři flows referencující původní UUID osiřely. Tohle je příběh diagnostiky a bulk fix.

Symptom

Door/Window Sensor Jidelna1 funguje normálně z perspektivy capability — v Homey UI vidím alarm_contact hodnotu, real-time se mění při otevření/zavření. Tile na dashboardu reaguje. Senzor není mrtvý, komunikuje, posílá data.

Ale flowy které měly reagovat na change events — nereagují. Žádný flow run log, žádný error. Trigger karta v UI vypadá normálně, žádné červené upozornění. Senzor existuje, flow existuje, jen mezi nimi chybí spojení.

Postižené flows

  1. SH – Cistic – Window Open — vypne čističku při otevřeném okně (zbytečné filtrovat venkovní vzduch)
  2. SH – Heating – Window Open — sníží target koupelny + jídelny o 2 °C při otevřeném okně (heat loss compensation)
  3. SH – Lights – Privacy Bypass — při otevřeném okně dočasně uvolní privacy guard (předpokládá user activity)

Diagnose

Zkusil jsem několik checků:

# Senzor existuje?
GET /api/manager/devices/device/<jidelna1_uuid_in_flow>
→ 404 Not Found

# Senzor v device list?
GET /api/manager/devices/device
→ vidím "Door/Window Sensor Jidelna1" ale s JINÝM UUID

# Compare:
flow_uuid: 5c3a8e21-b4f2-4a91-9d1c-7e8f6a2b3c4d
real_uuid: 9f4c2e88-3a7d-4f5b-b2e6-1c8a9d5e7f3b

Old UUID (v flow trigger karty) vs. real UUID (current device) se liší. Po výměně baterky 19.4. (memory snapshot) Homey vygeneroval nové UUID. Old UUID v 3 flows zůstal jako orphan reference — zařízení které „neexistuje" (404), takže trigger nikdy nefiruje.

Proč to není error

Homey flow trigger systém má graceful degradation pro chybějící devices — místo erroru jen nikdy nefiruje. To dává smysl pro robustnost (jeden offline senzor by neměl shodit celý flow systém), ale znamená to silent fail.

Žádná UI indikace „tento flow odkazuje na neexistující device". Žádný alert. Žádný flow run log entry. Bug je viditelný jen tehdy, kdy očekáváš, že se něco stane, a nestane se nic.

Fix — bulk swap

Manuální fix per flow přes UI by znamenal otevřít každý flow, najít trigger card, přemapovat na nový device. Tři flows = tři minuty manuálně. Pro budoucí incidenty (a budoucí výměny baterek) chce automatizaci.

# 1. Najdi všechny flows referencující old UUID
flows = GET /api/manager/flow/advancedflow
broken = [f for f in flows if old_uuid in str(f.cards)]

# 2. Per broken flow: PUT s nahrazeným UUID
for flow in broken:
  for card in flow.cards:
    if card.deviceId == old_uuid:
      card.deviceId = new_uuid
  PUT /api/manager/flow/advancedflow/<flow_id> flow

Bulk swap proběhl, 3 flows fixly. Test: otevřu okno, čistička se vypne. Funkce obnovena.

Backlog — preventive scanner

Tohle je očekávaný incident — výměna baterky se opakuje každý rok+, a každý re-pair vygeneruje nové UUID. Reactive fix per incident není škálovatelný.

Backlog: tools/find_orphan_device_refs.py — preventive scanner který běží před každým commitem (případně daily cron). Iteruje flows, porovnává device IDs s current device list, hlásí orphan refs.

# tools/find_orphan_device_refs.py (návrh)
from homey_api import get_devices, get_flows

def main():
  devices = {d.id for d in get_devices()}
  flows = get_flows()
  for flow in flows:
    for card in flow.cards:
      if card.deviceId and card.deviceId not in devices:
        print(f'ORPHAN: flow={flow.name} card={card.id} '
              f'orphan_id={card.deviceId}')

Co se naučilo

Silent fail je nejhorší kategorie bugu. Vidíš výsledek (čistička neběží), netušíš příčinu (žádný error). Diagnose vyžaduje state inspection napříč systémem, ne čtení logů.

Lessons:

  • Re-pair = nový UUID. Po každé výměně baterky / re-installu očekávat orphan flow trigger refs. Není to bug Homey, je to design choice (UUID stability vs. clean slate).
  • Test po každé výměně baterky. Jednoduchý smoke test — otevři okno, čistička se vypne? Ne? Diagnose.
  • Preventive scanners > reactive fixes. Lepší minutu denně ověřovat invariant než hodinu fixovat incident.
  • Brain Guardian extension. Tahle invariant patří do guardian — periodicky kontroloval, žádné orphan device IDs ve flows. V plánu.

UUID stability ve smart home světě je problém který bude eskalovat s každým novým zařízením. Aqara P2 (Matter/Thread) náhrada pro SNZB-04 přidává další permutaci, kde re-pair po Thread network change generuje nové ID.

Generální princip: nikdy nereferencovat device přímo přes UUID v user-facing kódu. Místo toho přes name lookup (resolve at runtime) nebo device map abstraction (one place to update). Aktuální architektura tohle dělá pro skripty (sh_device_map_v1), ale ne pro flow trigger karty — limitace Homey UI.