node-red-contrib-knx-ultimate 2.0.15 → 2.0.16
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,11 @@
|
|
|
6
6
|
|
|
7
7
|
# CHANGELOG
|
|
8
8
|
|
|
9
|
+
<p>
|
|
10
|
+
<b>Version 2.0.16</b> - June 2023<br/>
|
|
11
|
+
- HUE: CAUTION POSSIBLE BREAKING CHANGES TO THE HUE NODES. PLEASE BE AWARE THAT HUE NODES ARE STILL IN BETA<br/>
|
|
12
|
+
- Fixed issues with dimming in the hue button and hue tap dial nodes.<br/>
|
|
13
|
+
</p>
|
|
9
14
|
<p>
|
|
10
15
|
<b>Version 2.0.15</b> - June 2023<br/>
|
|
11
16
|
- HUE: CAUTION POSSIBLE BREAKING CHANGES TO THE HUE NODES. PLEASE BE AWARE THAT HUE NODES ARE STILL IN BETA<br/>
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
serverHue: { type: "hue-config", required: true },
|
|
9
9
|
name: { value: "" },
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
nameDim: { value: "" },
|
|
12
12
|
GArepeat: { value: "" },
|
|
13
13
|
dptrepeat: { value: "3.007" },
|
|
14
14
|
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
return i == aSearchWords.length;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
// DPT
|
|
76
|
+
// DPT Dim
|
|
77
77
|
// ########################
|
|
78
78
|
$.getJSON('knxUltimateDpts', (data) => {
|
|
79
79
|
data.forEach(dpt => {
|
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
sDevName = sDevName.substr(sDevName.indexOf(")") + 1).trim();
|
|
113
113
|
} catch (error) {
|
|
114
114
|
}
|
|
115
|
-
$('#node-input-
|
|
115
|
+
$('#node-input-nameDim').val(sDevName);
|
|
116
116
|
var optVal = $("#node-input-dptrepeat option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
|
|
117
117
|
// Select the option value
|
|
118
118
|
$("#node-input-dptrepeat").val(optVal);
|
|
@@ -382,8 +382,8 @@
|
|
|
382
382
|
<label for="node-input-dptrepeat" style="width:40px; margin-left: 0px; text-align: right;">DPT</label>
|
|
383
383
|
<select id="node-input-dptrepeat" style="width:140px;"></select>
|
|
384
384
|
|
|
385
|
-
<label for="node-input-
|
|
386
|
-
<input type="text" id="node-input-
|
|
385
|
+
<label for="node-input-nameDim" style="width:50px; margin-left: 0px; text-align: right;">Name</label>
|
|
386
|
+
<input type="text" id="node-input-nameDim" style="width:200px;margin-left: 5px; text-align: left;">
|
|
387
387
|
</div>
|
|
388
388
|
<br/>
|
|
389
389
|
<br/>
|
|
@@ -433,7 +433,7 @@ This allows the internal logic to be aware of external devices, like wall switch
|
|
|
433
433
|
|--|--|
|
|
434
434
|
| Switch | As soon as you quickly press and release your HUE button, this event fires |
|
|
435
435
|
| Switch Status | To allow internal logic to take care of the external KNX devices, for example an external wall switch, you should set this group address |
|
|
436
|
-
|
|
|
436
|
+
| Dim | This event is used either to send DIM (increase/decrease) or true/false commands to the KNX group address |
|
|
437
437
|
| Toggle values | Enable or disable toggling values. If enabled, all values toggles, otherwise, all values are sent as *true* or *increase dim*, to the selected KNX group address |
|
|
438
438
|
|
|
439
439
|
### Outputs
|
|
@@ -24,8 +24,8 @@ module.exports = function (RED) {
|
|
|
24
24
|
node.formatmultiplyvalue = 1
|
|
25
25
|
node.formatnegativevalue = 'leave'
|
|
26
26
|
node.formatdecimalsvalue = 2
|
|
27
|
-
node.
|
|
28
|
-
node.
|
|
27
|
+
node.short_releaseValue = false
|
|
28
|
+
node.isTimerDimStopRunning = false
|
|
29
29
|
|
|
30
30
|
// Used to call the status update from the config node.
|
|
31
31
|
node.setNodeStatus = ({ fill, shape, text, payload }) => {
|
|
@@ -39,7 +39,7 @@ module.exports = function (RED) {
|
|
|
39
39
|
switch (msg.knx.destination) {
|
|
40
40
|
case config.GAshort_releaseStatus:
|
|
41
41
|
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptshort_release))
|
|
42
|
-
node.
|
|
42
|
+
node.short_releaseValue = msg.payload
|
|
43
43
|
setTimeout(() => {
|
|
44
44
|
node.status({ fill: 'blue', shape: 'dot', text: 'Updated Switch ' + msg.knx.destination + ' ' + JSON.stringify(msg.payload) + ' (' + new Date().getDate() + ', ' + new Date().toLocaleTimeString() + ')' })
|
|
45
45
|
}, 500)
|
|
@@ -63,61 +63,84 @@ module.exports = function (RED) {
|
|
|
63
63
|
try {
|
|
64
64
|
if (_event.id === config.hueDevice) {
|
|
65
65
|
const knxMsgPayload = {}
|
|
66
|
+
let flowMsgPayload = true
|
|
66
67
|
// Handling events with toggles
|
|
68
|
+
// KNX Dimming reminder tips
|
|
69
|
+
// { decr_incr: 1, data: 1 } : Start increasing until { decr_incr: 0, data: 0 } is received.
|
|
70
|
+
// { decr_incr: 0, data: 1 } : Start decreasing until { decr_incr: 0, data: 0 } is received.
|
|
67
71
|
switch (_event.button.last_event) {
|
|
68
72
|
case 'initial_press':
|
|
69
73
|
if (node.initial_pressValue === undefined) node.initial_pressValue = false
|
|
70
|
-
|
|
71
|
-
|
|
74
|
+
node.initial_pressValue = config.toggleValues ? !node.initial_pressValue : true
|
|
75
|
+
flowMsgPayload = node.initial_pressValue
|
|
72
76
|
break
|
|
73
77
|
case 'long_release':
|
|
74
|
-
|
|
75
|
-
config.toggleValues ? node.long_releaseValue = !node.long_releaseValue : node.long_releaseValue = true
|
|
76
|
-
knxMsgPayload.payload = node.long_releaseValue
|
|
78
|
+
flowMsgPayload = node.long_pressValue
|
|
77
79
|
break
|
|
78
80
|
case 'double_short_release':
|
|
79
81
|
if (node.double_short_releaseValue === undefined) node.double_short_releaseValue = false
|
|
80
|
-
|
|
81
|
-
|
|
82
|
+
node.double_short_releaseValue = config.toggleValues ? !node.double_short_releaseValue : true
|
|
83
|
+
flowMsgPayload = node.double_short_releaseValue
|
|
82
84
|
break
|
|
83
85
|
case 'long_press':
|
|
84
86
|
if (node.long_pressValue === undefined) node.long_pressValue = false
|
|
85
|
-
|
|
86
|
-
|
|
87
|
+
node.long_pressValue = config.toggleValues ? !node.long_pressValue : true
|
|
88
|
+
flowMsgPayload = node.long_pressValue
|
|
87
89
|
break
|
|
88
90
|
case 'short_release':
|
|
91
|
+
node.short_releaseValue = config.toggleValues ? !node.short_releaseValue : true
|
|
92
|
+
flowMsgPayload = node.short_releaseValue
|
|
89
93
|
knxMsgPayload.topic = config.GAshort_release
|
|
90
94
|
knxMsgPayload.dpt = config.dptshort_release
|
|
91
|
-
|
|
92
|
-
knxMsgPayload.payload = node.toggleGAshort_release
|
|
93
|
-
node.status({ fill: 'green', shape: 'dot', text: 'HUE->KNX ' + _event.button.last_event + ' ' + JSON.stringify(knxMsgPayload.payload) + ' (' + new Date().getDate() + ', ' + new Date().toLocaleTimeString() + ')' })
|
|
95
|
+
knxMsgPayload.payload = node.short_releaseValue
|
|
94
96
|
// Send to KNX bus
|
|
95
97
|
if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined) node.server.writeQueueAdd({ grpaddr: knxMsgPayload.topic, payload: knxMsgPayload.payload, dpt: knxMsgPayload.dpt, outputtype: 'write', nodecallerid: node.id })
|
|
98
|
+
if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined) node.status({ fill: 'green', shape: 'dot', text: 'HUE->KNX ' + _event.button.last_event + ' ' + JSON.stringify(knxMsgPayload.payload) + ' (' + new Date().getDate() + ', ' + new Date().toLocaleTimeString() + ')' })
|
|
96
99
|
break
|
|
97
100
|
case 'repeat':
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
101
|
+
flowMsgPayload = true
|
|
102
|
+
if (node.isTimerDimStopRunning === false) {
|
|
103
|
+
// Set KNX Dim up/down start
|
|
104
|
+
knxMsgPayload.topic = config.GArepeat
|
|
105
|
+
knxMsgPayload.dpt = config.dptrepeat
|
|
106
|
+
knxMsgPayload.payload = node.long_pressValue ? { decr_incr: 1, data: 3 } : { decr_incr: 0, data: 3 }
|
|
107
|
+
// Send to KNX bus
|
|
108
|
+
if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined) node.server.writeQueueAdd({ grpaddr: knxMsgPayload.topic, payload: knxMsgPayload.payload, dpt: knxMsgPayload.dpt, outputtype: 'write', nodecallerid: node.id })
|
|
109
|
+
if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined) node.status({ fill: 'green', shape: 'dot', text: 'HUE->KNX start Dim' + ' (' + new Date().getDate() + ', ' + new Date().toLocaleTimeString() + ')' })
|
|
110
|
+
}
|
|
111
|
+
node.startDimStopper(knxMsgPayload)
|
|
105
112
|
break
|
|
106
113
|
default:
|
|
107
114
|
break
|
|
108
115
|
}
|
|
109
116
|
|
|
110
117
|
// Setup the output msg
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
118
|
+
const flowMsg = {}
|
|
119
|
+
flowMsg.name = node.name
|
|
120
|
+
flowMsg.event = _event.button.last_event
|
|
121
|
+
flowMsg.rawEvent = _event
|
|
122
|
+
flowMsg.payload = flowMsgPayload
|
|
123
|
+
node.send(flowMsg)
|
|
115
124
|
}
|
|
116
125
|
} catch (error) {
|
|
117
126
|
node.status({ fill: 'red', shape: 'dot', text: 'HUE->KNX error ' + error.message + ' (' + new Date().getDate() + ', ' + new Date().toLocaleTimeString() + ')' })
|
|
118
127
|
}
|
|
119
128
|
}
|
|
120
129
|
|
|
130
|
+
// Timer to stop the dimming sequence
|
|
131
|
+
node.startDimStopper = function (knxMsgPayload) {
|
|
132
|
+
if (node.timerDimStop !== undefined) clearInterval(node.timerDimStop)
|
|
133
|
+
node.isTimerDimStopRunning = true
|
|
134
|
+
node.timerDimStop = setTimeout(() => {
|
|
135
|
+
// KNX Stop DIM
|
|
136
|
+
knxMsgPayload.payload = { decr_incr: 0, data: 0 } // Payload for the output msg
|
|
137
|
+
// Send to KNX bus
|
|
138
|
+
if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined) node.server.writeQueueAdd({ grpaddr: knxMsgPayload.topic, payload: knxMsgPayload.payload, dpt: knxMsgPayload.dpt, outputtype: 'write', nodecallerid: node.id })
|
|
139
|
+
if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined) node.status({ fill: 'green', shape: 'dot', text: 'HUE->KNX Stop DIM' + ' (' + new Date().getDate() + ', ' + new Date().toLocaleTimeString() + ')' })
|
|
140
|
+
node.isTimerDimStopRunning = false
|
|
141
|
+
}, 700);
|
|
142
|
+
}
|
|
143
|
+
|
|
121
144
|
// On each deploy, unsubscribe+resubscribe
|
|
122
145
|
if (node.server) {
|
|
123
146
|
node.server.removeClient(node)
|
|
@@ -69,9 +69,16 @@ module.exports = function (RED) {
|
|
|
69
69
|
node.serverHue.hueManager.setLightState(config.hueDevice, state)
|
|
70
70
|
break
|
|
71
71
|
case config.GALightDIM:
|
|
72
|
+
// { decr_incr: 1, data: 1 } : Start increasing until { decr_incr: 0, data: 0 } is received.
|
|
73
|
+
// { decr_incr: 0, data: 1 } : Start decreasing until { decr_incr: 0, data: 0 } is received.
|
|
72
74
|
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightDIM))
|
|
73
|
-
|
|
74
|
-
|
|
75
|
+
if (msg.payload.data > 0) {
|
|
76
|
+
let dimDirection = 'down'
|
|
77
|
+
dimDirection = msg.payload.decr_incr === 1 ? 'up' : 'down'
|
|
78
|
+
node.startDim(dimDirection)
|
|
79
|
+
} else {
|
|
80
|
+
node.startDim('stop')
|
|
81
|
+
}
|
|
75
82
|
break
|
|
76
83
|
case config.GALightBrightness:
|
|
77
84
|
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightBrightness))
|
|
@@ -94,6 +101,31 @@ module.exports = function (RED) {
|
|
|
94
101
|
node.status({ fill: 'red', shape: 'dot', text: 'KNX->HUE error ' + error.message + ' (' + new Date().getDate() + ', ' + new Date().toLocaleTimeString() + ')' })
|
|
95
102
|
}
|
|
96
103
|
}
|
|
104
|
+
// Start dimming
|
|
105
|
+
node.timerDim = undefined
|
|
106
|
+
node.dimDirection = {}
|
|
107
|
+
node.timeoutDim = 0
|
|
108
|
+
node.startDim = function (_direction) {
|
|
109
|
+
clearInterval(node.timerDim)
|
|
110
|
+
if (_direction === "stop") return
|
|
111
|
+
switch (_direction) {
|
|
112
|
+
case 'up':
|
|
113
|
+
node.dimDirection = { dimming_delta: { action: 'up', brightness_delta: 5 } }
|
|
114
|
+
break
|
|
115
|
+
case 'down':
|
|
116
|
+
node.dimDirection = { dimming_delta: { action: 'down', brightness_delta: 5 } }
|
|
117
|
+
break
|
|
118
|
+
default:
|
|
119
|
+
break
|
|
120
|
+
}
|
|
121
|
+
node.timerDim = setInterval(() => {
|
|
122
|
+
node.timeoutDim += 1
|
|
123
|
+
if (node.timeoutDim > 100) { node.timeoutDim = 0; clearInterval(node.timerDim) }
|
|
124
|
+
node.serverHue.hueManager.setLightState(config.hueDevice, node.dimDirection)
|
|
125
|
+
}, 50);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
|
|
97
129
|
|
|
98
130
|
node.handleSendHUE = _event => {
|
|
99
131
|
try {
|
|
@@ -39,6 +39,7 @@ module.exports = function (RED) {
|
|
|
39
39
|
node.formatnegativevalue = 'leave'
|
|
40
40
|
node.formatdecimalsvalue = 2
|
|
41
41
|
node.brightnessState = 0
|
|
42
|
+
node.isTimerDimStopRunning = false
|
|
42
43
|
|
|
43
44
|
// Read the state of the light and store it in the holding object
|
|
44
45
|
try {
|
|
@@ -63,9 +64,16 @@ module.exports = function (RED) {
|
|
|
63
64
|
const knxMsgPayload = {}
|
|
64
65
|
knxMsgPayload.topic = config.GArepeat
|
|
65
66
|
knxMsgPayload.dpt = config.dptrepeat
|
|
67
|
+
|
|
66
68
|
if (_event.relative_rotary.last_event.rotation.direction === 'clock_wise') {
|
|
67
69
|
if (knxMsgPayload.dpt.startsWith('3.007')) {
|
|
68
|
-
|
|
70
|
+
if (node.isTimerDimStopRunning === false) {
|
|
71
|
+
// Set KNX Dim up/down start
|
|
72
|
+
knxMsgPayload.payload = { decr_incr: 1, data: 3 } // Send to KNX bus
|
|
73
|
+
if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined) node.server.writeQueueAdd({ grpaddr: knxMsgPayload.topic, payload: knxMsgPayload.payload, dpt: knxMsgPayload.dpt, outputtype: 'write', nodecallerid: node.id })
|
|
74
|
+
if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined) node.status({ fill: 'green', shape: 'dot', text: 'HUE->KNX start Dim' + ' (' + new Date().getDate() + ', ' + new Date().toLocaleTimeString() + ')' })
|
|
75
|
+
}
|
|
76
|
+
node.startDimStopper(knxMsgPayload)
|
|
69
77
|
} else if (knxMsgPayload.dpt.startsWith('5.001')) {
|
|
70
78
|
//0 – maximum: 32767
|
|
71
79
|
node.brightnessState < 100 ? node.brightnessState += 20 : node.brightnessState = 100
|
|
@@ -73,17 +81,19 @@ module.exports = function (RED) {
|
|
|
73
81
|
}
|
|
74
82
|
} else if (_event.relative_rotary.last_event.rotation.direction === 'counter_clock_wise') {
|
|
75
83
|
if (knxMsgPayload.dpt.startsWith('3.007')) {
|
|
76
|
-
|
|
84
|
+
if (node.isTimerDimStopRunning === false) {
|
|
85
|
+
// Set KNX Dim up/down start
|
|
86
|
+
knxMsgPayload.payload = { decr_incr: 0, data: 3 } // Send to KNX bus
|
|
87
|
+
if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined) node.server.writeQueueAdd({ grpaddr: knxMsgPayload.topic, payload: knxMsgPayload.payload, dpt: knxMsgPayload.dpt, outputtype: 'write', nodecallerid: node.id })
|
|
88
|
+
if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined) node.status({ fill: 'green', shape: 'dot', text: 'HUE->KNX start Dim' + ' (' + new Date().getDate() + ', ' + new Date().toLocaleTimeString() + ')' })
|
|
89
|
+
}
|
|
90
|
+
node.startDimStopper(knxMsgPayload)
|
|
77
91
|
} else if (knxMsgPayload.dpt.startsWith('5.001')) {
|
|
78
92
|
node.brightnessState > 0 ? node.brightnessState -= 20 : node.brightnessState = 0
|
|
79
93
|
knxMsgPayload.payload = node.brightnessState
|
|
80
94
|
}
|
|
81
95
|
}
|
|
82
96
|
|
|
83
|
-
// Send to KNX bus
|
|
84
|
-
if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined) node.server.writeQueueAdd({ grpaddr: knxMsgPayload.topic, payload: knxMsgPayload.payload, dpt: knxMsgPayload.dpt, outputtype: 'write', nodecallerid: node.id })
|
|
85
|
-
node.status({ fill: 'green', shape: 'dot', text: 'HUE->KNX ' + JSON.stringify(knxMsgPayload.payload) + ' (' + new Date().getDate() + ', ' + new Date().toLocaleTimeString() + ')' })
|
|
86
|
-
|
|
87
97
|
// Setup the output msg
|
|
88
98
|
knxMsgPayload.name = node.name
|
|
89
99
|
knxMsgPayload.event = 'rotation ' + _event.relative_rotary.last_event.rotation.direction
|
|
@@ -95,6 +105,20 @@ module.exports = function (RED) {
|
|
|
95
105
|
}
|
|
96
106
|
}
|
|
97
107
|
|
|
108
|
+
// Timer to stop the dimming sequence
|
|
109
|
+
node.startDimStopper = function (knxMsgPayload) {
|
|
110
|
+
if (node.timerDimStop !== undefined) clearInterval(node.timerDimStop)
|
|
111
|
+
node.isTimerDimStopRunning = true
|
|
112
|
+
node.timerDimStop = setTimeout(() => {
|
|
113
|
+
// KNX Stop DIM
|
|
114
|
+
knxMsgPayload.payload = { decr_incr: 0, data: 0 } // Payload for the output msg
|
|
115
|
+
// Send to KNX bus
|
|
116
|
+
if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined) node.server.writeQueueAdd({ grpaddr: knxMsgPayload.topic, payload: knxMsgPayload.payload, dpt: knxMsgPayload.dpt, outputtype: 'write', nodecallerid: node.id })
|
|
117
|
+
if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined) node.status({ fill: 'green', shape: 'dot', text: 'HUE->KNX Stop DIM' + ' (' + new Date().getDate() + ', ' + new Date().toLocaleTimeString() + ')' })
|
|
118
|
+
node.isTimerDimStopRunning = false
|
|
119
|
+
}, 500);
|
|
120
|
+
}
|
|
121
|
+
|
|
98
122
|
// On each deploy, unsubscribe+resubscribe
|
|
99
123
|
if (node.server) {
|
|
100
124
|
node.server.removeClient(node)
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"engines": {
|
|
4
4
|
"node": ">=14.0.0"
|
|
5
5
|
},
|
|
6
|
-
"version": "2.0.
|
|
6
|
+
"version": "2.0.16",
|
|
7
7
|
"description": "Control your KNX intallation via Node-Red! Single Node KNX IN/OUT with optional ETS group address importer. Easy to use and highly configurable. With integrated Philips HUE devices handling.",
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"mkdirp": "1.0.4",
|