node-red-contrib-knx-ultimate 4.3.23 → 4.3.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -6,6 +6,10 @@
6
6
 
7
7
  # CHANGELOG
8
8
 
9
+ **Version 4.3.24** - June 2026<br/>
10
+
11
+ - Hue **Contact Sensor** and **Motion** nodes: fixed the state on the KNX bus getting stuck on a wrong value (e.g. a contact sensor showing **closed** while the door stayed open) after the Hue event-stream reconnected. The nodes now re-publish the authoritative state at startup and after every (re)connection, and ignore stale/out-of-order reports by checking the `contact_report.changed` / `motion_report.changed` timestamp. Closes [#514](https://github.com/Supergiovane/node-red-contrib-knx-ultimate/issues/514).<br/>
12
+
9
13
  **Version 4.3.23** - June 2026<br/>
10
14
 
11
15
  - Hue nodes: fixed the **help text** not appearing in the editor sidebar when selecting a node. The help is now declared inline in each node's main HTML file (sidebar reads help from there; the `locales/` files keep providing translations). Affected nodes: Light/Outlet, Area Motion, Battery, Button, Contact Sensor, Light Sensor, Motion, Scene, Tap Dial, Temperature Sensor, Zigbee Connectivity and Device Software Update. Also closed an unterminated template `<script>` tag in the Hue Light node.<br/>
@@ -23,7 +23,13 @@ module.exports = function (RED) {
23
23
  node.formatnegativevalue = 'leave'
24
24
  node.formatdecimalsvalue = 2
25
25
  node.hueDevice = config.hueDevice
26
- node.initializingAtStart = false
26
+ // Re-publish the authoritative contact state at startup and after every event-stream
27
+ // (re)connection. Without this, any contact_report event missed during an SSE reconnect
28
+ // gap leaves KNX stuck on the last value seen (see issue #514).
29
+ node.initializingAtStart = (config.readStatusAtStartup === undefined || config.readStatusAtStartup === 'yes')
30
+ // Timestamp (ms) of the last contact_report.changed we already applied to KNX. Used to
31
+ // ignore stale/out-of-order reports (e.g. replays after a reconnect).
32
+ node.lastContactChangedTs = undefined
27
33
 
28
34
  const pushStatus = (status) => {
29
35
  if (!status) return
@@ -94,6 +100,18 @@ module.exports = function (RED) {
94
100
  return
95
101
  }
96
102
 
103
+ // contact_report.state is always the real current state (per Hue API v2), and
104
+ // contact_report.changed is when it last changed. Ignore reports that are not newer
105
+ // than the last one applied, so stale/replayed events after an SSE reconnect can't
106
+ // flip KNX to a wrong state (issue #514).
107
+ const changedTs = _event.contact_report.changed !== undefined ? new Date(_event.contact_report.changed).getTime() : NaN
108
+ if (!Number.isNaN(changedTs)) {
109
+ if (node.lastContactChangedTs !== undefined && changedTs <= node.lastContactChangedTs) {
110
+ return
111
+ }
112
+ node.lastContactChangedTs = changedTs
113
+ }
114
+
97
115
  const knxMsgPayload = {}
98
116
  knxMsgPayload.topic = config.GAcontact
99
117
  knxMsgPayload.dpt = config.dptcontact
@@ -23,7 +23,13 @@ module.exports = function (RED) {
23
23
  node.formatnegativevalue = 'leave'
24
24
  node.formatdecimalsvalue = 2
25
25
  node.hueDevice = config.hueDevice
26
- node.initializingAtStart = false
26
+ // Re-publish the authoritative motion state at startup and after every event-stream
27
+ // (re)connection, so events missed during an SSE reconnect gap don't leave KNX stuck
28
+ // on a wrong value (same root cause as the contact sensor, issue #514).
29
+ node.initializingAtStart = (config.readStatusAtStartup === undefined || config.readStatusAtStartup === 'yes')
30
+ // Timestamp (ms) of the last motion_report.changed we already applied to KNX. Used to
31
+ // ignore stale/out-of-order reports (e.g. replays after a reconnect).
32
+ node.lastMotionChangedTs = undefined
27
33
  const pinsSetting = (config.enableNodePINS === undefined || config.enableNodePINS === 'yes' || config.enableNodePINS === true)
28
34
  node.enableNodePINS = pinsSetting ? 'yes' : 'no'
29
35
  node.outputs = pinsSetting ? 1 : 0
@@ -97,6 +103,18 @@ module.exports = function (RED) {
97
103
  try {
98
104
  if (_event.id === config.hueDevice) {
99
105
  if (!_event.hasOwnProperty('motion') || _event.motion.motion === undefined) return
106
+
107
+ // Ignore reports that are not newer than the last one applied, so stale/replayed
108
+ // events after an SSE reconnect can't push a wrong state to KNX (issue #514).
109
+ const motionChanged = _event.motion.motion_report !== undefined ? _event.motion.motion_report.changed : undefined
110
+ const changedTs = motionChanged !== undefined ? new Date(motionChanged).getTime() : NaN
111
+ if (!Number.isNaN(changedTs)) {
112
+ if (node.lastMotionChangedTs !== undefined && changedTs <= node.lastMotionChangedTs) {
113
+ return
114
+ }
115
+ node.lastMotionChangedTs = changedTs
116
+ }
117
+
100
118
  const knxMsgPayload = {}
101
119
  knxMsgPayload.topic = config.GAmotion
102
120
  knxMsgPayload.dpt = config.dptmotion
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "engines": {
4
4
  "node": ">=20.18.1"
5
5
  },
6
- "version": "4.3.23",
6
+ "version": "4.3.24",
7
7
  "description": "Control your KNX and KNX Secure intallation via Node-Red! A bunch of KNX nodes, with integrated Philips HUE control, ETS group address importer, KNX AI for diagnosticsand KNX routing between interfaces. Easy to use and highly configurable.",
8
8
  "files": [
9
9
  "nodes/",