Skip to content

Build 14: device status no-op guards + rate-limit/SSE reconnect fixes#17

Merged
TillBrede merged 14 commits into
symcon:masterfrom
bumaas:sync/upstream-build-14
Jul 1, 2026
Merged

Build 14: device status no-op guards + rate-limit/SSE reconnect fixes#17
TillBrede merged 14 commits into
symcon:masterfrom
bumaas:sync/upstream-build-14

Conversation

@bumaas

@bumaas bumaas commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Bringt symcon/HomeConnect auf Build 14 und bündelt zwei Korrektur-Stränge.

1. Device-Status nur bei Änderung setzen

Seit „Fix/device status refresh and setting constraints (#10)" rief das Home-Connect-Device-Modul SetStatus() bei jedem Refresh (Parent-Statuswechsel, CONNECT, Reconnect, ApplyChanges) bedingungslos auf. Das triggerte Status-Monitoring (z. B. EventControl-Skripte) auch ohne tatsächliche Änderung und erzeugte viele unnötige Log-/Trigger-Einträge.

Alle drei Status-Setzer (IS_ACTIVE in refreshDeviceState() sowie beide IS_INACTIVE-Aufrufe in refreshDeviceState() und im FM_DISCONNECT-Handler) laufen jetzt über eine neue Hilfsmethode setInstanceStatus(), die den aktuellen Status zuerst vergleicht und nur bei echter Änderung schreibt — analog zum bereits im Cloud-Modul vorhandenen Guard. Ursprünglich gemeldet und angestoßen von @ThomasM65.

2. Rate-Limit-/SSE-Reconnect-Fixes

  • Verhindert, dass die SSE-Reconnect-Schleife /events weiter anfragt, während ein Rate-Limit aktiv ist.
  • Behebt eine Re-Init-Schleife, die das API-Kontingent bei Geräten ohne OperationState aufbraucht (Initialized-Attribut statt vorab geschriebener Signatur).
  • Neue Tests: HomeConnectCloudTest, HomeConnectFridgeFreezerTest.

Build

library.json: build → 14, date → 1782691200 (2026-06-29).

Tests

PHPUnit: 30 Tests, 519 Assertions – grün.

bumaas and others added 14 commits June 19, 2026 08:56
Write InitializationSignature at the start of InitializeDevice() instead
of at the end. Previously, if createStates() failed (device offline) or
setupSettings() was interrupted (rate limit hit mid-way), the signature
was never written. Any subsequent IM_CHANGESTATUS or CONNECTED event would
re-trigger InitializeDevice(), burning through the 1000 requests/day limit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Devices without an OperationState in /status (e.g. FridgeFreezer) never
created that variable, so needsInitialization() returned true on every
IM_CHANGESTATUS. Each parent status flap re-ran a full InitializeDevice(),
burning through the rate limit within seconds (observed: 3 full cycles
before the 429).

Replace the fragile "OperationState variable exists" check with a dedicated
Initialized attribute that is only set true after a fully successful
initialization. The signature is written at the same point, so a partial
failure (offline / rate limit mid-way) leaves Initialized=false and a retry
happens on the next CONNECTED event - not on every status flap.

Also suppress the echo for rate-limit responses (key 429) in
RequestDataFromParent so blocked requests no longer spam the kernel log as
"Fehler bei Instanz ... IM_CHANGESTATUS".

Add a FridgeFreezer fixture and regression test (with an API request counter
in the test API) that fails on the old code (5 calls) and passes now (0).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The keep-alive watchdog (60s timer) reconnected the event stream whenever no
KEEP-ALIVE arrived. When /events itself returns 429 (daily limit), no keep-alive
ever arrives, so the watchdog reconnected every ~60s - ~1440 calls/day, which on
its own exceeds the 1000/day limit and keeps the account permanently blocked.
This was independent of the device re-init loop and is why the problem persisted.

- Guard RegisterServerEvents() on isRateLimitActive(): defer the reconnect to the
  end of the block window instead of retrying immediately. This covers all
  reconnect paths (Reconnect timer, keep-alive check, FM_CONNECT).
- CheckServerEvents() returns early while rate limited (the missing keep-alive is
  expected then).
- ResetRateLimit() resumes the stream exactly once when the window ends.
- Feed a 429 carried by the SSE stream into the shared rate-limit machinery
  (ReceiveData -> applyRateLimitFromStream), so the limit is honored even when no
  REST call ran. Extracted applyRateLimit() so REST and SSE share one code path.

Add HomeConnectCloudTest covering: 429-from-stream activates the limit, reconnect
is deferred while limited, keep-alive check skips while limited. These fail on the
old code (reconnect despite limit) and pass now.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
I'm using Eventcontrol-Scripts to monitor if Status of Instances has changed.
Since last change Status is updated very often even if state has not changed. This will Trigger everytime a Eventcontrol message (no option on changed, always on updated). There is no way to check if status was already active (no $_IPS['LASTSTATUS']). So now EventControl will only get triggered if Status has really changed.
Set status to active only if not already active
Extends Thomas' fix (#1) so the Home Connect Device instance status is only
written when it actually changes. Before, refreshDeviceState() and the
FM_DISCONNECT handler called SetStatus() unconditionally on every refresh
(parent status change, CONNECT, reconnect, ApplyChanges), which re-triggered
status monitoring (EventControl scripts) even when nothing changed.

Route the IS_ACTIVE and both IS_INACTIVE setters through a new
setInstanceStatus() helper that compares the current status first.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Build 14: rate-limit/SSE reconnect fixes + device status no-op guards
# Conflicts:
#	Home Connect Device/module.php
#	library.json
ordered_class_elements moved the private helpers below the public methods
in Home Connect Cloud/module.php (applyRateLimitFromStream) and
tests/HomeConnectCloudTest.php (cloud/invoke), fixing the checkstyle run.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@TillBrede TillBrede self-assigned this Jul 1, 2026
@TillBrede TillBrede merged commit 1156648 into symcon:master Jul 1, 2026
2 checks passed
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.

3 participants