Skip to content

Event-only program support (hoods, hobs) & keep-alive watchdog backoff (builds 20–24) - #19

Open
bumaas wants to merge 5 commits into
symcon:masterfrom
bumaas:pr/event-only-programs-watchdog-backoff
Open

Event-only program support (hoods, hobs) & keep-alive watchdog backoff (builds 20–24)#19
bumaas wants to merge 5 commits into
symcon:masterfrom
bumaas:pr/event-only-programs-watchdog-backoff

Conversation

@bumaas

@bumaas bumaas commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

This PR builds on the current master (build 19) and adds builds 20–24. It is the delta only; the tree matches our tested fork state. All 52 PHPUnit tests pass.

Motivation

Two field cases drove these changes. A hood operated at the appliance reports its programs only via BSH.Common.Root.ActiveProgram events (never via SelectedProgram), so runtime programs like fan run-on were invisible. And hobs turned out to be monitoring-only appliances: the API lists no programs for them at all, leaving the Programs profile empty and the raw key on display. Separately, a support log showed a permanently dead event stream turning into a quota death spiral: the keep-alive watchdog reconnected every 2 minutes without backoff (~700 GET /events per day), keeping the "1000 calls in 1 day" limit exhausted for good.

Changes

Device (Home Connect Device)

  • Active program from ActiveProgram events: a read-only ActiveProgram variable is maintained from the event stream, so appliance-started programs (e.g. hood fan run-on) become visible. SelectedProgram is intentionally never filled from these events — its value goes into the start payload.
  • Option variables for event-only programs: on a program change reported via ActiveProgram, the option variables (e.g. VentingLevel) are created from a single deferred programs/available/<key> request (RegisterOnceTimerRequestAction, off the event thread). Option values arriving before the variables exist are buffered and applied afterwards. An UnsupportedProgram answer no longer clears the program selection.
  • Translated display names for event-only programs: programs that never appear under programs/available (hob modes, hood interval venting, oven follow-up/cleaning modes, coffee maker cleaning modes, favorites) get a curated, translatable display name in the HomeConnect.<type>.Programs profile via the new EVENT_ONLY_PROGRAM_NAMES map, including a BSH.Common.Program.Favorite.NNN → "Favorite N" pattern rule. German translations included.
  • Skip GET /programs for programless appliance types: the API documentation states "There are no programs available for …" for Refrigerator, Freezer, Fridge Freezer and Wine Cooler (and no released program support for Cook Processor), so the request — a guaranteed SDK.Error.UnsupportedOperation — is skipped for these types.

Cloud (Home Connect Cloud)

  • Keep-alive watchdog backoff: reconnect attempts on a stale keep-alive now back off exponentially (2 min → capped at 1 h), reset by the first received keep-alive. A briefly dropped stream still recovers quickly, but a permanently dead stream no longer burns the daily quota (~700 → ~30 requests/day worst case).
  • Watchdog logs the IO status: the "KeepAlive | Failed" debug line now includes the SSE client IO's InstanceStatus. On a silently dead stream nothing reaches ReceiveData, so this is the only hint whether the IO saw an HTTP error or still believes it is connected.

Tests

PHPUnit suite extended from 40 → 52 tests (hood fixture set incl. ActiveProgram flow, buffered option values, unsupported-program handling, profile associations with translated names and the favorites rule, watchdog backoff and its keep-alive reset, no /programs request for programless types). All green.

bumaas and others added 5 commits August 2, 2026 11:53
…achlauf)

Geräte wie Dunstabzugshauben melden das laufende Programm beim
Lüfternachlauf / der Intervall-Lüftung nur über
BSH.Common.Root.ActiveProgram, nie über SelectedProgram - bisher wurde
das Event per EXCLUDE-Liste komplett ignoriert und die Programmanzeige
blieb leer (Forum-Meldung pitti, Beitrag #530/#531).

Neu: rein anzeigende Variable "Aktives Programm" (Ident ActiveProgram),
befüllt direkt aus dem Event, angelegt erst beim ersten
ActiveProgram-Event, geleert bei value=null (Programmende). Keine
zusätzlichen API-Aufrufe, keine Auswirkung auf SelectedProgram/Start.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…gLevel)

Haube bei lokaler Bedienung meldet ihr Programm nur über ActiveProgram,
nie über SelectedProgram - der Pfad, der die Options-Variablen anlegt,
lief daher nie und Events wie VentingLevel hatten keine Variable zum
Aktualisieren (Forum-Fall pitti, LD88WMM66).

- ActiveProgram-Event stößt (entkoppelt per OnceTimer, nur bei
  Programmwechsel) einen Abruf von programs/available/<key> an und legt
  die Options-Variablen mit Profil aus den Constraints an
- Option-Werte, die vor der Variablenerzeugung eintreffen, werden
  gepuffert und nach dem Anlegen angewendet
- updateOptionVariables: neuer Parameter clearSelectionOnFailure, damit
  ein nicht auflösbares Laufzeitprogramm (z. B. Lüfternachlauf,
  SDK.Error.UnsupportedProgram) die Programmauswahl nicht mehr leert
- Tests: Haube mit vollständigem Fixture-Satz (Init, Variablenerzeugung
  inkl. Request-Zählung, Puffer-Replay, UnsupportedProgram-Regression)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…iral on dead stream)

With a permanently dead event stream the watchdog used to reconnect every
2 minutes - ~700 GET /events per day, keeping the "1000 calls in 1 day"
quota exhausted for good (forum case zman0801). Reconnect attempts now back
off exponentially (2/4/8/... min, capped at 1 hour) and reset as soon as
the first keep-alive arrives.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…odes, oven/coffee runtime programs)

Hobs are monitoring-only: the API lists no programs, so the Programs
profile stayed empty and ActiveProgram showed the raw key. ActiveProgram
events now add a translated profile association for programs that never
appear under programs/available (hob modes, hood interval venting, oven
follow-up/cleaning modes, coffee maker cleaning modes, favorites).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… appliance types

- CheckServerEvents now includes the SSE client IO's InstanceStatus in the
  "KeepAlive | Failed" debug line. On a silently dead stream nothing reaches
  ReceiveData, so this is the only hint whether the IO saw an HTTP error or
  still believes it is connected (diagnosis gap seen in a support case where
  the stream stayed dead with no visible cause).
- createPrograms() skips the GET /programs request for appliance types the
  API documents as having no programs (Refrigerator, Freezer, FridgeFreezer,
  WineCooler, CookProcessor) - it was a guaranteed
  SDK.Error.UnsupportedOperation costing one request per initialization.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@bumaas
bumaas force-pushed the pr/event-only-programs-watchdog-backoff branch from baf5b46 to 05bda74 Compare August 2, 2026 09:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant