Skip to content

Only publish polled values that changed (setStateChanged) - #117

Open
AlanSRU wants to merge 1 commit into
TA2k:mainfrom
AlanSRU:perf/write-changed-only
Open

AlanSRU wants to merge 1 commit into
TA2k:mainfrom
AlanSRU:perf/write-changed-only

Conversation

@AlanSRU

@AlanSRU AlanSRU commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

What

Polls now publish a value only when it has changed. json2iob writes through setStateChangedAsync instead of setStateAsync, via a thin wrapper around the adapter that is passed to new Json2iob(...). Nothing else changes.

Why

Every poll re-wrote every state, so every subscriber received an update for every value on every poll, even when nothing had changed. With a KH100 hub and nine KE100 TRVs plus one P110, that was about 340 state updates a minute. Each TRV produced 35 updates a minute while its readings stayed the same.

That traffic reaches everything subscribed to the states: VIS and other UIs, scripts with on({ id }) without change: 'ne', aliases, and cloud relays. The ioBroker.cloud free tier blocks the account for "too many events" because of it.

Measured from a UI subscribed to the TRV and plug aliases, over 60 seconds:

Before After
All updates 307 30
Per KE100 35 0–1 (only real changes)

Why not json2iob's previousData option

json2iob has a previousData option for this, but it doesn't work for list payloads such as a hub's child_device_list. json2iob names list entries (by nickname, ID and so on) when it builds the state path. _hasValueChanged then looks that named path up in the previous payload, where the entries are still array indexes. The lookup never matches, so every child value counts as changed and is written anyway. Comparing against the stored state with setStateChanged avoids the problem. It also corrects a state after a command the device didn't apply, because the next poll's value differs from the ack: false value the user wrote.

Notes

  • Only json2iob's writes are affected. Direct setState calls are unchanged, including connected, motionEvent, ringEvent and the remotes, so events still fire every time.
  • Camera detection states written through json2iob (active, eventCount, the event list) are level values that change with every new event, so they still update.
  • Side effect: ts no longer advances for values that don't change. lc was already only set on change.

Testing

  • npm run lint, type check, build-adapter ts, and npm test (44 passing).
  • Running on a live install (KH100 + 9 × KE100, P110, P100s) since 2026-10-04: values stay current, no errors in the log.

Zusammenfassung (DE)

Beim Polling werden jetzt nur noch geänderte Werte geschrieben: json2iob schreibt über setStateChangedAsync statt setStateAsync. Bisher wurde bei jedem Poll jeder State neu gesetzt. Mit einem KH100 und neun KE100 waren das rund 340 Updates pro Minute an alle Abonnenten (VIS, Skripte, Aliase, Cloud). Gemessen sinkt das von 307 auf 30 pro Minute. Die json2iob-Option previousData funktioniert für Listen wie child_device_list nicht, weil die benannten Pfade im vorherigen Payload nie gefunden werden. Direkte setState-Aufrufe (z. B. motionEvent, ringEvent, connected) bleiben unverändert.

🤖 Generated with Claude Code

Every poll re-wrote every state through json2iob, so each subscriber received an
update for every value on every poll even when nothing changed (a KH100 with nine
KE100s: ~340 updates a minute). json2iob now writes through setStateChanged.

json2iob's own previousData option can't be used here: it looks list entries up by
the named path it generates, which doesn't exist in the previous payload, so every
child of a hub's child list would still count as changed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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