Skip to content

fix(opener): emit every ring, not just the first one - #540

Open
ooooli wants to merge 1 commit into
iobroker-community-adapters:masterfrom
ooooli:fix/opener-repeated-ring-events
Open

ooooli wants to merge 1 commit into
iobroker-community-adapters:masterfrom
ooooli:fix/opener-repeated-ring-events

Conversation

@ooooli

@ooooli ooooli commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Problem

The Opener's ring is an event, not a status. Nuki reports state.ringactionState = true again for every ring, while state.ringactionTimestamp advances each time.

Library._setValue() deduplicates writes against its internal _STATES cache:

https://github.com/iobroker-community-adapters/ioBroker.nuki-extended/blob/master/lib/library.js#L597-L612

if (value !== undefined && (options.force || this._STATES[state] === undefined ||
    this._STATES[state] === null || this._STATES[state].val != value)) {
    this._adapter.setStateAsync(state, { val: value, ts: Date.now(), ack: true });
} else {
    this.setDeviceProperties(state);   // nothing is written
}

Because the value is true both times, the second ring is swallowed and state.ringState is never written again. Anything subscribing to that state misses every ring after the first.

There is a second, related effect: the cache can drift from the actual state. If ringState is written from outside the adapter — a script resetting it to false, a VIS widget, a manual change — the adapter still believes the value is true and suppresses all further writes until it is restarted.

How to reproduce

  1. Subscribe to <instance>.openers.<opener>.state.ringState.
  2. Ring the doorbell — the state turns true, the subscription fires.
  3. Ring again a few minutes later — no write, no event.

Real-world symptom: the postman rings and the announcement plays; the parcel service rings minutes later and nothing happens. It works again after an adapter restart (cache reset) or if Nuki happens to report false in between, which is why it looks intermittent.

state.ringStateUpdate (the timestamp) is unaffected and can be used as a workaround, but ringState is the obvious state to subscribe to and currently misleads consumers.

Fix

Whenever a newer ringactionTimestamp arrives in NukiTools.updateDevice(), invalidate the cached ringState entry so the event is written through. This is deliberately scoped to an actual new ring, so it cannot cause repeated writes on regular polling cycles, and it leaves every other state untouched.

Adds a small Library.invalidateDeviceState() helper for that purpose, mirroring the existing resetStates().

Notes

  • No behaviour change unless a genuinely new ring timestamp arrives.
  • Verified against adapter 2.8.2 running on js-controller 7.2.2 (Nuki Opener via Web API), where the issue is reproducible.
  • I could not run the integration tests against real hardware; review of the timestamp comparison would be welcome.

🤖 Generated with Claude Code

The Opener's ring is an event, not a status: Nuki reports
`state.ringactionState = true` again for every ring while
`state.ringactionTimestamp` advances each time.

`Library._setValue()` deduplicates writes against its internal `_STATES`
cache, so the repeated `true` is swallowed and `state.ringState` is never
written again. Consumers subscribing to that state therefore miss every
ring after the first one -- e.g. a parcel service ringing shortly after
the postman produces no second notification.

The cache can also drift from the actual state: anything that writes
`ringState` from outside the adapter (a script resetting it to false, a
VIS widget, a manual change) leaves the adapter believing the value is
still `true`, which suppresses subsequent writes until the adapter is
restarted.

Fix: whenever a newer `ringactionTimestamp` arrives in `updateDevice()`,
invalidate the cached `ringState` entry so the event is written through.
This is scoped to an actual new ring, so it cannot cause repeated writes
on regular polling cycles.

Adds `Library.invalidateDeviceState()` for that purpose.

Co-Authored-By: Claude Opus 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