node-red-contrib-knx-ultimate 4.3.1 → 4.3.3
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 +11 -0
- package/nodes/knxUltimate.html +22 -3
- package/nodes/knxUltimate.js +1 -1
- package/nodes/knxUltimateAI.html +215 -18
- package/nodes/knxUltimateAI.js +289 -70
- package/nodes/knxUltimateHueLight.js +807 -810
- package/nodes/knxUltimateLogger.js +3 -4
- package/nodes/knxUltimateMultiRouting.js +0 -1
- package/nodes/locales/de/knxUltimateAI.html +11 -0
- package/nodes/locales/de/knxUltimateAI.json +13 -2
- package/nodes/locales/en/knxUltimateAI.html +11 -0
- package/nodes/locales/en/knxUltimateAI.json +12 -3
- package/nodes/locales/es/knxUltimateAI.html +11 -0
- package/nodes/locales/es/knxUltimateAI.json +13 -2
- package/nodes/locales/fr/knxUltimateAI.html +11 -0
- package/nodes/locales/fr/knxUltimateAI.json +13 -2
- package/nodes/locales/it/knxUltimateAI.html +11 -0
- package/nodes/locales/it/knxUltimateAI.json +12 -3
- package/nodes/locales/zh-CN/knxUltimateAI.html +11 -0
- package/nodes/locales/zh-CN/knxUltimateAI.json +13 -2
- package/nodes/plugins/knxUltimateAI-vue/assets/app.js +3 -3
- package/package.json +1 -1
- package/resources/KNXSendSnippets.js +65 -49
|
@@ -2,297 +2,297 @@
|
|
|
2
2
|
/* eslint-disable camelcase */
|
|
3
3
|
/* eslint-disable max-len */
|
|
4
4
|
/* eslint-disable no-lonely-if */
|
|
5
|
-
const cloneDeep = require(
|
|
6
|
-
const dptlib = require('knxultimate').dptlib
|
|
7
|
-
const hueColorConverter = require(
|
|
5
|
+
const cloneDeep = require('lodash/cloneDeep')
|
|
6
|
+
const dptlib = require('knxultimate').dptlib
|
|
7
|
+
const hueColorConverter = require('./utils/colorManipulators/hueColorConverter')
|
|
8
8
|
|
|
9
9
|
module.exports = function (RED) {
|
|
10
|
-
function knxUltimateHueLight(config) {
|
|
11
|
-
RED.nodes.createNode(this, config)
|
|
12
|
-
const node = this
|
|
13
|
-
node.serverKNX = RED.nodes.getNode(config.server) || undefined
|
|
14
|
-
node.serverHue = RED.nodes.getNode(config.serverHue) || undefined
|
|
10
|
+
function knxUltimateHueLight (config) {
|
|
11
|
+
RED.nodes.createNode(this, config)
|
|
12
|
+
const node = this
|
|
13
|
+
node.serverKNX = RED.nodes.getNode(config.server) || undefined
|
|
14
|
+
node.serverHue = RED.nodes.getNode(config.serverHue) || undefined
|
|
15
15
|
|
|
16
16
|
// Convert for backward compatibility
|
|
17
17
|
if (config.nameLightKelvinDIM === undefined) {
|
|
18
|
-
config.nameLightKelvinDIM = config.nameLightHSV
|
|
19
|
-
config.GALightKelvinDIM = config.GALightHSV
|
|
20
|
-
config.dptLightKelvinDIM = config.dptLightHSV
|
|
18
|
+
config.nameLightKelvinDIM = config.nameLightHSV
|
|
19
|
+
config.GALightKelvinDIM = config.GALightHSV
|
|
20
|
+
config.dptLightKelvinDIM = config.dptLightHSV
|
|
21
21
|
|
|
22
|
-
config.nameLightKelvinPercentage = config.nameLightHSVPercentage
|
|
23
|
-
config.GALightKelvinPercentage = config.GALightHSVPercentage
|
|
24
|
-
config.dptLightKelvinPercentage = config.dptLightHSVPercentage
|
|
22
|
+
config.nameLightKelvinPercentage = config.nameLightHSVPercentage
|
|
23
|
+
config.GALightKelvinPercentage = config.GALightHSVPercentage
|
|
24
|
+
config.dptLightKelvinPercentage = config.dptLightHSVPercentage
|
|
25
25
|
|
|
26
|
-
config.nameLightKelvinPercentageState = config.nameLightHSVState
|
|
27
|
-
config.GALightKelvinPercentageState = config.GALightHSVState
|
|
28
|
-
config.dptLightKelvinPercentageState = config.dptLightHSVState
|
|
26
|
+
config.nameLightKelvinPercentageState = config.nameLightHSVState
|
|
27
|
+
config.GALightKelvinPercentageState = config.GALightHSVState
|
|
28
|
+
config.dptLightKelvinPercentageState = config.dptLightHSVState
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
node.topic = node.name
|
|
32
|
-
node.name = config.name === undefined ?
|
|
33
|
-
node.outputtopic = node.name
|
|
34
|
-
node.dpt =
|
|
35
|
-
node.notifyreadrequest = true
|
|
36
|
-
node.notifyreadrequestalsorespondtobus =
|
|
37
|
-
node.notifyreadrequestalsorespondtobusdefaultvalueifnotinitialized =
|
|
38
|
-
node.notifyresponse = false
|
|
39
|
-
node.notifywrite = true
|
|
40
|
-
node.initialread = true
|
|
41
|
-
node.listenallga = true
|
|
42
|
-
node.outputtype =
|
|
43
|
-
node.outputRBE = 'false'
|
|
44
|
-
node.inputRBE = 'false'
|
|
45
|
-
node.currentPayload =
|
|
46
|
-
node.passthrough =
|
|
47
|
-
node.formatmultiplyvalue = 1
|
|
48
|
-
node.formatnegativevalue =
|
|
49
|
-
node.formatdecimalsvalue = 2
|
|
50
|
-
node.currentHUEDevice = undefined
|
|
51
|
-
node.HUEDeviceWhileDaytime = null
|
|
52
|
-
node.HUELightsBelongingToGroupWhileDaytime = null
|
|
53
|
-
node.DayTime = true
|
|
54
|
-
node.isGrouped_light = config.hueDevice.split(
|
|
55
|
-
node.hueDevice = config.hueDevice.split(
|
|
56
|
-
node.initializingAtStart = (config.readStatusAtStartup === undefined || config.readStatusAtStartup ===
|
|
57
|
-
config.specifySwitchOnBrightness = (config.specifySwitchOnBrightness === undefined || config.specifySwitchOnBrightness === '') ?
|
|
58
|
-
config.specifySwitchOnBrightnessNightTime = (config.specifySwitchOnBrightnessNightTime === undefined || config.specifySwitchOnBrightnessNightTime === '') ?
|
|
59
|
-
config.colorAtSwitchOnDayTime = (config.colorAtSwitchOnDayTime === '' || config.colorAtSwitchOnDayTime === undefined) ? '{ "kelvin":3000, "brightness":100 }' : config.colorAtSwitchOnDayTime
|
|
60
|
-
config.colorAtSwitchOnNightTime = (config.colorAtSwitchOnNightTime === '' || config.colorAtSwitchOnNightTime === undefined) ? '{ "kelvin":2700, "brightness":20 }' : config.colorAtSwitchOnNightTime
|
|
61
|
-
config.colorAtSwitchOnDayTime = config.colorAtSwitchOnDayTime.replace(
|
|
62
|
-
config.colorAtSwitchOnNightTime = config.colorAtSwitchOnNightTime.replace(
|
|
63
|
-
config.dimSpeed = (config.dimSpeed === undefined || config.dimSpeed === '') ? 5000 : Number(config.dimSpeed)
|
|
64
|
-
config.HSVDimSpeed = (config.HSVDimSpeed === undefined || config.HSVDimSpeed === '') ? 5000 : Number(config.HSVDimSpeed)
|
|
65
|
-
config.invertDimTunableWhiteDirection = config.invertDimTunableWhiteDirection !== undefined
|
|
66
|
-
config.restoreDayMode = config.restoreDayMode === undefined ?
|
|
67
|
-
config.updateLocalStateFromKNXWrite = config.updateLocalStateFromKNXWrite === true || config.updateLocalStateFromKNXWrite ===
|
|
68
|
-
node.timerCheckForFastLightSwitch = null
|
|
69
|
-
config.invertDayNight = config.invertDayNight === undefined ? false : config.invertDayNight
|
|
70
|
-
node.HSVObject = null
|
|
31
|
+
node.topic = node.name
|
|
32
|
+
node.name = config.name === undefined ? 'Hue' : config.name
|
|
33
|
+
node.outputtopic = node.name
|
|
34
|
+
node.dpt = ''
|
|
35
|
+
node.notifyreadrequest = true
|
|
36
|
+
node.notifyreadrequestalsorespondtobus = 'false'
|
|
37
|
+
node.notifyreadrequestalsorespondtobusdefaultvalueifnotinitialized = ''
|
|
38
|
+
node.notifyresponse = false
|
|
39
|
+
node.notifywrite = true
|
|
40
|
+
node.initialread = true
|
|
41
|
+
node.listenallga = true // Don't remove
|
|
42
|
+
node.outputtype = 'write'
|
|
43
|
+
node.outputRBE = 'false' // Apply or not RBE to the output (Messages coming from flow)
|
|
44
|
+
node.inputRBE = 'false' // Apply or not RBE to the input (Messages coming from BUS)
|
|
45
|
+
node.currentPayload = '' // Current value for the RBE input and for the .previouspayload msg
|
|
46
|
+
node.passthrough = 'no'
|
|
47
|
+
node.formatmultiplyvalue = 1
|
|
48
|
+
node.formatnegativevalue = 'leave'
|
|
49
|
+
node.formatdecimalsvalue = 2
|
|
50
|
+
node.currentHUEDevice = undefined // At start, this value is filled by a call to HUE api. It stores a value representing the current light status.
|
|
51
|
+
node.HUEDeviceWhileDaytime = null// This retains the HUE device status while daytime, to be restored after nighttime elapsed.
|
|
52
|
+
node.HUELightsBelongingToGroupWhileDaytime = null // Array contains all light belonging to the grouped_light (if grouped_light is selected)
|
|
53
|
+
node.DayTime = true
|
|
54
|
+
node.isGrouped_light = config.hueDevice.split('#')[1] === 'grouped_light'
|
|
55
|
+
node.hueDevice = config.hueDevice.split('#')[0]
|
|
56
|
+
node.initializingAtStart = (config.readStatusAtStartup === undefined || config.readStatusAtStartup === 'yes')
|
|
57
|
+
config.specifySwitchOnBrightness = (config.specifySwitchOnBrightness === undefined || config.specifySwitchOnBrightness === '') ? 'temperature' : config.specifySwitchOnBrightness
|
|
58
|
+
config.specifySwitchOnBrightnessNightTime = (config.specifySwitchOnBrightnessNightTime === undefined || config.specifySwitchOnBrightnessNightTime === '') ? 'no' : config.specifySwitchOnBrightnessNightTime
|
|
59
|
+
config.colorAtSwitchOnDayTime = (config.colorAtSwitchOnDayTime === '' || config.colorAtSwitchOnDayTime === undefined) ? '{ "kelvin":3000, "brightness":100 }' : config.colorAtSwitchOnDayTime
|
|
60
|
+
config.colorAtSwitchOnNightTime = (config.colorAtSwitchOnNightTime === '' || config.colorAtSwitchOnNightTime === undefined) ? '{ "kelvin":2700, "brightness":20 }' : config.colorAtSwitchOnNightTime
|
|
61
|
+
config.colorAtSwitchOnDayTime = config.colorAtSwitchOnDayTime.replace('geen', 'green')
|
|
62
|
+
config.colorAtSwitchOnNightTime = config.colorAtSwitchOnNightTime.replace('geen', 'green')
|
|
63
|
+
config.dimSpeed = (config.dimSpeed === undefined || config.dimSpeed === '') ? 5000 : Number(config.dimSpeed)
|
|
64
|
+
config.HSVDimSpeed = (config.HSVDimSpeed === undefined || config.HSVDimSpeed === '') ? 5000 : Number(config.HSVDimSpeed)
|
|
65
|
+
config.invertDimTunableWhiteDirection = config.invertDimTunableWhiteDirection !== undefined
|
|
66
|
+
config.restoreDayMode = config.restoreDayMode === undefined ? 'no' : config.restoreDayMode // no or setDayByFastSwitchLightSingle or setDayByFastSwitchLightALL
|
|
67
|
+
config.updateLocalStateFromKNXWrite = config.updateLocalStateFromKNXWrite === true || config.updateLocalStateFromKNXWrite === 'true' // Starting from v 4.1.31
|
|
68
|
+
node.timerCheckForFastLightSwitch = null
|
|
69
|
+
config.invertDayNight = config.invertDayNight === undefined ? false : config.invertDayNight
|
|
70
|
+
node.HSVObject = null // { h, s, v };// Store the current light calculated HSV
|
|
71
71
|
|
|
72
72
|
// Transform HEX in RGB and stringified json in json oblects.
|
|
73
|
-
if (config.colorAtSwitchOnDayTime.indexOf(
|
|
73
|
+
if (config.colorAtSwitchOnDayTime.indexOf('#') !== -1) {
|
|
74
74
|
// Transform to rgb.
|
|
75
75
|
try {
|
|
76
|
-
config.colorAtSwitchOnDayTime = hueColorConverter.ColorConverter.hexRgb(config.colorAtSwitchOnDayTime.replace(
|
|
76
|
+
config.colorAtSwitchOnDayTime = hueColorConverter.ColorConverter.hexRgb(config.colorAtSwitchOnDayTime.replace('#', ''))
|
|
77
77
|
} catch (error) {
|
|
78
|
-
config.colorAtSwitchOnDayTime = { kelvin: 3000, brightness: 100 }
|
|
78
|
+
config.colorAtSwitchOnDayTime = { kelvin: 3000, brightness: 100 }
|
|
79
79
|
}
|
|
80
80
|
} else {
|
|
81
81
|
try {
|
|
82
|
-
config.colorAtSwitchOnDayTime = JSON.parse(config.colorAtSwitchOnDayTime)
|
|
82
|
+
config.colorAtSwitchOnDayTime = JSON.parse(config.colorAtSwitchOnDayTime)
|
|
83
83
|
} catch (error) {
|
|
84
|
-
RED.log.error(`knxUltimateHueLight: config.colorAtSwitchOnDayTime = JSON.parse(config.colorAtSwitchOnDayTime): ${error.message} : ${error.stack ||
|
|
85
|
-
config.colorAtSwitchOnDayTime =
|
|
84
|
+
RED.log.error(`knxUltimateHueLight: config.colorAtSwitchOnDayTime = JSON.parse(config.colorAtSwitchOnDayTime): ${error.message} : ${error.stack || ''} `)
|
|
85
|
+
config.colorAtSwitchOnDayTime = ''
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
// Same thing, but with night color
|
|
89
|
-
if (config.colorAtSwitchOnNightTime.indexOf(
|
|
89
|
+
if (config.colorAtSwitchOnNightTime.indexOf('#') !== -1) {
|
|
90
90
|
// Transform to rgb.
|
|
91
91
|
try {
|
|
92
|
-
config.colorAtSwitchOnNightTime = hueColorConverter.ColorConverter.hexRgb(config.colorAtSwitchOnNightTime.replace(
|
|
92
|
+
config.colorAtSwitchOnNightTime = hueColorConverter.ColorConverter.hexRgb(config.colorAtSwitchOnNightTime.replace('#', ''))
|
|
93
93
|
} catch (error) {
|
|
94
|
-
config.colorAtSwitchOnNightTime = { kelvin: 2700, brightness: 20 }
|
|
94
|
+
config.colorAtSwitchOnNightTime = { kelvin: 2700, brightness: 20 }
|
|
95
95
|
}
|
|
96
96
|
} else {
|
|
97
97
|
try {
|
|
98
|
-
config.colorAtSwitchOnNightTime = JSON.parse(config.colorAtSwitchOnNightTime)
|
|
98
|
+
config.colorAtSwitchOnNightTime = JSON.parse(config.colorAtSwitchOnNightTime)
|
|
99
99
|
} catch (error) {
|
|
100
|
-
RED.log.error(`knxUltimateHueLight: config.colorAtSwitchOnDayTime = JSON.parse(config.colorAtSwitchOnNightTime): ${error.message} : ${error.stack ||
|
|
101
|
-
config.colorAtSwitchOnNightTime =
|
|
100
|
+
RED.log.error(`knxUltimateHueLight: config.colorAtSwitchOnDayTime = JSON.parse(config.colorAtSwitchOnNightTime): ${error.message} : ${error.stack || ''} `)
|
|
101
|
+
config.colorAtSwitchOnNightTime = ''
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
const formatTs = (date) => {
|
|
106
|
-
const d = date instanceof Date ? date : new Date(date)
|
|
107
|
-
const provider = node.serverKNX
|
|
108
|
-
if (provider && typeof provider.formatStatusTimestamp ===
|
|
109
|
-
return `${d.getDate()}, ${d.toLocaleTimeString()}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
node.syncCurrentHUEDeviceFromKNXState = function syncCurrentHUEDeviceFromKNXState(_state) { // Starting from v 4.1.31
|
|
113
|
-
if (config.updateLocalStateFromKNXWrite !== true) return
|
|
114
|
-
if (_state === undefined || _state === null || typeof _state !==
|
|
115
|
-
if (node.currentHUEDevice === undefined || node.currentHUEDevice === null) return
|
|
116
|
-
if (_state.on !== undefined && typeof _state.on.on ===
|
|
117
|
-
if (node.currentHUEDevice.on === undefined || node.currentHUEDevice.on === null) node.currentHUEDevice.on = {}
|
|
118
|
-
node.currentHUEDevice.on.on = _state.on.on
|
|
106
|
+
const d = date instanceof Date ? date : new Date(date)
|
|
107
|
+
const provider = node.serverKNX
|
|
108
|
+
if (provider && typeof provider.formatStatusTimestamp === 'function') return provider.formatStatusTimestamp(d)
|
|
109
|
+
return `${d.getDate()}, ${d.toLocaleTimeString()}`
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
node.syncCurrentHUEDeviceFromKNXState = function syncCurrentHUEDeviceFromKNXState (_state) { // Starting from v 4.1.31
|
|
113
|
+
if (config.updateLocalStateFromKNXWrite !== true) return // Starting from v 4.1.31
|
|
114
|
+
if (_state === undefined || _state === null || typeof _state !== 'object') return // Starting from v 4.1.31
|
|
115
|
+
if (node.currentHUEDevice === undefined || node.currentHUEDevice === null) return // Starting from v 4.1.31
|
|
116
|
+
if (_state.on !== undefined && typeof _state.on.on === 'boolean') { // Starting from v 4.1.31
|
|
117
|
+
if (node.currentHUEDevice.on === undefined || node.currentHUEDevice.on === null) node.currentHUEDevice.on = {} // Starting from v 4.1.31
|
|
118
|
+
node.currentHUEDevice.on.on = _state.on.on // Starting from v 4.1.31
|
|
119
119
|
} // Starting from v 4.1.31
|
|
120
120
|
if (_state.dimming !== undefined && _state.dimming !== null && _state.dimming.brightness !== undefined) { // Starting from v 4.1.31
|
|
121
|
-
if (node.currentHUEDevice.dimming === undefined || node.currentHUEDevice.dimming === null) node.currentHUEDevice.dimming = {}
|
|
122
|
-
node.currentHUEDevice.dimming.brightness = _state.dimming.brightness
|
|
121
|
+
if (node.currentHUEDevice.dimming === undefined || node.currentHUEDevice.dimming === null) node.currentHUEDevice.dimming = {} // Starting from v 4.1.31
|
|
122
|
+
node.currentHUEDevice.dimming.brightness = _state.dimming.brightness // Starting from v 4.1.31
|
|
123
123
|
} // Starting from v 4.1.31
|
|
124
124
|
if (_state.color !== undefined && _state.color !== null && _state.color.xy !== undefined) { // Starting from v 4.1.31
|
|
125
|
-
if (node.currentHUEDevice.color === undefined || node.currentHUEDevice.color === null) node.currentHUEDevice.color = {}
|
|
126
|
-
node.currentHUEDevice.color.xy = cloneDeep(_state.color.xy)
|
|
125
|
+
if (node.currentHUEDevice.color === undefined || node.currentHUEDevice.color === null) node.currentHUEDevice.color = {} // Starting from v 4.1.31
|
|
126
|
+
node.currentHUEDevice.color.xy = cloneDeep(_state.color.xy) // Starting from v 4.1.31
|
|
127
127
|
} // Starting from v 4.1.31
|
|
128
128
|
if (_state.color_temperature !== undefined && _state.color_temperature !== null && _state.color_temperature.mirek !== undefined) { // Starting from v 4.1.31
|
|
129
|
-
if (node.currentHUEDevice.color_temperature === undefined || node.currentHUEDevice.color_temperature === null) node.currentHUEDevice.color_temperature = {}
|
|
130
|
-
node.currentHUEDevice.color_temperature.mirek = _state.color_temperature.mirek
|
|
129
|
+
if (node.currentHUEDevice.color_temperature === undefined || node.currentHUEDevice.color_temperature === null) node.currentHUEDevice.color_temperature = {} // Starting from v 4.1.31
|
|
130
|
+
node.currentHUEDevice.color_temperature.mirek = _state.color_temperature.mirek // Starting from v 4.1.31
|
|
131
131
|
} // Starting from v 4.1.31
|
|
132
|
-
}
|
|
132
|
+
} // Starting from v 4.1.31
|
|
133
133
|
|
|
134
134
|
// Used to call the status update from the config node.
|
|
135
135
|
node.setNodeStatus = ({
|
|
136
|
-
fill, shape, text, payload
|
|
136
|
+
fill, shape, text, payload
|
|
137
137
|
}) => {
|
|
138
138
|
try {
|
|
139
|
-
if (node.currentHUEDevice?.on?.on === true) { fill =
|
|
140
|
-
if (payload === undefined) payload = ''
|
|
141
|
-
const dDate = new Date()
|
|
142
|
-
payload = typeof payload ===
|
|
143
|
-
node.sKNXNodeStatusText = `|KNX: ${text} ${payload} (${formatTs(dDate)})
|
|
144
|
-
node.status({ fill, shape, text: (node.sHUENodeStatusText || '') + ' ' + (node.sKNXNodeStatusText || '') })
|
|
139
|
+
if (node.currentHUEDevice?.on?.on === true) { fill = 'blue'; shape = 'dot' } else { fill = 'blue'; shape = 'ring' };
|
|
140
|
+
if (payload === undefined) payload = ''
|
|
141
|
+
const dDate = new Date()
|
|
142
|
+
payload = typeof payload === 'object' ? JSON.stringify(payload) : payload.toString()
|
|
143
|
+
node.sKNXNodeStatusText = `|KNX: ${text} ${payload} (${formatTs(dDate)})`
|
|
144
|
+
node.status({ fill, shape, text: (node.sHUENodeStatusText || '') + ' ' + (node.sKNXNodeStatusText || '') })
|
|
145
145
|
} catch (error) { }
|
|
146
|
-
}
|
|
146
|
+
}
|
|
147
147
|
// Used to call the status update from the HUE config node.
|
|
148
148
|
node.setNodeStatusHue = ({ fill, shape, text, payload }) => {
|
|
149
149
|
try {
|
|
150
|
-
if (node.currentHUEDevice?.on?.on === true) { fill =
|
|
151
|
-
if (payload === undefined) payload = ''
|
|
152
|
-
const dDate = new Date()
|
|
153
|
-
payload = typeof payload ===
|
|
154
|
-
node.sHUENodeStatusText = `|HUE: ${text} ${payload} (${formatTs(dDate)})
|
|
155
|
-
node.status({ fill, shape, text: node.sHUENodeStatusText + ' ' + (node.sKNXNodeStatusText || '') })
|
|
150
|
+
if (node.currentHUEDevice?.on?.on === true) { fill = 'blue'; shape = 'dot' } else { fill = 'blue'; shape = 'ring' };
|
|
151
|
+
if (payload === undefined) payload = ''
|
|
152
|
+
const dDate = new Date()
|
|
153
|
+
payload = typeof payload === 'object' ? JSON.stringify(payload) : payload.toString()
|
|
154
|
+
node.sHUENodeStatusText = `|HUE: ${text} ${payload} (${formatTs(dDate)})`
|
|
155
|
+
node.status({ fill, shape, text: node.sHUENodeStatusText + ' ' + (node.sKNXNodeStatusText || '') })
|
|
156
156
|
} catch (error) { }
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
node.writeHueState = function writeHueState(_state) {
|
|
160
|
-
const defaultOperation = node.isGrouped_light === false ?
|
|
161
|
-
const isGroupedLightOff = node.isGrouped_light === true && node.currentHUEDevice?.on?.on === false
|
|
162
|
-
const stateKeys = _state && typeof _state ===
|
|
163
|
-
const presetKeys = [
|
|
164
|
-
const actionableKeys = [
|
|
165
|
-
const hasActionablePayload = stateKeys.some((key) => actionableKeys.includes(key))
|
|
166
|
-
const mustPresetGroupedLightChildren = isGroupedLightOff
|
|
167
|
-
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
node.writeHueState = function writeHueState (_state) {
|
|
160
|
+
const defaultOperation = node.isGrouped_light === false ? 'setLight' : 'setGroupedLight'
|
|
161
|
+
const isGroupedLightOff = node.isGrouped_light === true && node.currentHUEDevice?.on?.on === false
|
|
162
|
+
const stateKeys = _state && typeof _state === 'object' ? Object.keys(_state) : []
|
|
163
|
+
const presetKeys = ['dimming', 'color', 'color_temperature', 'gradient']
|
|
164
|
+
const actionableKeys = ['dimming', ...presetKeys]
|
|
165
|
+
const hasActionablePayload = stateKeys.some((key) => actionableKeys.includes(key))
|
|
166
|
+
const mustPresetGroupedLightChildren = isGroupedLightOff &&
|
|
167
|
+
stateKeys.some((key) => presetKeys.includes(key))
|
|
168
168
|
|
|
169
169
|
if (!mustPresetGroupedLightChildren) {
|
|
170
|
-
node.serverHue.hueManager.writeHueQueueAdd(node.hueDevice, _state, defaultOperation)
|
|
171
|
-
return
|
|
170
|
+
node.serverHue.hueManager.writeHueQueueAdd(node.hueDevice, _state, defaultOperation)
|
|
171
|
+
return
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
(async () => {
|
|
175
175
|
try {
|
|
176
|
-
const groupLights = await node.serverHue.getAllLightsBelongingToTheGroup(node.hueDevice, false)
|
|
177
|
-
RED.log.debug(`knxUltimateHueLight: preset grouped_light children before group on. Group=${node.hueDevice} lights=${Array.isArray(groupLights) ? groupLights.length : 0}`)
|
|
178
|
-
let hasWrittenAtLeastOneLight = false
|
|
176
|
+
const groupLights = await node.serverHue.getAllLightsBelongingToTheGroup(node.hueDevice, false)
|
|
177
|
+
RED.log.debug(`knxUltimateHueLight: preset grouped_light children before group on. Group=${node.hueDevice} lights=${Array.isArray(groupLights) ? groupLights.length : 0}`)
|
|
178
|
+
let hasWrittenAtLeastOneLight = false
|
|
179
179
|
for (let index = 0; index < groupLights.length; index++) {
|
|
180
|
-
const light = groupLights[index]
|
|
181
|
-
if (!light?.id) continue
|
|
182
|
-
const lightState = {}
|
|
183
|
-
let hasActionableStateForLight = false
|
|
180
|
+
const light = groupLights[index]
|
|
181
|
+
if (!light?.id) continue
|
|
182
|
+
const lightState = {}
|
|
183
|
+
let hasActionableStateForLight = false
|
|
184
184
|
|
|
185
185
|
if (_state.dimming !== undefined && light.dimming !== undefined) {
|
|
186
|
-
lightState.dimming = cloneDeep(_state.dimming)
|
|
187
|
-
hasActionableStateForLight = true
|
|
186
|
+
lightState.dimming = cloneDeep(_state.dimming)
|
|
187
|
+
hasActionableStateForLight = true
|
|
188
188
|
}
|
|
189
189
|
if (_state.color !== undefined && light.color !== undefined) {
|
|
190
|
-
lightState.color = cloneDeep(_state.color)
|
|
191
|
-
hasActionableStateForLight = true
|
|
190
|
+
lightState.color = cloneDeep(_state.color)
|
|
191
|
+
hasActionableStateForLight = true
|
|
192
192
|
}
|
|
193
193
|
if (_state.color_temperature !== undefined && light.color_temperature !== undefined) {
|
|
194
|
-
lightState.color_temperature = cloneDeep(_state.color_temperature)
|
|
195
|
-
hasActionableStateForLight = true
|
|
194
|
+
lightState.color_temperature = cloneDeep(_state.color_temperature)
|
|
195
|
+
hasActionableStateForLight = true
|
|
196
196
|
}
|
|
197
197
|
if (_state.gradient !== undefined && light.gradient !== undefined) {
|
|
198
|
-
lightState.gradient = cloneDeep(_state.gradient)
|
|
199
|
-
hasActionableStateForLight = true
|
|
198
|
+
lightState.gradient = cloneDeep(_state.gradient)
|
|
199
|
+
hasActionableStateForLight = true
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
-
if (!hasActionableStateForLight) continue
|
|
203
|
-
node.serverHue.hueManager.writeHueQueueAdd(light.id, lightState,
|
|
204
|
-
hasWrittenAtLeastOneLight = true
|
|
202
|
+
if (!hasActionableStateForLight) continue
|
|
203
|
+
node.serverHue.hueManager.writeHueQueueAdd(light.id, lightState, 'setLight')
|
|
204
|
+
hasWrittenAtLeastOneLight = true
|
|
205
205
|
}
|
|
206
206
|
|
|
207
207
|
if (!hasWrittenAtLeastOneLight || !hasActionablePayload) {
|
|
208
|
-
node.serverHue.hueManager.writeHueQueueAdd(node.hueDevice, _state, defaultOperation)
|
|
209
|
-
return
|
|
208
|
+
node.serverHue.hueManager.writeHueQueueAdd(node.hueDevice, _state, defaultOperation)
|
|
209
|
+
return
|
|
210
210
|
}
|
|
211
211
|
|
|
212
|
-
if (_state?.on?.on !== true) return
|
|
212
|
+
if (_state?.on?.on !== true) return
|
|
213
213
|
|
|
214
|
-
const groupedLightState = { on: cloneDeep(_state.on) }
|
|
215
|
-
if (_state.dynamics !== undefined) groupedLightState.dynamics = cloneDeep(_state.dynamics)
|
|
216
|
-
RED.log.debug(`knxUltimateHueLight: turning on grouped_light after children preset. Group=${node.hueDevice}`)
|
|
217
|
-
node.serverHue.hueManager.writeHueQueueAdd(node.hueDevice, groupedLightState, defaultOperation)
|
|
214
|
+
const groupedLightState = { on: cloneDeep(_state.on) }
|
|
215
|
+
if (_state.dynamics !== undefined) groupedLightState.dynamics = cloneDeep(_state.dynamics)
|
|
216
|
+
RED.log.debug(`knxUltimateHueLight: turning on grouped_light after children preset. Group=${node.hueDevice}`)
|
|
217
|
+
node.serverHue.hueManager.writeHueQueueAdd(node.hueDevice, groupedLightState, defaultOperation)
|
|
218
218
|
} catch (error) {
|
|
219
|
-
RED.log.debug(`knxUltimateHueLight: node.writeHueState fallback to grouped_light write: ${error.message}`)
|
|
220
|
-
node.serverHue.hueManager.writeHueQueueAdd(node.hueDevice, _state, defaultOperation)
|
|
219
|
+
RED.log.debug(`knxUltimateHueLight: node.writeHueState fallback to grouped_light write: ${error.message}`)
|
|
220
|
+
node.serverHue.hueManager.writeHueQueueAdd(node.hueDevice, _state, defaultOperation)
|
|
221
221
|
}
|
|
222
|
-
})()
|
|
223
|
-
}
|
|
222
|
+
})()
|
|
223
|
+
}
|
|
224
224
|
|
|
225
|
-
node.deleteHueStateQueue = function deleteHueStateQueue() {
|
|
226
|
-
node.serverHue.hueManager.deleteHueQueue(node.hueDevice)
|
|
225
|
+
node.deleteHueStateQueue = function deleteHueStateQueue () {
|
|
226
|
+
node.serverHue.hueManager.deleteHueQueue(node.hueDevice)
|
|
227
227
|
if (node.isGrouped_light !== true) return;
|
|
228
228
|
|
|
229
229
|
(async () => {
|
|
230
230
|
try {
|
|
231
|
-
const groupLights = await node.serverHue.getAllLightsBelongingToTheGroup(node.hueDevice, false)
|
|
231
|
+
const groupLights = await node.serverHue.getAllLightsBelongingToTheGroup(node.hueDevice, false)
|
|
232
232
|
for (let index = 0; index < groupLights.length; index++) {
|
|
233
|
-
const light = groupLights[index]
|
|
234
|
-
if (!light?.id) continue
|
|
235
|
-
node.serverHue.hueManager.deleteHueQueue(light.id)
|
|
233
|
+
const light = groupLights[index]
|
|
234
|
+
if (!light?.id) continue
|
|
235
|
+
node.serverHue.hueManager.deleteHueQueue(light.id)
|
|
236
236
|
}
|
|
237
237
|
} catch (error) {
|
|
238
|
-
RED.log.debug(`knxUltimateHueLight: node.deleteHueStateQueue: ${error.message}`)
|
|
238
|
+
RED.log.debug(`knxUltimateHueLight: node.deleteHueStateQueue: ${error.message}`)
|
|
239
239
|
}
|
|
240
|
-
})()
|
|
241
|
-
}
|
|
240
|
+
})()
|
|
241
|
+
}
|
|
242
242
|
|
|
243
|
-
function getRandomIntInclusive(min, max) {
|
|
244
|
-
min = Math.ceil(min)
|
|
245
|
-
max = Math.floor(max)
|
|
246
|
-
return Math.floor(Math.random() * (max - min + 1) + min)
|
|
243
|
+
function getRandomIntInclusive (min, max) {
|
|
244
|
+
min = Math.ceil(min)
|
|
245
|
+
max = Math.floor(max)
|
|
246
|
+
return Math.floor(Math.random() * (max - min + 1) + min) // The maximum is inclusive and the minimum is inclusive
|
|
247
247
|
}
|
|
248
248
|
|
|
249
249
|
// This function is called by the hue-config.js
|
|
250
250
|
node.handleSend = (msg) => {
|
|
251
|
-
if (node.currentHUEDevice === undefined && node.serverHue.linkStatus ===
|
|
251
|
+
if (node.currentHUEDevice === undefined && node.serverHue.linkStatus === 'connected') {
|
|
252
252
|
node.setNodeStatusHue({
|
|
253
|
-
fill:
|
|
254
|
-
shape:
|
|
255
|
-
text:
|
|
256
|
-
payload:
|
|
257
|
-
})
|
|
258
|
-
return
|
|
253
|
+
fill: 'yellow',
|
|
254
|
+
shape: 'ring',
|
|
255
|
+
text: 'Initializing. Please wait.',
|
|
256
|
+
payload: ''
|
|
257
|
+
})
|
|
258
|
+
return
|
|
259
259
|
}
|
|
260
|
-
if (msg.knx.event !==
|
|
261
|
-
let state = {}
|
|
260
|
+
if (msg.knx.event !== 'GroupValue_Read' && node.currentHUEDevice !== undefined) {
|
|
261
|
+
let state = {}
|
|
262
262
|
try {
|
|
263
263
|
switch (msg.knx.destination) {
|
|
264
264
|
case config.GALightSwitch:
|
|
265
|
-
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightSwitch))
|
|
265
|
+
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightSwitch))
|
|
266
266
|
|
|
267
267
|
// 15/05/2024 Supergiovane: check the Override to Day option
|
|
268
268
|
// config.restoreDayMode can be: no or setDayByFastSwitchLightSingle or setDayByFastSwitchLightALL
|
|
269
269
|
// ----------------------------------------------------------
|
|
270
|
-
if (config.restoreDayMode ===
|
|
270
|
+
if (config.restoreDayMode === 'setDayByFastSwitchLightSingle' || config.restoreDayMode === 'setDayByFastSwitchLightALL') {
|
|
271
271
|
if (node.DayTime === false) {
|
|
272
272
|
if (msg.payload === true) {
|
|
273
273
|
if (node.timerCheckForFastLightSwitch === null) {
|
|
274
274
|
node.timerCheckForFastLightSwitch = setTimeout(() => {
|
|
275
|
-
node.DayTime = false
|
|
276
|
-
RED.log.debug(
|
|
277
|
-
node.timerCheckForFastLightSwitch = null
|
|
278
|
-
}, 10000)
|
|
275
|
+
node.DayTime = false
|
|
276
|
+
RED.log.debug('knxUltimateHueLight: node.timerCheckForFastLightSwitch: set daytime to false after node.timerCheckForFastLightSwitch elapsed')
|
|
277
|
+
node.timerCheckForFastLightSwitch = null
|
|
278
|
+
}, 10000) // 10 seconds
|
|
279
279
|
} else {
|
|
280
|
-
if (config.restoreDayMode ===
|
|
280
|
+
if (config.restoreDayMode === 'setDayByFastSwitchLightALL') {
|
|
281
281
|
// Turn off the Day/Night group address
|
|
282
|
-
if (config.GADaylightSensor !== undefined && config.GADaylightSensor !==
|
|
283
|
-
if (node.timerCheckForFastLightSwitch !== null) { clearTimeout(node.timerCheckForFastLightSwitch); node.timerCheckForFastLightSwitch = null
|
|
284
|
-
RED.log.debug(`knxUltimateHueLight: node.timerCheckForFastLightSwitch: set daytime the group address ${config.GADaylightSensor}`)
|
|
282
|
+
if (config.GADaylightSensor !== undefined && config.GADaylightSensor !== '') {
|
|
283
|
+
if (node.timerCheckForFastLightSwitch !== null) { clearTimeout(node.timerCheckForFastLightSwitch); node.timerCheckForFastLightSwitch = null }
|
|
284
|
+
RED.log.debug(`knxUltimateHueLight: node.timerCheckForFastLightSwitch: set daytime the group address ${config.GADaylightSensor}`)
|
|
285
285
|
node.serverKNX.sendKNXTelegramToKNXEngine({
|
|
286
286
|
grpaddr: config.GADaylightSensor,
|
|
287
287
|
payload: config.invertDayNight === false,
|
|
288
288
|
dpt: config.dptDaylightSensor,
|
|
289
|
-
outputtype:
|
|
290
|
-
nodecallerid: node.id
|
|
291
|
-
})
|
|
289
|
+
outputtype: 'write',
|
|
290
|
+
nodecallerid: node.id
|
|
291
|
+
})
|
|
292
292
|
}
|
|
293
293
|
}
|
|
294
|
-
node.DayTime = true
|
|
295
|
-
RED.log.debug(
|
|
294
|
+
node.DayTime = true
|
|
295
|
+
RED.log.debug('knxUltimateHueLight: node.timerCheckForFastLightSwitch: set daytime to true')
|
|
296
296
|
}
|
|
297
297
|
}
|
|
298
298
|
}
|
|
@@ -304,374 +304,374 @@ module.exports = function (RED) {
|
|
|
304
304
|
// If you try and control multiple conflicting parameters at once e.g. {"color": {"xy": {"x":0.5,"y":0.5}}, "color_temperature": {"mirek": 250}}
|
|
305
305
|
// the lights can only physically do one, for this we apply the rule that xy beats ct. Simple.
|
|
306
306
|
// color_temperature.mirek: color temperature in mirek is null when the light color is not in the ct spectrum
|
|
307
|
-
if ((node.DayTime === true && config.specifySwitchOnBrightness ===
|
|
307
|
+
if ((node.DayTime === true && config.specifySwitchOnBrightness === 'no') && ((node.isGrouped_light === false && node.HUEDeviceWhileDaytime !== null) || (node.isGrouped_light === true && node.HUELightsBelongingToGroupWhileDaytime !== null))) {
|
|
308
308
|
if (node.isGrouped_light === false && node.HUEDeviceWhileDaytime !== null) {
|
|
309
309
|
// The DayNight has switched into day, so restore the previous light status
|
|
310
|
-
state = { on: { on: true }, dimming: node.HUEDeviceWhileDaytime.dimming, color: node.HUEDeviceWhileDaytime.color, color_temperature: node.HUEDeviceWhileDaytime.color_temperature }
|
|
311
|
-
if (node.HUEDeviceWhileDaytime.color_temperature !== undefined && node.HUEDeviceWhileDaytime.color_temperature.mirek === null) delete state.color_temperature
|
|
312
|
-
node.writeHueState(state)
|
|
310
|
+
state = { on: { on: true }, dimming: node.HUEDeviceWhileDaytime.dimming, color: node.HUEDeviceWhileDaytime.color, color_temperature: node.HUEDeviceWhileDaytime.color_temperature }
|
|
311
|
+
if (node.HUEDeviceWhileDaytime.color_temperature !== undefined && node.HUEDeviceWhileDaytime.color_temperature.mirek === null) delete state.color_temperature // Otherwise the lamp will not turn on due to an error. color_temperature.mirek: color temperature in mirek is null when the light color is not in the ct spectrum
|
|
312
|
+
node.writeHueState(state)
|
|
313
313
|
node.setNodeStatusHue({
|
|
314
|
-
fill:
|
|
315
|
-
shape:
|
|
316
|
-
text:
|
|
317
|
-
payload:
|
|
318
|
-
})
|
|
319
|
-
node.HUEDeviceWhileDaytime = null
|
|
314
|
+
fill: 'green',
|
|
315
|
+
shape: 'dot',
|
|
316
|
+
text: 'KNX->HUE',
|
|
317
|
+
payload: 'Restore light status'
|
|
318
|
+
})
|
|
319
|
+
node.HUEDeviceWhileDaytime = null // Nullize the object.
|
|
320
320
|
} else if (node.isGrouped_light === true && node.HUELightsBelongingToGroupWhileDaytime !== null) {
|
|
321
321
|
// The DayNight has switched into day, so restore the previous light state, belonging to the group
|
|
322
|
-
let bAtLeastOneIsOn = false
|
|
322
|
+
let bAtLeastOneIsOn = false
|
|
323
323
|
for (let index = 0; index < node.HUELightsBelongingToGroupWhileDaytime.length; index++) { // Ensure, at least 1 lamp was on, otherwise turn all lamps on
|
|
324
|
-
const element = node.HUELightsBelongingToGroupWhileDaytime[index].light[0]
|
|
324
|
+
const element = node.HUELightsBelongingToGroupWhileDaytime[index].light[0]
|
|
325
325
|
if (element.on.on === true) {
|
|
326
|
-
bAtLeastOneIsOn = true
|
|
327
|
-
break
|
|
326
|
+
bAtLeastOneIsOn = true
|
|
327
|
+
break
|
|
328
328
|
}
|
|
329
329
|
}
|
|
330
330
|
for (let index = 0; index < node.HUELightsBelongingToGroupWhileDaytime.length; index++) {
|
|
331
|
-
const element = node.HUELightsBelongingToGroupWhileDaytime[index].light[0]
|
|
331
|
+
const element = node.HUELightsBelongingToGroupWhileDaytime[index].light[0]
|
|
332
332
|
if (bAtLeastOneIsOn === true) {
|
|
333
|
-
state = { on: element.on, dimming: element.dimming, color: element.color, color_temperature: element.color_temperature }
|
|
333
|
+
state = { on: element.on, dimming: element.dimming, color: element.color, color_temperature: element.color_temperature }
|
|
334
334
|
} else {
|
|
335
335
|
// Failsafe all on
|
|
336
|
-
state = { on: { on: true }, dimming: element.dimming, color: element.color, color_temperature: element.color_temperature }
|
|
336
|
+
state = { on: { on: true }, dimming: element.dimming, color: element.color, color_temperature: element.color_temperature }
|
|
337
337
|
}
|
|
338
|
-
if (element.color_temperature !== undefined && element.color_temperature.mirek === null) delete state.color_temperature
|
|
339
|
-
node.serverHue.hueManager.writeHueQueueAdd(element.id, state,
|
|
338
|
+
if (element.color_temperature !== undefined && element.color_temperature.mirek === null) delete state.color_temperature // Otherwise the lamp will not turn on due to an error. color_temperature.mirek: color temperature in mirek is null when the light color is not in the ct spectrum
|
|
339
|
+
node.serverHue.hueManager.writeHueQueueAdd(element.id, state, 'setLight')
|
|
340
340
|
}
|
|
341
341
|
node.setNodeStatusHue({
|
|
342
|
-
fill:
|
|
343
|
-
shape:
|
|
344
|
-
text:
|
|
345
|
-
payload: "Resuming all group's light"
|
|
346
|
-
})
|
|
347
|
-
node.HUELightsBelongingToGroupWhileDaytime = null
|
|
348
|
-
return
|
|
342
|
+
fill: 'green',
|
|
343
|
+
shape: 'dot',
|
|
344
|
+
text: 'KNX->HUE',
|
|
345
|
+
payload: "Resuming all group's light"
|
|
346
|
+
})
|
|
347
|
+
node.HUELightsBelongingToGroupWhileDaytime = null // Nullize the object.
|
|
348
|
+
return
|
|
349
349
|
}
|
|
350
350
|
} else {
|
|
351
|
-
let colorChoosen
|
|
352
|
-
let temperatureChoosen
|
|
353
|
-
let brightnessChoosen
|
|
351
|
+
let colorChoosen
|
|
352
|
+
let temperatureChoosen
|
|
353
|
+
let brightnessChoosen
|
|
354
354
|
// The light must support the temperature (in this case, colorAtSwitchOnNightTime is an object {kelvin:xx, brightness:yy})
|
|
355
355
|
if (node.currentHUEDevice.color_temperature !== undefined) {
|
|
356
|
-
if (node.DayTime === true && config.specifySwitchOnBrightness ===
|
|
357
|
-
temperatureChoosen = config.colorAtSwitchOnDayTime.kelvin
|
|
358
|
-
} else if (node.DayTime === false && config.enableDayNightLighting ===
|
|
359
|
-
temperatureChoosen = config.colorAtSwitchOnNightTime.kelvin
|
|
356
|
+
if (node.DayTime === true && config.specifySwitchOnBrightness === 'temperature') {
|
|
357
|
+
temperatureChoosen = config.colorAtSwitchOnDayTime.kelvin
|
|
358
|
+
} else if (node.DayTime === false && config.enableDayNightLighting === 'temperature') {
|
|
359
|
+
temperatureChoosen = config.colorAtSwitchOnNightTime.kelvin
|
|
360
360
|
}
|
|
361
361
|
}
|
|
362
362
|
if (node.currentHUEDevice.dimming !== undefined) {
|
|
363
363
|
// Check wether the user selected specific brightness at switch on (in this case, colorAtSwitchOnNightTime is an object {kelvin:xx, brightness:yy})
|
|
364
|
-
if (node.DayTime === true && config.specifySwitchOnBrightness ===
|
|
365
|
-
brightnessChoosen = config.colorAtSwitchOnDayTime.brightness
|
|
366
|
-
} else if (node.DayTime === false && config.enableDayNightLighting ===
|
|
367
|
-
brightnessChoosen = config.colorAtSwitchOnNightTime.brightness
|
|
364
|
+
if (node.DayTime === true && config.specifySwitchOnBrightness === 'temperature') {
|
|
365
|
+
brightnessChoosen = config.colorAtSwitchOnDayTime.brightness
|
|
366
|
+
} else if (node.DayTime === false && config.enableDayNightLighting === 'temperature') {
|
|
367
|
+
brightnessChoosen = config.colorAtSwitchOnNightTime.brightness
|
|
368
368
|
}
|
|
369
369
|
}
|
|
370
370
|
if (node.currentHUEDevice.color !== undefined) {
|
|
371
371
|
// Check wether the user selected specific color at switch on (in this case, colorAtSwitchOnDayTime is a text with HTML web color)
|
|
372
|
-
if (node.DayTime === true && config.specifySwitchOnBrightness ===
|
|
373
|
-
colorChoosen = config.colorAtSwitchOnDayTime
|
|
374
|
-
} else if (node.DayTime === false && config.enableDayNightLighting ===
|
|
375
|
-
colorChoosen = config.colorAtSwitchOnNightTime
|
|
372
|
+
if (node.DayTime === true && config.specifySwitchOnBrightness === 'yes') {
|
|
373
|
+
colorChoosen = config.colorAtSwitchOnDayTime
|
|
374
|
+
} else if (node.DayTime === false && config.enableDayNightLighting === 'yes') {
|
|
375
|
+
colorChoosen = config.colorAtSwitchOnNightTime
|
|
376
376
|
}
|
|
377
377
|
}
|
|
378
378
|
// Create the HUE command
|
|
379
379
|
if (colorChoosen !== undefined) {
|
|
380
380
|
// Now we have a jColorChoosen. Proceed illuminating the light
|
|
381
|
-
let gamut = null
|
|
381
|
+
let gamut = null
|
|
382
382
|
if (node.currentHUEDevice.color.gamut !== undefined) {
|
|
383
|
-
gamut = node.currentHUEDevice.color.gamut
|
|
383
|
+
gamut = node.currentHUEDevice.color.gamut
|
|
384
384
|
}
|
|
385
|
-
const dretXY = hueColorConverter.ColorConverter.calculateXYFromRGB(colorChoosen.red, colorChoosen.green, colorChoosen.blue, gamut)
|
|
386
|
-
const dbright = hueColorConverter.ColorConverter.getBrightnessFromRGBOrHex(colorChoosen.red, colorChoosen.green, colorChoosen.blue)
|
|
387
|
-
node.currentHUEDevice.dimming.brightness = Math.round(dbright, 0)
|
|
388
|
-
if (node.currentHUEDevice.color !== undefined) node.currentHUEDevice.color.xy = dretXY
|
|
389
|
-
node.updateKNXBrightnessState(node.currentHUEDevice.dimming.brightness)
|
|
390
|
-
state = dbright > 0 ? { on: { on: true }, dimming: { brightness: dbright }, color: { xy: dretXY } } : { on: { on: false } }
|
|
385
|
+
const dretXY = hueColorConverter.ColorConverter.calculateXYFromRGB(colorChoosen.red, colorChoosen.green, colorChoosen.blue, gamut)
|
|
386
|
+
const dbright = hueColorConverter.ColorConverter.getBrightnessFromRGBOrHex(colorChoosen.red, colorChoosen.green, colorChoosen.blue)
|
|
387
|
+
node.currentHUEDevice.dimming.brightness = Math.round(dbright, 0)
|
|
388
|
+
if (node.currentHUEDevice.color !== undefined) node.currentHUEDevice.color.xy = dretXY // 26/03/2024
|
|
389
|
+
node.updateKNXBrightnessState(node.currentHUEDevice.dimming.brightness)
|
|
390
|
+
state = dbright > 0 ? { on: { on: true }, dimming: { brightness: dbright }, color: { xy: dretXY } } : { on: { on: false } }
|
|
391
391
|
// state = { on: { on: true }, dimming: { brightness: dbright }, color: { xy: dretXY } };
|
|
392
392
|
} else if (temperatureChoosen !== undefined) {
|
|
393
393
|
// Kelvin
|
|
394
|
-
const mirek = hueColorConverter.ColorConverter.kelvinToMirek(temperatureChoosen)
|
|
395
|
-
node.currentHUEDevice.color_temperature.mirek = mirek
|
|
396
|
-
node.currentHUEDevice.dimming.brightness = brightnessChoosen
|
|
397
|
-
node.updateKNXBrightnessState(node.currentHUEDevice.dimming.brightness)
|
|
394
|
+
const mirek = hueColorConverter.ColorConverter.kelvinToMirek(temperatureChoosen)
|
|
395
|
+
node.currentHUEDevice.color_temperature.mirek = mirek
|
|
396
|
+
node.currentHUEDevice.dimming.brightness = brightnessChoosen
|
|
397
|
+
node.updateKNXBrightnessState(node.currentHUEDevice.dimming.brightness)
|
|
398
398
|
// Kelvin temp
|
|
399
|
-
state = brightnessChoosen > 0 ? { on: { on: true }, dimming: { brightness: brightnessChoosen }, color_temperature: { mirek
|
|
399
|
+
state = brightnessChoosen > 0 ? { on: { on: true }, dimming: { brightness: brightnessChoosen }, color_temperature: { mirek } } : { on: { on: false } }
|
|
400
400
|
// state = { on: { on: true }, dimming: { brightness: brightnessChoosen }, color_temperature: { mirek: mirek } };
|
|
401
401
|
} else if (brightnessChoosen !== undefined) {
|
|
402
|
-
state = brightnessChoosen > 0 ? { on: { on: true }, dimming: { brightness: brightnessChoosen } } : { on: { on: false } }
|
|
402
|
+
state = brightnessChoosen > 0 ? { on: { on: true }, dimming: { brightness: brightnessChoosen } } : { on: { on: false } }
|
|
403
403
|
// state = { on: { on: true }, dimming: { brightness: brightnessChoosen } };
|
|
404
404
|
} else {
|
|
405
|
-
state = { on: { on: true } }
|
|
405
|
+
state = { on: { on: true } }
|
|
406
406
|
}
|
|
407
407
|
}
|
|
408
408
|
} else {
|
|
409
409
|
// Stop color cycle
|
|
410
|
-
if (node.timerColorCycle !== undefined) clearInterval(node.timerColorCycle)
|
|
410
|
+
if (node.timerColorCycle !== undefined) clearInterval(node.timerColorCycle)
|
|
411
411
|
// Stop Blinking
|
|
412
|
-
if (node.timerBlink !== undefined) clearInterval(node.timerBlink)
|
|
413
|
-
state = { on: { on: false } }
|
|
412
|
+
if (node.timerBlink !== undefined) clearInterval(node.timerBlink)
|
|
413
|
+
state = { on: { on: false } }
|
|
414
414
|
}
|
|
415
415
|
|
|
416
|
-
node.syncCurrentHUEDeviceFromKNXState(state)
|
|
417
|
-
node.writeHueState(state)
|
|
416
|
+
node.syncCurrentHUEDeviceFromKNXState(state) // Starting from v 4.1.31
|
|
417
|
+
node.writeHueState(state)
|
|
418
418
|
node.setNodeStatusHue({
|
|
419
|
-
fill:
|
|
420
|
-
shape:
|
|
421
|
-
text:
|
|
422
|
-
payload: state
|
|
423
|
-
})
|
|
424
|
-
break
|
|
419
|
+
fill: 'green',
|
|
420
|
+
shape: 'dot',
|
|
421
|
+
text: 'KNX->HUE',
|
|
422
|
+
payload: state
|
|
423
|
+
})
|
|
424
|
+
break
|
|
425
425
|
case config.GALightDIM:
|
|
426
426
|
// { decr_incr: 1, data: 1 } : Start increasing until { decr_incr: 0, data: 0 } is received.
|
|
427
427
|
// { decr_incr: 0, data: 1 } : Start decreasing until { decr_incr: 0, data: 0 } is received.
|
|
428
|
-
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightDIM))
|
|
429
|
-
node.hueDimming(msg.payload.decr_incr, msg.payload.data, config.dimSpeed)
|
|
428
|
+
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightDIM))
|
|
429
|
+
node.hueDimming(msg.payload.decr_incr, msg.payload.data, config.dimSpeed)
|
|
430
430
|
node.setNodeStatusHue({
|
|
431
|
-
fill:
|
|
432
|
-
})
|
|
433
|
-
break
|
|
431
|
+
fill: 'green', shape: 'dot', text: 'KNX->HUE', payload: JSON.stringify(msg.payload)
|
|
432
|
+
})
|
|
433
|
+
break
|
|
434
434
|
case config.GALightHSV_H_DIM:
|
|
435
435
|
// { decr_incr: 1, data: 1 } : Start increasing until { decr_incr: 0, data: 0 } is received.
|
|
436
436
|
// { decr_incr: 0, data: 1 } : Start decreasing until { decr_incr: 0, data: 0 } is received.
|
|
437
|
-
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightDIM))
|
|
438
|
-
node.hueDimmingHSV_H(msg.payload.decr_incr, msg.payload.data, config.HSVDimSpeed)
|
|
437
|
+
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightDIM))
|
|
438
|
+
node.hueDimmingHSV_H(msg.payload.decr_incr, msg.payload.data, config.HSVDimSpeed)
|
|
439
439
|
node.setNodeStatusHue({
|
|
440
|
-
fill:
|
|
441
|
-
})
|
|
442
|
-
break
|
|
440
|
+
fill: 'green', shape: 'dot', text: 'KNX->HUE', payload: JSON.stringify(msg.payload)
|
|
441
|
+
})
|
|
442
|
+
break
|
|
443
443
|
case config.GALightHSV_S_DIM:
|
|
444
444
|
// { decr_incr: 1, data: 1 } : Start increasing until { decr_incr: 0, data: 0 } is received.
|
|
445
445
|
// { decr_incr: 0, data: 1 } : Start decreasing until { decr_incr: 0, data: 0 } is received.
|
|
446
|
-
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightDIM))
|
|
447
|
-
node.hueDimmingHSV_S(msg.payload.decr_incr, msg.payload.data, config.HSVDimSpeed)
|
|
446
|
+
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightDIM))
|
|
447
|
+
node.hueDimmingHSV_S(msg.payload.decr_incr, msg.payload.data, config.HSVDimSpeed)
|
|
448
448
|
node.setNodeStatusHue({
|
|
449
|
-
fill:
|
|
450
|
-
})
|
|
451
|
-
break
|
|
449
|
+
fill: 'green', shape: 'dot', text: 'KNX->HUE', payload: JSON.stringify(msg.payload)
|
|
450
|
+
})
|
|
451
|
+
break
|
|
452
452
|
case config.GALightKelvin:
|
|
453
|
-
let retMirek
|
|
454
|
-
let kelvinValue = 0
|
|
455
|
-
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightKelvin))
|
|
456
|
-
if (config.dptLightKelvin ===
|
|
457
|
-
if (msg.payload > 6535) msg.payload = 6535
|
|
458
|
-
if (msg.payload < 2000) msg.payload = 2000
|
|
459
|
-
kelvinValue = msg.payload
|
|
460
|
-
retMirek = hueColorConverter.ColorConverter.kelvinToMirek(kelvinValue)
|
|
461
|
-
} else if (config.dptLightKelvin ===
|
|
453
|
+
let retMirek
|
|
454
|
+
let kelvinValue = 0
|
|
455
|
+
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightKelvin))
|
|
456
|
+
if (config.dptLightKelvin === '7.600') {
|
|
457
|
+
if (msg.payload > 6535) msg.payload = 6535
|
|
458
|
+
if (msg.payload < 2000) msg.payload = 2000
|
|
459
|
+
kelvinValue = msg.payload// hueColorConverter.ColorConverter.scale(msg.payload, [0, 65535], [2000, 6535]);
|
|
460
|
+
retMirek = hueColorConverter.ColorConverter.kelvinToMirek(kelvinValue)
|
|
461
|
+
} else if (config.dptLightKelvin === '9.002') {
|
|
462
462
|
// Relative temperature in Kelvin. Use HUE scale.
|
|
463
|
-
if (msg.payload > 6535) msg.payload = 6535
|
|
464
|
-
if (msg.payload < 2000) msg.payload = 2000
|
|
465
|
-
retMirek = hueColorConverter.ColorConverter.kelvinToMirek(msg.payload)
|
|
463
|
+
if (msg.payload > 6535) msg.payload = 6535
|
|
464
|
+
if (msg.payload < 2000) msg.payload = 2000
|
|
465
|
+
retMirek = hueColorConverter.ColorConverter.kelvinToMirek(msg.payload)
|
|
466
466
|
}
|
|
467
|
-
state = { color_temperature: { mirek: retMirek } }
|
|
468
|
-
node.syncCurrentHUEDeviceFromKNXState(state)
|
|
469
|
-
node.writeHueState(state)
|
|
467
|
+
state = { color_temperature: { mirek: retMirek } }
|
|
468
|
+
node.syncCurrentHUEDeviceFromKNXState(state) // Starting from v 4.1.31
|
|
469
|
+
node.writeHueState(state)
|
|
470
470
|
node.setNodeStatusHue({
|
|
471
|
-
fill:
|
|
472
|
-
shape:
|
|
473
|
-
text:
|
|
474
|
-
payload: kelvinValue
|
|
475
|
-
})
|
|
476
|
-
break
|
|
471
|
+
fill: 'green',
|
|
472
|
+
shape: 'dot',
|
|
473
|
+
text: 'KNX->HUE',
|
|
474
|
+
payload: kelvinValue
|
|
475
|
+
})
|
|
476
|
+
break
|
|
477
477
|
case config.GADaylightSensor:
|
|
478
|
-
node.DayTime = Boolean(dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptDaylightSensor)))
|
|
479
|
-
if (config.invertDayNight === true) node.DayTime = !node.DayTime
|
|
480
|
-
if (config.specifySwitchOnBrightness ===
|
|
478
|
+
node.DayTime = Boolean(dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptDaylightSensor)))
|
|
479
|
+
if (config.invertDayNight === true) node.DayTime = !node.DayTime
|
|
480
|
+
if (config.specifySwitchOnBrightness === 'no') {
|
|
481
481
|
// This retains the HUE device status while daytime, to be restored after nighttime elapsed. https://github.com/Supergiovane/node-red-contrib-knx-ultimate/issues/298
|
|
482
482
|
if (node.DayTime === false) {
|
|
483
|
-
if (node.isGrouped_light === false) node.HUEDeviceWhileDaytime = cloneDeep(node.currentHUEDevice)
|
|
483
|
+
if (node.isGrouped_light === false) node.HUEDeviceWhileDaytime = cloneDeep(node.currentHUEDevice) // DayTime has switched to false: save the currentHUEDevice into the HUEDeviceWhileDaytime
|
|
484
484
|
if (node.isGrouped_light === true) {
|
|
485
485
|
(async () => {
|
|
486
486
|
try {
|
|
487
|
-
const retLights = await node.serverHue.getAllLightsBelongingToTheGroup(node.hueDevice, false)
|
|
488
|
-
node.HUELightsBelongingToGroupWhileDaytime = cloneDeep(retLights)
|
|
487
|
+
const retLights = await node.serverHue.getAllLightsBelongingToTheGroup(node.hueDevice, false)
|
|
488
|
+
node.HUELightsBelongingToGroupWhileDaytime = cloneDeep(retLights) // DayTime has switched to false: save the lights belonging to the group into the HUELightsBelongingToGroupWhileDaytime array
|
|
489
489
|
} catch (error) { /* empty */ }
|
|
490
|
-
})()
|
|
490
|
+
})()
|
|
491
491
|
}
|
|
492
492
|
}
|
|
493
493
|
} else {
|
|
494
|
-
node.HUEDeviceWhileDaytime = null
|
|
495
|
-
node.HUELightsBelongingToGroupWhileDaytime = null
|
|
494
|
+
node.HUEDeviceWhileDaytime = null
|
|
495
|
+
node.HUELightsBelongingToGroupWhileDaytime = null
|
|
496
496
|
}
|
|
497
497
|
node.setNodeStatusHue({
|
|
498
|
-
fill:
|
|
499
|
-
shape:
|
|
500
|
-
text:
|
|
501
|
-
payload: node.DayTime
|
|
502
|
-
})
|
|
498
|
+
fill: 'green',
|
|
499
|
+
shape: 'dot',
|
|
500
|
+
text: 'KNX->HUE Daytime',
|
|
501
|
+
payload: node.DayTime
|
|
502
|
+
})
|
|
503
503
|
|
|
504
|
-
break
|
|
504
|
+
break
|
|
505
505
|
case config.GALightKelvinDIM:
|
|
506
|
-
if (config.dptLightKelvinDIM ===
|
|
506
|
+
if (config.dptLightKelvinDIM === '3.007') {
|
|
507
507
|
// MDT smartbutton will dim the color temperature
|
|
508
508
|
// { decr_incr: 1, data: 1 } : Start increasing until { decr_incr: 0, data: 0 } is received.
|
|
509
509
|
// { decr_incr: 0, data: 1 } : Start decreasing until { decr_incr: 0, data: 0 } is received.
|
|
510
|
-
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightKelvinDIM))
|
|
511
|
-
node.hueDimmingTunableWhite(msg.payload.decr_incr, msg.payload.data, 5000)
|
|
510
|
+
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightKelvinDIM))
|
|
511
|
+
node.hueDimmingTunableWhite(msg.payload.decr_incr, msg.payload.data, 5000)
|
|
512
512
|
node.setNodeStatusHue({
|
|
513
|
-
fill:
|
|
514
|
-
})
|
|
513
|
+
fill: 'green', shape: 'dot', text: 'KNX->HUE', payload: JSON.stringify(msg.payload)
|
|
514
|
+
})
|
|
515
515
|
}
|
|
516
|
-
break
|
|
516
|
+
break
|
|
517
517
|
case config.GALightKelvinPercentage:
|
|
518
|
-
if (config.dptLightKelvinPercentage ===
|
|
518
|
+
if (config.dptLightKelvinPercentage === '5.001') {
|
|
519
519
|
// 0-100% tunable white
|
|
520
|
-
msg.payload = 100 - dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightKelvinPercentage))
|
|
520
|
+
msg.payload = 100 - dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightKelvinPercentage))
|
|
521
521
|
// msg.payload = msg.payload <= 0 ? 1 : msg.payload
|
|
522
|
-
const retMirek = hueColorConverter.ColorConverter.scale(msg.payload, [0, 100], [153, 500])
|
|
523
|
-
msg.payload = retMirek
|
|
524
|
-
state = { color_temperature: { mirek: msg.payload } }
|
|
525
|
-
node.syncCurrentHUEDeviceFromKNXState(state)
|
|
526
|
-
node.writeHueState(state)
|
|
522
|
+
const retMirek = hueColorConverter.ColorConverter.scale(msg.payload, [0, 100], [153, 500])
|
|
523
|
+
msg.payload = retMirek
|
|
524
|
+
state = { color_temperature: { mirek: msg.payload } }
|
|
525
|
+
node.syncCurrentHUEDeviceFromKNXState(state) // Starting from v 4.1.31
|
|
526
|
+
node.writeHueState(state)
|
|
527
527
|
node.setNodeStatusHue({
|
|
528
|
-
fill:
|
|
529
|
-
shape:
|
|
530
|
-
text:
|
|
531
|
-
payload: state
|
|
532
|
-
})
|
|
528
|
+
fill: 'green',
|
|
529
|
+
shape: 'dot',
|
|
530
|
+
text: 'KNX->HUE',
|
|
531
|
+
payload: state
|
|
532
|
+
})
|
|
533
533
|
}
|
|
534
|
-
break
|
|
534
|
+
break
|
|
535
535
|
case config.GALightBrightness:
|
|
536
|
-
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightBrightness))
|
|
537
|
-
if (typeof msg.payload !==
|
|
538
|
-
state = { dimming: { brightness: msg.payload } }
|
|
536
|
+
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightBrightness))
|
|
537
|
+
if (typeof msg.payload !== 'number' || Number.isNaN(msg.payload)) throw new Error('Invalid KNX brightness payload')
|
|
538
|
+
state = { dimming: { brightness: msg.payload } }
|
|
539
539
|
if (msg.payload === 0) {
|
|
540
|
-
state.on = { on: false }
|
|
540
|
+
state.on = { on: false }
|
|
541
541
|
} else if (node.currentHUEDevice !== undefined && node.currentHUEDevice.on?.on === true) {
|
|
542
|
-
state.on = { on: true }
|
|
542
|
+
state.on = { on: true }
|
|
543
543
|
}
|
|
544
|
-
node.syncCurrentHUEDeviceFromKNXState(state)
|
|
545
|
-
node.writeHueState(state)
|
|
544
|
+
node.syncCurrentHUEDeviceFromKNXState(state) // Starting from v 4.1.31
|
|
545
|
+
node.writeHueState(state)
|
|
546
546
|
node.setNodeStatusHue({
|
|
547
|
-
fill:
|
|
548
|
-
shape:
|
|
549
|
-
text:
|
|
550
|
-
payload: state
|
|
551
|
-
})
|
|
552
|
-
break
|
|
547
|
+
fill: 'green',
|
|
548
|
+
shape: 'dot',
|
|
549
|
+
text: 'KNX->HUE',
|
|
550
|
+
payload: state
|
|
551
|
+
})
|
|
552
|
+
break
|
|
553
553
|
case config.GALightColor:
|
|
554
|
-
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightColor))
|
|
555
|
-
let gamut = null
|
|
554
|
+
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightColor))
|
|
555
|
+
let gamut = null
|
|
556
556
|
if (
|
|
557
|
-
node.currentHUEDevice !== undefined
|
|
558
|
-
|
|
559
|
-
|
|
557
|
+
node.currentHUEDevice !== undefined &&
|
|
558
|
+
node.currentHUEDevice.color !== undefined &&
|
|
559
|
+
node.currentHUEDevice.color.gamut !== undefined
|
|
560
560
|
) {
|
|
561
|
-
gamut = node.currentHUEDevice.color.gamut
|
|
561
|
+
gamut = node.currentHUEDevice.color.gamut
|
|
562
562
|
}
|
|
563
|
-
const retXY = hueColorConverter.ColorConverter.calculateXYFromRGB(msg.payload.red, msg.payload.green, msg.payload.blue, gamut)
|
|
564
|
-
const bright = hueColorConverter.ColorConverter.getBrightnessFromRGBOrHex(msg.payload.red, msg.payload.green, msg.payload.blue)
|
|
565
|
-
state = { dimming: { brightness: bright }, color: { xy: retXY } }
|
|
563
|
+
const retXY = hueColorConverter.ColorConverter.calculateXYFromRGB(msg.payload.red, msg.payload.green, msg.payload.blue, gamut)
|
|
564
|
+
const bright = hueColorConverter.ColorConverter.getBrightnessFromRGBOrHex(msg.payload.red, msg.payload.green, msg.payload.blue)
|
|
565
|
+
state = { dimming: { brightness: bright }, color: { xy: retXY } }
|
|
566
566
|
if (node.currentHUEDevice === undefined) {
|
|
567
567
|
// Grouped light
|
|
568
|
-
state.on = { on: bright > 0 }
|
|
568
|
+
state.on = { on: bright > 0 }
|
|
569
569
|
} else {
|
|
570
570
|
// Light
|
|
571
|
-
if (node.currentHUEDevice.on.on === false && bright > 0) state.on = { on: true }
|
|
572
|
-
if (node.currentHUEDevice.on.on === true && bright === 0) state = { on: { on: false }, dimming: { brightness: bright } }
|
|
571
|
+
if (node.currentHUEDevice.on.on === false && bright > 0) state.on = { on: true }
|
|
572
|
+
if (node.currentHUEDevice.on.on === true && bright === 0) state = { on: { on: false }, dimming: { brightness: bright } }
|
|
573
573
|
}
|
|
574
|
-
node.syncCurrentHUEDeviceFromKNXState(state)
|
|
575
|
-
node.writeHueState(state)
|
|
574
|
+
node.syncCurrentHUEDeviceFromKNXState(state) // Starting from v 4.1.31
|
|
575
|
+
node.writeHueState(state)
|
|
576
576
|
node.setNodeStatusHue({
|
|
577
|
-
fill:
|
|
578
|
-
shape:
|
|
579
|
-
text:
|
|
580
|
-
payload: state
|
|
581
|
-
})
|
|
582
|
-
break
|
|
577
|
+
fill: 'green',
|
|
578
|
+
shape: 'dot',
|
|
579
|
+
text: 'KNX->HUE',
|
|
580
|
+
payload: state
|
|
581
|
+
})
|
|
582
|
+
break
|
|
583
583
|
case config.GALightBlink:
|
|
584
|
-
const gaVal = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightBlink))
|
|
584
|
+
const gaVal = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightBlink))
|
|
585
585
|
if (gaVal) {
|
|
586
586
|
node.timerBlink = setInterval(() => {
|
|
587
|
-
if (node.blinkValue === undefined) node.blinkValue = true
|
|
588
|
-
node.blinkValue = !node.blinkValue
|
|
589
|
-
msg.payload = node.blinkValue
|
|
587
|
+
if (node.blinkValue === undefined) node.blinkValue = true
|
|
588
|
+
node.blinkValue = !node.blinkValue
|
|
589
|
+
msg.payload = node.blinkValue
|
|
590
590
|
// state = msg.payload === true ? { on: { on: true } } : { on: { on: false } }
|
|
591
591
|
state = msg.payload === true
|
|
592
592
|
? { on: { on: true }, dimming: { brightness: 100 }, dynamics: { duration: 0 } }
|
|
593
|
-
: { on: { on: false }, dimming: { brightness: 0 }, dynamics: { duration: 0 } }
|
|
594
|
-
node.writeHueState(state)
|
|
595
|
-
}, 1500)
|
|
593
|
+
: { on: { on: false }, dimming: { brightness: 0 }, dynamics: { duration: 0 } }
|
|
594
|
+
node.writeHueState(state)
|
|
595
|
+
}, 1500)
|
|
596
596
|
} else {
|
|
597
|
-
if (node.timerBlink !== undefined) clearInterval(node.timerBlink)
|
|
598
|
-
node.writeHueState({ on: { on: false } })
|
|
597
|
+
if (node.timerBlink !== undefined) clearInterval(node.timerBlink)
|
|
598
|
+
node.writeHueState({ on: { on: false } })
|
|
599
599
|
}
|
|
600
600
|
node.setNodeStatusHue({
|
|
601
|
-
fill:
|
|
602
|
-
shape:
|
|
603
|
-
text:
|
|
604
|
-
payload: gaVal
|
|
605
|
-
})
|
|
606
|
-
break
|
|
601
|
+
fill: 'green',
|
|
602
|
+
shape: 'dot',
|
|
603
|
+
text: 'KNX->HUE',
|
|
604
|
+
payload: gaVal
|
|
605
|
+
})
|
|
606
|
+
break
|
|
607
607
|
case config.GALightColorCycle:
|
|
608
608
|
{
|
|
609
|
-
if (node.timerColorCycle !== undefined) clearInterval(node.timerColorCycle)
|
|
610
|
-
const gaValColorCycle = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightColorCycle))
|
|
609
|
+
if (node.timerColorCycle !== undefined) clearInterval(node.timerColorCycle)
|
|
610
|
+
const gaValColorCycle = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightColorCycle))
|
|
611
611
|
if (gaValColorCycle === true) {
|
|
612
|
-
node.writeHueState({ on: { on: true } })
|
|
612
|
+
node.writeHueState({ on: { on: true } })
|
|
613
613
|
node.timerColorCycle = setInterval(() => {
|
|
614
614
|
try {
|
|
615
|
-
const red = getRandomIntInclusive(0, 255)
|
|
616
|
-
const green = getRandomIntInclusive(0, 255)
|
|
617
|
-
const blue = getRandomIntInclusive(0, 255)
|
|
618
|
-
let gamut = null
|
|
615
|
+
const red = getRandomIntInclusive(0, 255)
|
|
616
|
+
const green = getRandomIntInclusive(0, 255)
|
|
617
|
+
const blue = getRandomIntInclusive(0, 255)
|
|
618
|
+
let gamut = null
|
|
619
619
|
if (
|
|
620
|
-
node.currentHUEDevice !== undefined
|
|
621
|
-
|
|
622
|
-
|
|
620
|
+
node.currentHUEDevice !== undefined &&
|
|
621
|
+
node.currentHUEDevice.color !== undefined &&
|
|
622
|
+
node.currentHUEDevice.color.gamut !== undefined
|
|
623
623
|
) {
|
|
624
|
-
gamut = node.currentHUEDevice.color.gamut
|
|
624
|
+
gamut = node.currentHUEDevice.color.gamut
|
|
625
625
|
}
|
|
626
|
-
const retXY = hueColorConverter.ColorConverter.calculateXYFromRGB(red, green, blue, gamut)
|
|
627
|
-
const bright = hueColorConverter.ColorConverter.getBrightnessFromRGBOrHex(red, green, blue)
|
|
628
|
-
state = bright > 0 ? { on: { on: true }, dimming: { brightness: bright }, color: { xy: retXY } } : { on: { on: false } }
|
|
629
|
-
node.writeHueState(state)
|
|
626
|
+
const retXY = hueColorConverter.ColorConverter.calculateXYFromRGB(red, green, blue, gamut)
|
|
627
|
+
const bright = hueColorConverter.ColorConverter.getBrightnessFromRGBOrHex(red, green, blue)
|
|
628
|
+
state = bright > 0 ? { on: { on: true }, dimming: { brightness: bright }, color: { xy: retXY } } : { on: { on: false } }
|
|
629
|
+
node.writeHueState(state)
|
|
630
630
|
} catch (error) { }
|
|
631
|
-
}, 10000)
|
|
631
|
+
}, 10000)
|
|
632
632
|
} else {
|
|
633
|
-
if (node.timerColorCycle !== undefined) clearInterval(node.timerColorCycle)
|
|
634
|
-
node.writeHueState({ on: { on: false } })
|
|
633
|
+
if (node.timerColorCycle !== undefined) clearInterval(node.timerColorCycle)
|
|
634
|
+
node.writeHueState({ on: { on: false } })
|
|
635
635
|
}
|
|
636
636
|
node.setNodeStatusHue({
|
|
637
|
-
fill:
|
|
638
|
-
shape:
|
|
639
|
-
text:
|
|
640
|
-
payload: gaValColorCycle
|
|
641
|
-
})
|
|
637
|
+
fill: 'green',
|
|
638
|
+
shape: 'dot',
|
|
639
|
+
text: 'KNX->HUE',
|
|
640
|
+
payload: gaValColorCycle
|
|
641
|
+
})
|
|
642
642
|
}
|
|
643
|
-
break
|
|
643
|
+
break
|
|
644
644
|
default:
|
|
645
|
-
break
|
|
645
|
+
break
|
|
646
646
|
}
|
|
647
647
|
} catch (error) {
|
|
648
648
|
node.status({
|
|
649
|
-
fill:
|
|
650
|
-
shape:
|
|
651
|
-
text: `KNX->HUE errorRead ${error.message} (${formatTs(new Date())})
|
|
652
|
-
})
|
|
653
|
-
RED.log.error(`knxUltimateHueLight: node.handleSend: if (msg.knx.event !== "GroupValue_Read"): ${error.message} : ${error.stack ||
|
|
649
|
+
fill: 'red',
|
|
650
|
+
shape: 'dot',
|
|
651
|
+
text: `KNX->HUE errorRead ${error.message} (${formatTs(new Date())})`
|
|
652
|
+
})
|
|
653
|
+
RED.log.error(`knxUltimateHueLight: node.handleSend: if (msg.knx.event !== "GroupValue_Read"): ${error.message} : ${error.stack || ''} `)
|
|
654
654
|
}
|
|
655
655
|
}
|
|
656
656
|
|
|
657
657
|
// I must respond to query requests (read request) sent from the KNX BUS
|
|
658
658
|
try {
|
|
659
|
-
if (msg.knx.event ===
|
|
660
|
-
const zeroBrightnessWhenOff = (config.updateKNXBrightnessStatusOnHUEOnOff === undefined || config.updateKNXBrightnessStatusOnHUEOnOff ===
|
|
661
|
-
let ret
|
|
659
|
+
if (msg.knx.event === 'GroupValue_Read' && node.currentHUEDevice !== undefined) {
|
|
660
|
+
const zeroBrightnessWhenOff = (config.updateKNXBrightnessStatusOnHUEOnOff === undefined || config.updateKNXBrightnessStatusOnHUEOnOff === 'onhueoff')
|
|
661
|
+
let ret
|
|
662
662
|
switch (msg.knx.destination) {
|
|
663
663
|
case config.GALightState:
|
|
664
|
-
ret = node.currentHUEDevice.on.on
|
|
665
|
-
if (ret !== undefined) node.updateKNXLightState(ret,
|
|
666
|
-
break
|
|
664
|
+
ret = node.currentHUEDevice.on.on
|
|
665
|
+
if (ret !== undefined) node.updateKNXLightState(ret, 'response')
|
|
666
|
+
break
|
|
667
667
|
case config.GALightColorState:
|
|
668
|
-
ret = node.currentHUEDevice.color.xy
|
|
669
|
-
if (ret !== undefined) node.updateKNXLightColorState(node.currentHUEDevice.color,
|
|
670
|
-
break
|
|
668
|
+
ret = node.currentHUEDevice.color.xy
|
|
669
|
+
if (ret !== undefined) node.updateKNXLightColorState(node.currentHUEDevice.color, 'response')
|
|
670
|
+
break
|
|
671
671
|
case config.GALightKelvinPercentageState:
|
|
672
672
|
// The kelvin level belongs to the group defice, so i don't need to get the first light in the collection (if the device is a grouped_light)
|
|
673
|
-
ret = node.currentHUEDevice.color_temperature.mirek
|
|
674
|
-
if (ret !== undefined) node.updateKNXLightKelvinPercentageState(ret,
|
|
673
|
+
ret = node.currentHUEDevice.color_temperature.mirek
|
|
674
|
+
if (ret !== undefined) node.updateKNXLightKelvinPercentageState(ret, 'response')
|
|
675
675
|
// if (node.isGrouped_light === false) {
|
|
676
676
|
// ret = node.currentHUEDevice.color_temperature.mirek;
|
|
677
677
|
// if (ret !== undefined) node.updateKNXLightKelvinPercentageState(ret, "response");
|
|
@@ -691,21 +691,21 @@ module.exports = function (RED) {
|
|
|
691
691
|
// } catch (error) { /* empty */ }
|
|
692
692
|
// })();
|
|
693
693
|
// }
|
|
694
|
-
break
|
|
694
|
+
break
|
|
695
695
|
case config.GALightBrightnessState:
|
|
696
696
|
// Hue keeps the last brightness even when the light is OFF. If the user enabled "brightness status -> 0 on HUE off",
|
|
697
697
|
// keep returning 0 while OFF to avoid the KNX status jumping back to the last/start value after some time/read-requests.
|
|
698
698
|
if (zeroBrightnessWhenOff === true && node.currentHUEDevice?.on?.on === false) {
|
|
699
|
-
ret = 0
|
|
699
|
+
ret = 0
|
|
700
700
|
} else {
|
|
701
|
-
ret = node.currentHUEDevice.dimming.brightness
|
|
701
|
+
ret = node.currentHUEDevice.dimming.brightness
|
|
702
702
|
}
|
|
703
|
-
if (ret !== undefined) node.updateKNXBrightnessState(ret,
|
|
704
|
-
break
|
|
703
|
+
if (ret !== undefined) node.updateKNXBrightnessState(ret, 'response')
|
|
704
|
+
break
|
|
705
705
|
case config.GALightKelvinState:
|
|
706
706
|
// The kelvin level belongs to the group defice, so i don't need to get the first light in the collection (if the device is a grouped_light)
|
|
707
|
-
ret = node.currentHUEDevice.color_temperature.mirek
|
|
708
|
-
if (ret !== undefined) node.updateKNXLightKelvinState(ret,
|
|
707
|
+
ret = node.currentHUEDevice.color_temperature.mirek
|
|
708
|
+
if (ret !== undefined) node.updateKNXLightKelvinState(ret, 'response')
|
|
709
709
|
// if (node.isGrouped_light === false) {
|
|
710
710
|
// ret = node.currentHUEDevice.color_temperature.mirek;
|
|
711
711
|
// if (ret !== undefined) node.updateKNXLightKelvinState(ret, "response");
|
|
@@ -725,178 +725,177 @@ module.exports = function (RED) {
|
|
|
725
725
|
// } catch (error) { /* empty */ }
|
|
726
726
|
// })();
|
|
727
727
|
// }
|
|
728
|
-
break
|
|
728
|
+
break
|
|
729
729
|
default:
|
|
730
|
-
break
|
|
730
|
+
break
|
|
731
731
|
}
|
|
732
732
|
}
|
|
733
733
|
} catch (error) {
|
|
734
734
|
node.status({
|
|
735
|
-
fill:
|
|
736
|
-
shape:
|
|
737
|
-
text: `KNX->HUE error :-( ${error.message} (${formatTs(new Date())})
|
|
738
|
-
})
|
|
739
|
-
RED.log.error(`knxUltimateHueLight: node.handleSend: if (msg.knx.event === "GroupValue_Read" && node.currentHUEDevice !== undefined): ${error.message} : ${error.stack ||
|
|
735
|
+
fill: 'red',
|
|
736
|
+
shape: 'dot',
|
|
737
|
+
text: `KNX->HUE error :-( ${error.message} (${formatTs(new Date())})`
|
|
738
|
+
})
|
|
739
|
+
RED.log.error(`knxUltimateHueLight: node.handleSend: if (msg.knx.event === "GroupValue_Read" && node.currentHUEDevice !== undefined): ${error.message} : ${error.stack || ''} `)
|
|
740
740
|
}
|
|
741
|
-
}
|
|
741
|
+
}
|
|
742
742
|
|
|
743
743
|
// Start dimming
|
|
744
744
|
// ***********************************************************
|
|
745
|
-
node.hueDimming = function hueDimming(_KNXaction, _KNXbrightness_Direction, _dimSpeedInMillisecs = undefined) {
|
|
745
|
+
node.hueDimming = function hueDimming (_KNXaction, _KNXbrightness_Direction, _dimSpeedInMillisecs = undefined) {
|
|
746
746
|
// 31/10/2023 after many attempts to use dimming_delta function of the HueApeV2, loosing days of my life, without a decent success, will use the standard dimming calculations
|
|
747
747
|
// i decide to go to the "step brightness" way.
|
|
748
748
|
try {
|
|
749
|
-
let hueTelegram = {}
|
|
750
|
-
let numStep = 10
|
|
751
|
-
const extendedConf = {}
|
|
749
|
+
let hueTelegram = {}
|
|
750
|
+
let numStep = 10 // Steps from 0 to 100 by 10
|
|
751
|
+
const extendedConf = {}
|
|
752
752
|
|
|
753
753
|
if (_KNXbrightness_Direction === 0 && _KNXaction === 0) {
|
|
754
754
|
// STOP DIM
|
|
755
|
-
if (node.timerStepDim !== undefined) clearInterval(node.timerStepDim)
|
|
756
|
-
node.brightnessStep = null
|
|
757
|
-
node.deleteHueStateQueue()
|
|
758
|
-
return
|
|
755
|
+
if (node.timerStepDim !== undefined) clearInterval(node.timerStepDim)
|
|
756
|
+
node.brightnessStep = null
|
|
757
|
+
node.deleteHueStateQueue() // Clear dimming queue.
|
|
758
|
+
return
|
|
759
759
|
}
|
|
760
760
|
|
|
761
761
|
// 26/03/2024 set the extended configuration as well, because the light was off (so i've been unable to set it up elsewhere)
|
|
762
762
|
if (node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === false) {
|
|
763
763
|
// if (node.currentHUEDevice.color !== undefined) extendedConf.color = { xy: node.currentHUEDevice.color.xy }; // DO NOT ADD THE COLOR, BECAUSE THE COLOR HAS ALSO THE BRIGHTNESS, SO ALL THE DATA NEEDED TO BE SWITCHED ON CORRECLY
|
|
764
|
-
if (node.currentHUEDevice.color_temperature !== undefined) extendedConf.color_temperature = { mirek: node.currentHUEDevice.color_temperature.mirek }
|
|
764
|
+
if (node.currentHUEDevice.color_temperature !== undefined) extendedConf.color_temperature = { mirek: node.currentHUEDevice.color_temperature.mirek }
|
|
765
765
|
}
|
|
766
766
|
|
|
767
767
|
// If i'm dimming up while the light is off, start the dim with the initial brightness set to zero
|
|
768
768
|
if (_KNXbrightness_Direction > 0 && _KNXaction === 1 && node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === false) {
|
|
769
|
-
node.brightnessStep = null
|
|
770
|
-
node.currentHUEDevice.dimming.brightness = 0
|
|
769
|
+
node.brightnessStep = null
|
|
770
|
+
node.currentHUEDevice.dimming.brightness = 0
|
|
771
771
|
}
|
|
772
772
|
|
|
773
773
|
// Set the actual brightness to start with
|
|
774
|
-
if (node.brightnessStep === null || node.brightnessStep === undefined) node.brightnessStep = node.currentHUEDevice.dimming.brightness !== undefined ? node.currentHUEDevice.dimming.brightness : 50
|
|
775
|
-
node.brightnessStep = Math.ceil(Number(node.brightnessStep))
|
|
774
|
+
if (node.brightnessStep === null || node.brightnessStep === undefined) node.brightnessStep = node.currentHUEDevice.dimming.brightness !== undefined ? node.currentHUEDevice.dimming.brightness : 50
|
|
775
|
+
node.brightnessStep = Math.ceil(Number(node.brightnessStep))
|
|
776
776
|
|
|
777
777
|
// We have also minDimLevelLight and maxDimLevelLight to take care of.
|
|
778
|
-
let minDimLevelLight
|
|
778
|
+
let minDimLevelLight
|
|
779
779
|
if (config.minDimLevelLight === undefined) {
|
|
780
|
-
minDimLevelLight = 10
|
|
781
|
-
} else if (config.minDimLevelLight ===
|
|
782
|
-
minDimLevelLight = node.currentHUEDevice.dimming.min_dim_level === undefined ? 10 : node.currentHUEDevice.dimming.min_dim_level
|
|
780
|
+
minDimLevelLight = 10
|
|
781
|
+
} else if (config.minDimLevelLight === 'useHueLightLevel') {
|
|
782
|
+
minDimLevelLight = node.currentHUEDevice.dimming.min_dim_level === undefined ? 10 : node.currentHUEDevice.dimming.min_dim_level
|
|
783
783
|
} else {
|
|
784
|
-
minDimLevelLight = Number(config.minDimLevelLight)
|
|
784
|
+
minDimLevelLight = Number(config.minDimLevelLight)
|
|
785
785
|
}
|
|
786
|
-
const maxDimLevelLight = config.maxDimLevelLight === undefined ? 100 : Number(config.maxDimLevelLight)
|
|
786
|
+
const maxDimLevelLight = config.maxDimLevelLight === undefined ? 100 : Number(config.maxDimLevelLight)
|
|
787
787
|
|
|
788
788
|
// Set the speed
|
|
789
|
-
_dimSpeedInMillisecs /= numStep
|
|
790
|
-
numStep = Math.round((maxDimLevelLight - minDimLevelLight) / numStep, 0)
|
|
789
|
+
_dimSpeedInMillisecs /= numStep
|
|
790
|
+
numStep = Math.round((maxDimLevelLight - minDimLevelLight) / numStep, 0)
|
|
791
791
|
|
|
792
792
|
if (_KNXbrightness_Direction > 0 && _KNXaction === 1) {
|
|
793
793
|
// DIM UP
|
|
794
|
-
if (node.timerStepDim !== undefined) clearInterval(node.timerStepDim)
|
|
794
|
+
if (node.timerStepDim !== undefined) clearInterval(node.timerStepDim)
|
|
795
795
|
node.timerStepDim = setInterval(() => {
|
|
796
|
-
node.updateKNXBrightnessState(node.brightnessStep)
|
|
797
|
-
node.brightnessStep += numStep
|
|
798
|
-
if (node.brightnessStep > maxDimLevelLight) node.brightnessStep = maxDimLevelLight
|
|
799
|
-
hueTelegram = { dimming: { brightness: node.brightnessStep }, dynamics: { duration: _dimSpeedInMillisecs + 500 } }
|
|
796
|
+
node.updateKNXBrightnessState(node.brightnessStep) // Unnecessary, but necessary to set the KNX Status in real time.
|
|
797
|
+
node.brightnessStep += numStep
|
|
798
|
+
if (node.brightnessStep > maxDimLevelLight) node.brightnessStep = maxDimLevelLight
|
|
799
|
+
hueTelegram = { dimming: { brightness: node.brightnessStep }, dynamics: { duration: _dimSpeedInMillisecs + 500 } } // + is to avoid ladder effect
|
|
800
800
|
// Switch on the light if off
|
|
801
801
|
if (node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === false) {
|
|
802
|
-
hueTelegram.on = { on: true }
|
|
803
|
-
Object.assign(hueTelegram, extendedConf)
|
|
802
|
+
hueTelegram.on = { on: true }
|
|
803
|
+
Object.assign(hueTelegram, extendedConf) // 26/03/2024 add extended conf
|
|
804
804
|
}
|
|
805
|
-
//console.log(hueTelegram)
|
|
806
|
-
node.writeHueState(hueTelegram)
|
|
807
|
-
if (node.brightnessStep >= maxDimLevelLight) clearInterval(node.timerStepDim)
|
|
808
|
-
}, _dimSpeedInMillisecs)
|
|
805
|
+
// console.log(hueTelegram)
|
|
806
|
+
node.writeHueState(hueTelegram)
|
|
807
|
+
if (node.brightnessStep >= maxDimLevelLight) clearInterval(node.timerStepDim)
|
|
808
|
+
}, _dimSpeedInMillisecs)
|
|
809
809
|
}
|
|
810
810
|
if (_KNXbrightness_Direction > 0 && _KNXaction === 0) {
|
|
811
|
-
if (node.currentHUEDevice.on.on === false) return
|
|
811
|
+
if (node.currentHUEDevice.on.on === false) return // Don't dim down, if the light is already off.
|
|
812
812
|
// DIM DOWN
|
|
813
|
-
if (node.timerStepDim !== undefined) clearInterval(node.timerStepDim)
|
|
813
|
+
if (node.timerStepDim !== undefined) clearInterval(node.timerStepDim)
|
|
814
814
|
node.timerStepDim = setInterval(() => {
|
|
815
|
-
node.updateKNXBrightnessState(node.brightnessStep)
|
|
816
|
-
node.brightnessStep -= numStep
|
|
817
|
-
if (node.brightnessStep < minDimLevelLight) node.brightnessStep = minDimLevelLight
|
|
818
|
-
hueTelegram = { dimming: { brightness: node.brightnessStep }, dynamics: { duration: _dimSpeedInMillisecs + 500 } }
|
|
815
|
+
node.updateKNXBrightnessState(node.brightnessStep) // Unnecessary, but necessary to set the KNX Status in real time.
|
|
816
|
+
node.brightnessStep -= numStep
|
|
817
|
+
if (node.brightnessStep < minDimLevelLight) node.brightnessStep = minDimLevelLight
|
|
818
|
+
hueTelegram = { dimming: { brightness: node.brightnessStep }, dynamics: { duration: _dimSpeedInMillisecs + 500 } }// + 100 is to avoid ladder effect
|
|
819
819
|
// Switch off the light if on
|
|
820
820
|
if (node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === true && node.brightnessStep === 0) {
|
|
821
|
-
hueTelegram.on = { on: false }
|
|
821
|
+
hueTelegram.on = { on: false }
|
|
822
822
|
}
|
|
823
|
-
node.writeHueState(hueTelegram)
|
|
824
|
-
if (node.brightnessStep <= minDimLevelLight) clearInterval(node.timerStepDim)
|
|
825
|
-
}, _dimSpeedInMillisecs)
|
|
823
|
+
node.writeHueState(hueTelegram)
|
|
824
|
+
if (node.brightnessStep <= minDimLevelLight) clearInterval(node.timerStepDim)
|
|
825
|
+
}, _dimSpeedInMillisecs)
|
|
826
826
|
}
|
|
827
827
|
} catch (error) { }
|
|
828
|
-
}
|
|
828
|
+
}
|
|
829
829
|
// ***********************************************************
|
|
830
830
|
|
|
831
831
|
// Start dimming tunable white
|
|
832
832
|
// mirek: required(integer minimum: 153, maximum: 500)
|
|
833
833
|
// ***********************************************************
|
|
834
|
-
node.hueDimmingTunableWhite = function hueDimmingTunableWhite(_KNXaction, _KNXbrightness_DirectionTunableWhite, _dimSpeedInMillisecsTunableWhite = undefined) {
|
|
834
|
+
node.hueDimmingTunableWhite = function hueDimmingTunableWhite (_KNXaction, _KNXbrightness_DirectionTunableWhite, _dimSpeedInMillisecsTunableWhite = undefined) {
|
|
835
835
|
// 23/23/2023 after many attempts to use dimming_delta function of the HueApeV2, loosing days of my life, without a decent success, will use the standard dimming calculations
|
|
836
836
|
// i decide to go to the "step brightness" way.
|
|
837
837
|
try {
|
|
838
|
-
|
|
839
838
|
if (_KNXbrightness_DirectionTunableWhite === 0 && _KNXaction === 0) {
|
|
840
839
|
// STOP DIM
|
|
841
|
-
if (node.timerStepDimTunableWhite !== undefined) clearInterval(node.timerStepDimTunableWhite)
|
|
842
|
-
node.brightnessStepTunableWhite = null
|
|
843
|
-
node.deleteHueStateQueue()
|
|
844
|
-
return
|
|
840
|
+
if (node.timerStepDimTunableWhite !== undefined) clearInterval(node.timerStepDimTunableWhite)
|
|
841
|
+
node.brightnessStepTunableWhite = null
|
|
842
|
+
node.deleteHueStateQueue() // Clear dimming queue.
|
|
843
|
+
return
|
|
845
844
|
}
|
|
846
845
|
|
|
847
|
-
let numStepTunableWhite = 10
|
|
846
|
+
let numStepTunableWhite = 10 // Steps from 153 to 500
|
|
848
847
|
if (config.invertDimTunableWhiteDirection === true) {
|
|
849
|
-
if (_KNXaction === 1) { _KNXaction = 0
|
|
848
|
+
if (_KNXaction === 1) { _KNXaction = 0 } else { _KNXaction = 1 }
|
|
850
849
|
}
|
|
851
850
|
|
|
852
851
|
// Set the actual brightness to start with
|
|
853
|
-
if (node.brightnessStepTunableWhite === null || node.brightnessStepTunableWhite === undefined) node.brightnessStepTunableWhite = node.currentHUEDevice.color_temperature.mirek || 372
|
|
854
|
-
node.brightnessStepTunableWhite = Math.ceil(Number(node.brightnessStepTunableWhite))
|
|
852
|
+
if (node.brightnessStepTunableWhite === null || node.brightnessStepTunableWhite === undefined) node.brightnessStepTunableWhite = node.currentHUEDevice.color_temperature.mirek || 372
|
|
853
|
+
node.brightnessStepTunableWhite = Math.ceil(Number(node.brightnessStepTunableWhite))
|
|
855
854
|
|
|
856
855
|
// Set the speed
|
|
857
|
-
_dimSpeedInMillisecsTunableWhite = Math.ceil(_dimSpeedInMillisecsTunableWhite / numStepTunableWhite)
|
|
856
|
+
_dimSpeedInMillisecsTunableWhite = Math.ceil(_dimSpeedInMillisecsTunableWhite / numStepTunableWhite)
|
|
858
857
|
|
|
859
|
-
const minDimLevelLightTunableWhite = 153
|
|
860
|
-
const maxDimLevelLightTunableWhite = 500
|
|
861
|
-
//numStepTunableWhite = hueColorConverter.ColorConverter.scale(numStepTunableWhite, [0, 100], [minDimLevelLightTunableWhite, maxDimLevelLightTunableWhite]);
|
|
862
|
-
//numStepTunableWhite = hueColorConverter.ColorConverter.scale(numStepTunableWhite, [node.brightnessStepTunableWhite, maxDimLevelLightTunableWhite], [node.brightnessStepTunableWhite, maxDimLevelLightTunableWhite]);
|
|
863
|
-
numStepTunableWhite = Math.round((maxDimLevelLightTunableWhite - minDimLevelLightTunableWhite) / numStepTunableWhite, 0)
|
|
858
|
+
const minDimLevelLightTunableWhite = 153
|
|
859
|
+
const maxDimLevelLightTunableWhite = 500
|
|
860
|
+
// numStepTunableWhite = hueColorConverter.ColorConverter.scale(numStepTunableWhite, [0, 100], [minDimLevelLightTunableWhite, maxDimLevelLightTunableWhite]);
|
|
861
|
+
// numStepTunableWhite = hueColorConverter.ColorConverter.scale(numStepTunableWhite, [node.brightnessStepTunableWhite, maxDimLevelLightTunableWhite], [node.brightnessStepTunableWhite, maxDimLevelLightTunableWhite]);
|
|
862
|
+
numStepTunableWhite = Math.round((maxDimLevelLightTunableWhite - minDimLevelLightTunableWhite) / numStepTunableWhite, 0)
|
|
864
863
|
|
|
865
864
|
if (_KNXbrightness_DirectionTunableWhite > 0 && _KNXaction === 1) {
|
|
866
865
|
// DIM UP
|
|
867
|
-
if (node.timerStepDimTunableWhite !== undefined) clearInterval(node.timerStepDimTunableWhite)
|
|
866
|
+
if (node.timerStepDimTunableWhite !== undefined) clearInterval(node.timerStepDimTunableWhite)
|
|
868
867
|
node.timerStepDimTunableWhite = setInterval(() => {
|
|
869
|
-
node.updateKNXLightKelvinPercentageState(node.brightnessStepTunableWhite)
|
|
870
|
-
node.brightnessStepTunableWhite += numStepTunableWhite
|
|
871
|
-
if (node.brightnessStepTunableWhite > maxDimLevelLightTunableWhite) node.brightnessStepTunableWhite = maxDimLevelLightTunableWhite
|
|
872
|
-
const hueTelegram = { color_temperature: { mirek: node.brightnessStepTunableWhite }, dynamics: { duration: _dimSpeedInMillisecsTunableWhite } }
|
|
868
|
+
node.updateKNXLightKelvinPercentageState(node.brightnessStepTunableWhite) // Unnecessary, but necessary to set the KNX Status in real time.
|
|
869
|
+
node.brightnessStepTunableWhite += numStepTunableWhite // *2 to speed up the things
|
|
870
|
+
if (node.brightnessStepTunableWhite > maxDimLevelLightTunableWhite) node.brightnessStepTunableWhite = maxDimLevelLightTunableWhite
|
|
871
|
+
const hueTelegram = { color_temperature: { mirek: node.brightnessStepTunableWhite }, dynamics: { duration: _dimSpeedInMillisecsTunableWhite } }
|
|
873
872
|
// Switch on the light if off
|
|
874
873
|
if (node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === false) {
|
|
875
|
-
hueTelegram.on = { on: true }
|
|
874
|
+
hueTelegram.on = { on: true }
|
|
876
875
|
}
|
|
877
|
-
node.writeHueState(hueTelegram)
|
|
878
|
-
if (node.brightnessStepTunableWhite >= maxDimLevelLightTunableWhite) clearInterval(node.timerStepDimTunableWhite)
|
|
879
|
-
}, _dimSpeedInMillisecsTunableWhite)
|
|
876
|
+
node.writeHueState(hueTelegram)
|
|
877
|
+
if (node.brightnessStepTunableWhite >= maxDimLevelLightTunableWhite) clearInterval(node.timerStepDimTunableWhite)
|
|
878
|
+
}, _dimSpeedInMillisecsTunableWhite)
|
|
880
879
|
}
|
|
881
880
|
if (_KNXbrightness_DirectionTunableWhite > 0 && _KNXaction === 0) {
|
|
882
|
-
if (node.currentHUEDevice.on.on === false) return
|
|
881
|
+
if (node.currentHUEDevice.on.on === false) return // Don't dim down, if the light is already off.
|
|
883
882
|
// DIM DOWN
|
|
884
|
-
if (node.timerStepDimTunableWhite !== undefined) clearInterval(node.timerStepDimTunableWhite)
|
|
883
|
+
if (node.timerStepDimTunableWhite !== undefined) clearInterval(node.timerStepDimTunableWhite)
|
|
885
884
|
node.timerStepDimTunableWhite = setInterval(() => {
|
|
886
|
-
node.updateKNXLightKelvinPercentageState(node.brightnessStepTunableWhite)
|
|
887
|
-
node.brightnessStepTunableWhite -= numStepTunableWhite
|
|
888
|
-
if (node.brightnessStepTunableWhite < minDimLevelLightTunableWhite) node.brightnessStepTunableWhite = minDimLevelLightTunableWhite
|
|
889
|
-
const hueTelegram = { color_temperature: { mirek: node.brightnessStepTunableWhite }, dynamics: { duration: _dimSpeedInMillisecsTunableWhite } }
|
|
885
|
+
node.updateKNXLightKelvinPercentageState(node.brightnessStepTunableWhite) // Unnecessary, but necessary to set the KNX Status in real time.
|
|
886
|
+
node.brightnessStepTunableWhite -= numStepTunableWhite // *2 to speed up the things
|
|
887
|
+
if (node.brightnessStepTunableWhite < minDimLevelLightTunableWhite) node.brightnessStepTunableWhite = minDimLevelLightTunableWhite
|
|
888
|
+
const hueTelegram = { color_temperature: { mirek: node.brightnessStepTunableWhite }, dynamics: { duration: _dimSpeedInMillisecsTunableWhite } }
|
|
890
889
|
// Switch off the light if on
|
|
891
890
|
if (node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === true && node.brightnessStepTunableWhite === 0) {
|
|
892
|
-
hueTelegram.on = { on: false }
|
|
891
|
+
hueTelegram.on = { on: false }
|
|
893
892
|
}
|
|
894
|
-
node.writeHueState(hueTelegram)
|
|
895
|
-
if (node.brightnessStepTunableWhite <= minDimLevelLightTunableWhite) clearInterval(node.timerStepDimTunableWhite)
|
|
896
|
-
}, _dimSpeedInMillisecsTunableWhite)
|
|
893
|
+
node.writeHueState(hueTelegram)
|
|
894
|
+
if (node.brightnessStepTunableWhite <= minDimLevelLightTunableWhite) clearInterval(node.timerStepDimTunableWhite)
|
|
895
|
+
}, _dimSpeedInMillisecsTunableWhite)
|
|
897
896
|
}
|
|
898
897
|
} catch (error) { }
|
|
899
|
-
}
|
|
898
|
+
}
|
|
900
899
|
// ***********************************************************
|
|
901
900
|
|
|
902
901
|
/**
|
|
@@ -906,87 +905,87 @@ module.exports = function (RED) {
|
|
|
906
905
|
* @param {number} _dimSpeedInMillisecsHSV Speed time in milliseconds
|
|
907
906
|
* @returns {}
|
|
908
907
|
*/
|
|
909
|
-
node.hueDimmingHSV_H = function hueDimmingHSV_H(_KNXaction, _KNXbrightness_DirectionHSV_H, _dimSpeedInMillisecsHSV = undefined) {
|
|
908
|
+
node.hueDimmingHSV_H = function hueDimmingHSV_H (_KNXaction, _KNXbrightness_DirectionHSV_H, _dimSpeedInMillisecsHSV = undefined) {
|
|
910
909
|
// After many attempts to use dimming_delta function of the HueApiV2, loosing days of my life, without a decent success, will use the standard dimming calculations
|
|
911
910
|
// i decide to go to the "step brightness" way.
|
|
912
911
|
try {
|
|
913
912
|
if (_KNXbrightness_DirectionHSV_H === 0 && _KNXaction === 0) {
|
|
914
913
|
// STOP DIM
|
|
915
|
-
if (node.timerStepDimHSV_H !== undefined) clearInterval(node.timerStepDimHSV_H)
|
|
916
|
-
node.deleteHueStateQueue()
|
|
917
|
-
return
|
|
914
|
+
if (node.timerStepDimHSV_H !== undefined) clearInterval(node.timerStepDimHSV_H)
|
|
915
|
+
node.deleteHueStateQueue() // Clear dimming queue.
|
|
916
|
+
return
|
|
918
917
|
}
|
|
919
918
|
|
|
920
|
-
let xyBrightnessToHsv
|
|
919
|
+
let xyBrightnessToHsv
|
|
921
920
|
if (node.currentHUEDevice.color !== undefined && node.currentHUEDevice.color.xy !== undefined) {
|
|
922
921
|
// Get the XY + brightness from the lamp and transform it into HSV
|
|
923
922
|
// xyBrightnessToHsv = hueColorConverter.ColorConverter.xyBrightnessToHsv(node.currentHUEDevice.color.xy.x, node.currentHUEDevice.color.xy.y, node.currentHUEDevice.dimming.brightness);
|
|
924
|
-
xyBrightnessToHsv = hueColorConverter.ColorConverter.xyBrightnessToHsv(hueColorConverter.ColorConverter.scale(node.currentHUEDevice.color.xy.x, [0, 1], [0, 100]), hueColorConverter.ColorConverter.scale(node.currentHUEDevice.color.xy.y, [0, 1], [0, 100]), node.currentHUEDevice.dimming.brightness)
|
|
923
|
+
xyBrightnessToHsv = hueColorConverter.ColorConverter.xyBrightnessToHsv(hueColorConverter.ColorConverter.scale(node.currentHUEDevice.color.xy.x, [0, 1], [0, 100]), hueColorConverter.ColorConverter.scale(node.currentHUEDevice.color.xy.y, [0, 1], [0, 100]), node.currentHUEDevice.dimming.brightness)
|
|
925
924
|
} else {
|
|
926
|
-
return
|
|
925
|
+
return // Something wrong here.
|
|
927
926
|
}
|
|
928
|
-
let numStepHSV_H = 10
|
|
927
|
+
let numStepHSV_H = 10 // Steps from 0 to 100
|
|
929
928
|
|
|
930
929
|
// Set the actual brightness to start with
|
|
931
|
-
if (node.brightnessStepHSV_H === null || node.brightnessStepHSV_H === undefined) node.brightnessStepHSV_H = node.currentHUEDevice.dimming.brightness
|
|
932
|
-
node.brightnessStepHSV_H = Math.ceil(Number(node.brightnessStepHSV_H))
|
|
930
|
+
if (node.brightnessStepHSV_H === null || node.brightnessStepHSV_H === undefined) node.brightnessStepHSV_H = node.currentHUEDevice.dimming.brightness
|
|
931
|
+
node.brightnessStepHSV_H = Math.ceil(Number(node.brightnessStepHSV_H))
|
|
933
932
|
|
|
934
|
-
const minDimLevelLightHSV_H = 1
|
|
935
|
-
const maxDimLevelLightHSV_H = 100
|
|
936
|
-
numStepHSV_H = Math.round((maxDimLevelLightHSV_H - minDimLevelLightHSV_H) / numStepHSV_H, 0)
|
|
933
|
+
const minDimLevelLightHSV_H = 1
|
|
934
|
+
const maxDimLevelLightHSV_H = 100
|
|
935
|
+
numStepHSV_H = Math.round((maxDimLevelLightHSV_H - minDimLevelLightHSV_H) / numStepHSV_H, 0)
|
|
937
936
|
// Set the speed
|
|
938
|
-
_dimSpeedInMillisecsHSV = Math.ceil(_dimSpeedInMillisecsHSV / (maxDimLevelLightHSV_H / numStepHSV_H))
|
|
937
|
+
_dimSpeedInMillisecsHSV = Math.ceil(_dimSpeedInMillisecsHSV / (maxDimLevelLightHSV_H / numStepHSV_H))
|
|
939
938
|
|
|
940
939
|
if (_KNXbrightness_DirectionHSV_H > 0 && _KNXaction === 1) {
|
|
941
940
|
// DIM UP
|
|
942
|
-
if (node.timerStepDimHSV_H !== undefined) clearInterval(node.timerStepDimHSV_H)
|
|
941
|
+
if (node.timerStepDimHSV_H !== undefined) clearInterval(node.timerStepDimHSV_H)
|
|
943
942
|
node.timerStepDimHSV_H = setInterval(() => {
|
|
944
|
-
node.deleteHueStateQueue()
|
|
945
|
-
node.brightnessStepHSV_H += numStepHSV_H
|
|
946
|
-
if (node.brightnessStepHSV_H > maxDimLevelLightHSV_H) node.brightnessStepHSV_H = maxDimLevelLightHSV_H
|
|
947
|
-
//node.updateKNXLightHSV_H_State(node.brightnessStepHSV_H); // Unnecessary, but necessary to set the KNX Status in real time.
|
|
948
|
-
xyBrightnessToHsv.h = node.brightnessStepHSV_H
|
|
949
|
-
const hsvToXYBri = hueColorConverter.ColorConverter.hsvToxyBrightness(xyBrightnessToHsv, node.currentHUEDevice.color.gamut)
|
|
950
|
-
const hueTelegram = { color: { xy: { x: hsvToXYBri.x, y: hsvToXYBri.y } }, dynamics: { duration: _dimSpeedInMillisecsHSV + 500 } }
|
|
943
|
+
node.deleteHueStateQueue() // Clear dimming queue.
|
|
944
|
+
node.brightnessStepHSV_H += numStepHSV_H
|
|
945
|
+
if (node.brightnessStepHSV_H > maxDimLevelLightHSV_H) node.brightnessStepHSV_H = maxDimLevelLightHSV_H
|
|
946
|
+
// node.updateKNXLightHSV_H_State(node.brightnessStepHSV_H); // Unnecessary, but necessary to set the KNX Status in real time.
|
|
947
|
+
xyBrightnessToHsv.h = node.brightnessStepHSV_H
|
|
948
|
+
const hsvToXYBri = hueColorConverter.ColorConverter.hsvToxyBrightness(xyBrightnessToHsv, node.currentHUEDevice.color.gamut)
|
|
949
|
+
const hueTelegram = { color: { xy: { x: hsvToXYBri.x, y: hsvToXYBri.y } }, dynamics: { duration: _dimSpeedInMillisecsHSV + 500 } } // Add some ms, to prevent the "ladder" step effect.
|
|
951
950
|
// Switch on the light if off
|
|
952
951
|
if (node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === false) {
|
|
953
|
-
hueTelegram.on = { on: true }
|
|
952
|
+
hueTelegram.on = { on: true }
|
|
954
953
|
}
|
|
955
|
-
node.currentHUEDevice.color.xy = hsvToXYBri
|
|
956
|
-
node.updateKNXLightColorState(node.currentHUEDevice.color)
|
|
957
|
-
node.writeHueState(hueTelegram)
|
|
954
|
+
node.currentHUEDevice.color.xy = hsvToXYBri// Unnecessary, but necessary to set the KNX Status in real time.
|
|
955
|
+
node.updateKNXLightColorState(node.currentHUEDevice.color)
|
|
956
|
+
node.writeHueState(hueTelegram)
|
|
958
957
|
if (node.brightnessStepHSV_H >= maxDimLevelLightHSV_H) {
|
|
959
|
-
if (node.timerStepDimHSV_H !== undefined) clearInterval(node.timerStepDimHSV_H)
|
|
958
|
+
if (node.timerStepDimHSV_H !== undefined) clearInterval(node.timerStepDimHSV_H)
|
|
960
959
|
}
|
|
961
|
-
}, _dimSpeedInMillisecsHSV)
|
|
960
|
+
}, _dimSpeedInMillisecsHSV)
|
|
962
961
|
}
|
|
963
962
|
if (_KNXbrightness_DirectionHSV_H > 0 && _KNXaction === 0) {
|
|
964
|
-
if (node.currentHUEDevice.on.on === false) return
|
|
963
|
+
if (node.currentHUEDevice.on.on === false) return // Don't dim down, if the light is already off.
|
|
965
964
|
// DIM DOWN
|
|
966
|
-
if (node.timerStepDimHSV_H !== undefined) clearInterval(node.timerStepDimHSV_H)
|
|
965
|
+
if (node.timerStepDimHSV_H !== undefined) clearInterval(node.timerStepDimHSV_H)
|
|
967
966
|
node.timerStepDimHSV_H = setInterval(() => {
|
|
968
|
-
node.deleteHueStateQueue()
|
|
969
|
-
node.brightnessStepHSV_H -= numStepHSV_H
|
|
970
|
-
if (node.brightnessStepHSV_H < minDimLevelLightHSV_H) node.brightnessStepHSV_H = minDimLevelLightHSV_H
|
|
971
|
-
//node.updateKNXLightHSV_H_State(node.brightnessStepHSV_H); // Unnecessary, but necessary to set the KNX Status in real time.
|
|
967
|
+
node.deleteHueStateQueue() // Clear dimming queue.
|
|
968
|
+
node.brightnessStepHSV_H -= numStepHSV_H // *2 to speed up the things
|
|
969
|
+
if (node.brightnessStepHSV_H < minDimLevelLightHSV_H) node.brightnessStepHSV_H = minDimLevelLightHSV_H
|
|
970
|
+
// node.updateKNXLightHSV_H_State(node.brightnessStepHSV_H); // Unnecessary, but necessary to set the KNX Status in real time.
|
|
972
971
|
// Produco l'RGB
|
|
973
|
-
xyBrightnessToHsv.h = node.brightnessStepHSV_H
|
|
974
|
-
const hsvToXYBri = hueColorConverter.ColorConverter.hsvToxyBrightness(xyBrightnessToHsv, node.currentHUEDevice.color.gamut)
|
|
975
|
-
const hueTelegram = { color: { xy: { x: hsvToXYBri.x, y: hsvToXYBri.y } }, dynamics: { duration: _dimSpeedInMillisecsHSV + 500 } }
|
|
972
|
+
xyBrightnessToHsv.h = node.brightnessStepHSV_H
|
|
973
|
+
const hsvToXYBri = hueColorConverter.ColorConverter.hsvToxyBrightness(xyBrightnessToHsv, node.currentHUEDevice.color.gamut)
|
|
974
|
+
const hueTelegram = { color: { xy: { x: hsvToXYBri.x, y: hsvToXYBri.y } }, dynamics: { duration: _dimSpeedInMillisecsHSV + 500 } }
|
|
976
975
|
// Switch off the light if on
|
|
977
976
|
if (node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === true && node.brightnessStepHSV_H === 0) {
|
|
978
|
-
hueTelegram.on = { on: false }
|
|
977
|
+
hueTelegram.on = { on: false }
|
|
979
978
|
}
|
|
980
|
-
node.currentHUEDevice.color.xy = hsvToXYBri
|
|
981
|
-
node.updateKNXLightColorState(node.currentHUEDevice.color)
|
|
982
|
-
node.writeHueState(hueTelegram)
|
|
979
|
+
node.currentHUEDevice.color.xy = hsvToXYBri// Unnecessary, but necessary to set the KNX Status in real time.
|
|
980
|
+
node.updateKNXLightColorState(node.currentHUEDevice.color)
|
|
981
|
+
node.writeHueState(hueTelegram)
|
|
983
982
|
if (node.brightnessStepHSV_H <= minDimLevelLightHSV_H) {
|
|
984
|
-
if (node.timerStepDimHSV_H !== undefined) clearInterval(node.timerStepDimHSV_H)
|
|
983
|
+
if (node.timerStepDimHSV_H !== undefined) clearInterval(node.timerStepDimHSV_H)
|
|
985
984
|
}
|
|
986
|
-
}, _dimSpeedInMillisecsHSV)
|
|
985
|
+
}, _dimSpeedInMillisecsHSV)
|
|
987
986
|
}
|
|
988
987
|
} catch (error) { /* empty */ }
|
|
989
|
-
}
|
|
988
|
+
}
|
|
990
989
|
/**
|
|
991
990
|
* Starts dimming / stop dimming of the Saturation
|
|
992
991
|
* @param {number} _KNXaction 1 for start, 0 for stop
|
|
@@ -994,341 +993,339 @@ module.exports = function (RED) {
|
|
|
994
993
|
* @param {number} _dimSpeedInMillisecsHSV Speed time in milliseconds
|
|
995
994
|
* @returns {}
|
|
996
995
|
*/
|
|
997
|
-
node.hueDimmingHSV_S = function hueDimmingHSV_S(_KNXaction, _KNXbrightness_DirectionHSV_S, _dimSpeedInMillisecsHSV = undefined) {
|
|
996
|
+
node.hueDimmingHSV_S = function hueDimmingHSV_S (_KNXaction, _KNXbrightness_DirectionHSV_S, _dimSpeedInMillisecsHSV = undefined) {
|
|
998
997
|
// After many attempts to use dimming_delta function of the HueApiV2, loosing days of my life, without a decent success, will use the standard dimming calculations
|
|
999
998
|
// i decide to go to the "step brightness" way.
|
|
1000
999
|
try {
|
|
1001
1000
|
if (_KNXbrightness_DirectionHSV_S === 0 && _KNXaction === 0) {
|
|
1002
1001
|
// STOP DIM
|
|
1003
|
-
if (node.timerStepDimHSV_S !== undefined) clearInterval(node.timerStepDimHSV_S)
|
|
1004
|
-
node.deleteHueStateQueue()
|
|
1005
|
-
return
|
|
1002
|
+
if (node.timerStepDimHSV_S !== undefined) clearInterval(node.timerStepDimHSV_S)
|
|
1003
|
+
node.deleteHueStateQueue() // Clear dimming queue.
|
|
1004
|
+
return
|
|
1006
1005
|
}
|
|
1007
1006
|
|
|
1008
|
-
let xyBrightnessToHsv
|
|
1007
|
+
let xyBrightnessToHsv
|
|
1009
1008
|
if (node.currentHUEDevice.color !== undefined && node.currentHUEDevice.color.xy !== undefined) {
|
|
1010
1009
|
// Get the XY + brightness from the lamp and transform it into HSV
|
|
1011
|
-
xyBrightnessToHsv = hueColorConverter.ColorConverter.xyBrightnessToHsv(hueColorConverter.ColorConverter.scale(node.currentHUEDevice.color.xy.x, [0, 1], [0, 100]), hueColorConverter.ColorConverter.scale(node.currentHUEDevice.color.xy.y, [0, 1], [0, 100]), node.currentHUEDevice.dimming.brightness)
|
|
1010
|
+
xyBrightnessToHsv = hueColorConverter.ColorConverter.xyBrightnessToHsv(hueColorConverter.ColorConverter.scale(node.currentHUEDevice.color.xy.x, [0, 1], [0, 100]), hueColorConverter.ColorConverter.scale(node.currentHUEDevice.color.xy.y, [0, 1], [0, 100]), node.currentHUEDevice.dimming.brightness)
|
|
1012
1011
|
} else {
|
|
1013
|
-
return
|
|
1012
|
+
return // Something wrong here.
|
|
1014
1013
|
}
|
|
1015
|
-
let numStepHSV_S = 10
|
|
1014
|
+
let numStepHSV_S = 10 // Steps from 0 to 100
|
|
1016
1015
|
|
|
1017
1016
|
// Set the actual brightness to start with
|
|
1018
|
-
if (node.brightnessStepHSV_S === null || node.brightnessStepHSV_S === undefined) node.brightnessStepHSV_S = node.currentHUEDevice.dimming.brightness
|
|
1019
|
-
node.brightnessStepHSV_S = Math.ceil(Number(node.brightnessStepHSV_S))
|
|
1017
|
+
if (node.brightnessStepHSV_S === null || node.brightnessStepHSV_S === undefined) node.brightnessStepHSV_S = node.currentHUEDevice.dimming.brightness
|
|
1018
|
+
node.brightnessStepHSV_S = Math.ceil(Number(node.brightnessStepHSV_S))
|
|
1020
1019
|
|
|
1021
|
-
const minDimLevelLightHSV_S = 1
|
|
1022
|
-
const maxDimLevelLightHSV_S = 100
|
|
1023
|
-
numStepHSV_S = Math.round((maxDimLevelLightHSV_S - minDimLevelLightHSV_S) / numStepHSV_S, 0)
|
|
1020
|
+
const minDimLevelLightHSV_S = 1
|
|
1021
|
+
const maxDimLevelLightHSV_S = 100
|
|
1022
|
+
numStepHSV_S = Math.round((maxDimLevelLightHSV_S - minDimLevelLightHSV_S) / numStepHSV_S, 0)
|
|
1024
1023
|
// Set the speed
|
|
1025
|
-
_dimSpeedInMillisecsHSV = Math.ceil(_dimSpeedInMillisecsHSV / (maxDimLevelLightHSV_S / numStepHSV_S))
|
|
1024
|
+
_dimSpeedInMillisecsHSV = Math.ceil(_dimSpeedInMillisecsHSV / (maxDimLevelLightHSV_S / numStepHSV_S))
|
|
1026
1025
|
|
|
1027
1026
|
if (_KNXbrightness_DirectionHSV_S > 0 && _KNXaction === 1) {
|
|
1028
1027
|
// DIM UP
|
|
1029
|
-
if (node.timerStepDimHSV_S !== undefined) clearInterval(node.timerStepDimHSV_S)
|
|
1028
|
+
if (node.timerStepDimHSV_S !== undefined) clearInterval(node.timerStepDimHSV_S)
|
|
1030
1029
|
node.timerStepDimHSV_S = setInterval(() => {
|
|
1031
|
-
node.deleteHueStateQueue()
|
|
1032
|
-
node.brightnessStepHSV_S += numStepHSV_S
|
|
1033
|
-
if (node.brightnessStepHSV_S > maxDimLevelLightHSV_S) node.brightnessStepHSV_S = maxDimLevelLightHSV_S
|
|
1034
|
-
//node.updateKNXLightHSV_S_State(node.brightnessStepHSV_S); // Unnecessary, but necessary to set the KNX Status in real time.
|
|
1035
|
-
xyBrightnessToHsv.s = node.brightnessStepHSV_S
|
|
1036
|
-
const hsvToXYBri = hueColorConverter.ColorConverter.hsvToxyBrightness(xyBrightnessToHsv, node.currentHUEDevice.color.gamut)
|
|
1037
|
-
const hueTelegram = { color: { xy: { x: hsvToXYBri.x, y: hsvToXYBri.y } }, dynamics: { duration: _dimSpeedInMillisecsHSV + 500 } }
|
|
1030
|
+
node.deleteHueStateQueue() // Clear dimming queue.
|
|
1031
|
+
node.brightnessStepHSV_S += numStepHSV_S
|
|
1032
|
+
if (node.brightnessStepHSV_S > maxDimLevelLightHSV_S) node.brightnessStepHSV_S = maxDimLevelLightHSV_S
|
|
1033
|
+
// node.updateKNXLightHSV_S_State(node.brightnessStepHSV_S); // Unnecessary, but necessary to set the KNX Status in real time.
|
|
1034
|
+
xyBrightnessToHsv.s = node.brightnessStepHSV_S
|
|
1035
|
+
const hsvToXYBri = hueColorConverter.ColorConverter.hsvToxyBrightness(xyBrightnessToHsv, node.currentHUEDevice.color.gamut)
|
|
1036
|
+
const hueTelegram = { color: { xy: { x: hsvToXYBri.x, y: hsvToXYBri.y } }, dynamics: { duration: _dimSpeedInMillisecsHSV + 500 } } // Add some ms, to prevent the "ladder" step effect.
|
|
1038
1037
|
// Switch on the light if off
|
|
1039
1038
|
if (node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === false) {
|
|
1040
|
-
hueTelegram.on = { on: true }
|
|
1039
|
+
hueTelegram.on = { on: true }
|
|
1041
1040
|
}
|
|
1042
|
-
node.currentHUEDevice.color.xy = cloneDeep(hsvToXYBri)
|
|
1043
|
-
node.updateKNXLightColorState(node.currentHUEDevice.color)
|
|
1044
|
-
node.writeHueState(hueTelegram)
|
|
1041
|
+
node.currentHUEDevice.color.xy = cloneDeep(hsvToXYBri)// Unnecessary, but necessary to set the KNX Status in real time.
|
|
1042
|
+
node.updateKNXLightColorState(node.currentHUEDevice.color)
|
|
1043
|
+
node.writeHueState(hueTelegram)
|
|
1045
1044
|
if (node.brightnessStepHSV_S >= maxDimLevelLightHSV_S) {
|
|
1046
|
-
if (node.timerStepDimHSV_S !== undefined) clearInterval(node.timerStepDimHSV_S)
|
|
1045
|
+
if (node.timerStepDimHSV_S !== undefined) clearInterval(node.timerStepDimHSV_S)
|
|
1047
1046
|
}
|
|
1048
|
-
}, _dimSpeedInMillisecsHSV)
|
|
1047
|
+
}, _dimSpeedInMillisecsHSV)
|
|
1049
1048
|
}
|
|
1050
1049
|
if (_KNXbrightness_DirectionHSV_S > 0 && _KNXaction === 0) {
|
|
1051
|
-
if (node.currentHUEDevice.on.on === false) return
|
|
1050
|
+
if (node.currentHUEDevice.on.on === false) return // Don't dim down, if the light is already off.
|
|
1052
1051
|
// DIM DOWN
|
|
1053
|
-
if (node.timerStepDimHSV_S !== undefined) clearInterval(node.timerStepDimHSV_S)
|
|
1052
|
+
if (node.timerStepDimHSV_S !== undefined) clearInterval(node.timerStepDimHSV_S)
|
|
1054
1053
|
node.timerStepDimHSV_S = setInterval(() => {
|
|
1055
|
-
node.deleteHueStateQueue()
|
|
1056
|
-
node.brightnessStepHSV_S -= numStepHSV_S
|
|
1057
|
-
if (node.brightnessStepHSV_S < minDimLevelLightHSV_S) node.brightnessStepHSV_S = minDimLevelLightHSV_S
|
|
1058
|
-
//node.updateKNXLightHSV_S_State(node.brightnessStepHSV_S); // Unnecessary, but necessary to set the KNX Status in real time.
|
|
1054
|
+
node.deleteHueStateQueue() // Clear dimming queue.
|
|
1055
|
+
node.brightnessStepHSV_S -= numStepHSV_S // *2 to speed up the things
|
|
1056
|
+
if (node.brightnessStepHSV_S < minDimLevelLightHSV_S) node.brightnessStepHSV_S = minDimLevelLightHSV_S
|
|
1057
|
+
// node.updateKNXLightHSV_S_State(node.brightnessStepHSV_S); // Unnecessary, but necessary to set the KNX Status in real time.
|
|
1059
1058
|
// Produco l'RGB
|
|
1060
|
-
xyBrightnessToHsv.s = node.brightnessStepHSV_S
|
|
1061
|
-
const hsvToXYBri = hueColorConverter.ColorConverter.hsvToxyBrightness(xyBrightnessToHsv, node.currentHUEDevice.color.gamut)
|
|
1062
|
-
const hueTelegram = { color: { xy: { x: hsvToXYBri.x, y: hsvToXYBri.y } }, dynamics: { duration: _dimSpeedInMillisecsHSV + 500 } }
|
|
1059
|
+
xyBrightnessToHsv.s = node.brightnessStepHSV_S
|
|
1060
|
+
const hsvToXYBri = hueColorConverter.ColorConverter.hsvToxyBrightness(xyBrightnessToHsv, node.currentHUEDevice.color.gamut)
|
|
1061
|
+
const hueTelegram = { color: { xy: { x: hsvToXYBri.x, y: hsvToXYBri.y } }, dynamics: { duration: _dimSpeedInMillisecsHSV + 500 } }
|
|
1063
1062
|
// Switch off the light if on
|
|
1064
1063
|
if (node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === true && node.brightnessStepHSV_S === 0) {
|
|
1065
|
-
hueTelegram.on = { on: false }
|
|
1064
|
+
hueTelegram.on = { on: false }
|
|
1066
1065
|
}
|
|
1067
|
-
node.currentHUEDevice.color.xy = cloneDeep(hsvToXYBri)
|
|
1068
|
-
node.updateKNXLightColorState(node.currentHUEDevice.color)
|
|
1069
|
-
node.writeHueState(hueTelegram)
|
|
1066
|
+
node.currentHUEDevice.color.xy = cloneDeep(hsvToXYBri)// Unnecessary, but necessary to set the KNX Status in real time.
|
|
1067
|
+
node.updateKNXLightColorState(node.currentHUEDevice.color)
|
|
1068
|
+
node.writeHueState(hueTelegram)
|
|
1070
1069
|
if (node.brightnessStepHSV_S <= minDimLevelLightHSV_S) {
|
|
1071
|
-
if (node.timerStepDimHSV_S !== undefined) clearInterval(node.timerStepDimHSV_S)
|
|
1070
|
+
if (node.timerStepDimHSV_S !== undefined) clearInterval(node.timerStepDimHSV_S)
|
|
1072
1071
|
}
|
|
1073
|
-
}, _dimSpeedInMillisecsHSV)
|
|
1072
|
+
}, _dimSpeedInMillisecsHSV)
|
|
1074
1073
|
}
|
|
1075
1074
|
} catch (error) { /* empty */ }
|
|
1076
|
-
}
|
|
1075
|
+
}
|
|
1077
1076
|
// ***********************************************************
|
|
1078
1077
|
|
|
1079
1078
|
node.handleSendHUE = async (_event) => {
|
|
1080
|
-
if (_event === undefined) return
|
|
1081
|
-
if (_event.type !== 'grouped_light' && _event.type !== 'light') return
|
|
1079
|
+
if (_event === undefined) return
|
|
1080
|
+
if (_event.type !== 'grouped_light' && _event.type !== 'light') return
|
|
1082
1081
|
|
|
1083
1082
|
// !!!! >>> if the node is a grouped_light, the only values required, thus present, by HUE apis are "on" and "dimming".
|
|
1084
1083
|
// !!!! >>> For all others properties like for example color and tunable white, i must get the data from one of the child lights.
|
|
1085
1084
|
|
|
1086
|
-
//(async () => {
|
|
1085
|
+
// (async () => {
|
|
1087
1086
|
try {
|
|
1088
1087
|
if (node.currentHUEDevice === undefined || node.serverHue === null || node.serverHue === undefined) {
|
|
1089
1088
|
node.setNodeStatusHue({
|
|
1090
|
-
fill:
|
|
1091
|
-
shape:
|
|
1089
|
+
fill: 'red',
|
|
1090
|
+
shape: 'ring',
|
|
1092
1091
|
text: "Rejected HUE light settings. I'm still not ready...",
|
|
1093
|
-
payload:
|
|
1094
|
-
})
|
|
1095
|
-
return
|
|
1092
|
+
payload: ''
|
|
1093
|
+
})
|
|
1094
|
+
return
|
|
1096
1095
|
}
|
|
1097
1096
|
|
|
1098
|
-
const receivedHUEObject = cloneDeep(_event)
|
|
1097
|
+
const receivedHUEObject = cloneDeep(_event)
|
|
1099
1098
|
|
|
1100
|
-
|
|
1099
|
+
// #region "CALCULATE COLOR AND COLOR TEMPERATURE OF THE LIGHTS BELONGING TO THE GROUPED_LIGHT"
|
|
1101
1100
|
// Check wether the incoming _event belongs to a light belonging to the group_light
|
|
1102
1101
|
if (node.isGrouped_light === true && receivedHUEObject.type === 'light') {
|
|
1103
1102
|
// Handling of not by HUE handled Color Temperature and ColorXY
|
|
1104
|
-
let modifiedLight
|
|
1105
|
-
const groupChilds = []
|
|
1106
|
-
let AverageColorsXYBrightnessAndTemperature
|
|
1103
|
+
let modifiedLight
|
|
1104
|
+
const groupChilds = []
|
|
1105
|
+
let AverageColorsXYBrightnessAndTemperature // Average color xy and color temp if the node is a grouped light.
|
|
1107
1106
|
// If the current node is a grouped lights, i must check wether the receivedHUEObject (containing a light) belongs to the node lights collection.
|
|
1108
1107
|
// Find all the lights in the collection, having the color_temperature capabilities, belonging to the group.
|
|
1109
|
-
const devices = await node.serverHue.getAllLightsBelongingToTheGroup(node.hueDevice, false)
|
|
1108
|
+
const devices = await node.serverHue.getAllLightsBelongingToTheGroup(node.hueDevice, false)
|
|
1110
1109
|
if (devices.length === 0) {
|
|
1111
|
-
devices.push(receivedHUEObject)
|
|
1110
|
+
devices.push(receivedHUEObject)
|
|
1112
1111
|
}
|
|
1113
1112
|
|
|
1114
1113
|
for (let index = 0; index < devices.length; index++) {
|
|
1115
|
-
const element = devices[index]
|
|
1114
|
+
const element = devices[index]
|
|
1116
1115
|
if (receivedHUEObject.id === element.id) {
|
|
1117
|
-
modifiedLight = element
|
|
1116
|
+
modifiedLight = element
|
|
1118
1117
|
// The dimming is not necessary, beacause the HUE API already sends a group_light event with the average brightness //if (receivedHUEObject.dimming !== undefined) modifiedLight.dimming = { brightness: receivedHUEObject.dimming.brightness };
|
|
1119
|
-
if (receivedHUEObject.color !== undefined && receivedHUEObject.color.xy !== undefined) modifiedLight.color = receivedHUEObject.color
|
|
1120
|
-
if (receivedHUEObject.color_temperature !== undefined) modifiedLight.color_temperature = receivedHUEObject.color_temperature
|
|
1121
|
-
groupChilds.push(modifiedLight)
|
|
1118
|
+
if (receivedHUEObject.color !== undefined && receivedHUEObject.color.xy !== undefined) modifiedLight.color = receivedHUEObject.color
|
|
1119
|
+
if (receivedHUEObject.color_temperature !== undefined) modifiedLight.color_temperature = receivedHUEObject.color_temperature
|
|
1120
|
+
groupChilds.push(modifiedLight)
|
|
1122
1121
|
} else {
|
|
1123
1122
|
// Simply append the light
|
|
1124
|
-
if ((element.color_temperature !== undefined && element.color_temperature.mirek !== undefined)
|
|
1125
|
-
|
|
1126
|
-
groupChilds.push(element)
|
|
1123
|
+
if ((element.color_temperature !== undefined && element.color_temperature.mirek !== undefined) ||
|
|
1124
|
+
(element.color !== undefined && element.color.xy !== undefined)) {
|
|
1125
|
+
groupChilds.push(element)
|
|
1127
1126
|
}
|
|
1128
1127
|
}
|
|
1129
1128
|
}
|
|
1130
1129
|
|
|
1131
1130
|
// Use the arithmetic average of color xy, brightness and color temperature "averageColorXYandKelvinOfGroupedLights"
|
|
1132
|
-
if (groupChilds !== undefined) AverageColorsXYBrightnessAndTemperature = await node.serverHue.getAverageColorsXYBrightnessAndTemperature(groupChilds)
|
|
1131
|
+
if (groupChilds !== undefined) AverageColorsXYBrightnessAndTemperature = await node.serverHue.getAverageColorsXYBrightnessAndTemperature(groupChilds)
|
|
1133
1132
|
|
|
1134
|
-
// Set the new values based on average calculated above
|
|
1133
|
+
// Set the new values based on average calculated above
|
|
1135
1134
|
// CHECK FIRST THE COLOR_TEMPERATURE, because it can be undefined, because the current selected color
|
|
1136
1135
|
// is out of the mirek range, so it cannot be represented with the colore temperature.
|
|
1137
1136
|
if (receivedHUEObject.color_temperature !== undefined && AverageColorsXYBrightnessAndTemperature.mirek !== undefined && receivedHUEObject.color_temperature.mirel_valid === true) {
|
|
1138
|
-
receivedHUEObject.color_temperature.mirek = AverageColorsXYBrightnessAndTemperature.mirek
|
|
1139
|
-
node.currentHUEDevice.color_temperature = { mirek: AverageColorsXYBrightnessAndTemperature.mirek }
|
|
1140
|
-
node.updateKNXLightKelvinPercentageState(receivedHUEObject.color_temperature.mirek)
|
|
1141
|
-
node.updateKNXLightKelvinState(receivedHUEObject.color_temperature.mirek)
|
|
1137
|
+
receivedHUEObject.color_temperature.mirek = AverageColorsXYBrightnessAndTemperature.mirek
|
|
1138
|
+
node.currentHUEDevice.color_temperature = { mirek: AverageColorsXYBrightnessAndTemperature.mirek }
|
|
1139
|
+
node.updateKNXLightKelvinPercentageState(receivedHUEObject.color_temperature.mirek)
|
|
1140
|
+
node.updateKNXLightKelvinState(receivedHUEObject.color_temperature.mirek)
|
|
1142
1141
|
} else if (receivedHUEObject.color !== undefined && receivedHUEObject.color.xy !== undefined && AverageColorsXYBrightnessAndTemperature.x !== undefined) {
|
|
1143
|
-
receivedHUEObject.color.xy.x = AverageColorsXYBrightnessAndTemperature.x
|
|
1144
|
-
receivedHUEObject.color.xy.y = AverageColorsXYBrightnessAndTemperature.y
|
|
1142
|
+
receivedHUEObject.color.xy.x = AverageColorsXYBrightnessAndTemperature.x
|
|
1143
|
+
receivedHUEObject.color.xy.y = AverageColorsXYBrightnessAndTemperature.y
|
|
1145
1144
|
node.currentHUEDevice.color = { xy: { x: AverageColorsXYBrightnessAndTemperature.x, y: AverageColorsXYBrightnessAndTemperature.y } }
|
|
1146
|
-
node.updateKNXLightColorState(receivedHUEObject.color)
|
|
1145
|
+
node.updateKNXLightColorState(receivedHUEObject.color)
|
|
1147
1146
|
}
|
|
1148
|
-
// The dimming is not necessary, beacause the HUE API already sends a group_light event with the average brightness
|
|
1147
|
+
// The dimming is not necessary, beacause the HUE API already sends a group_light event with the average brightness
|
|
1149
1148
|
// if (receivedHUEObject.dimming !== undefined && AverageColorsXYBrightnessAndTemperature.brightness !== undefined) {
|
|
1150
1149
|
// receivedHUEObject.dimming = { brightness: AverageColorsXYBrightnessAndTemperature.brightness };
|
|
1151
1150
|
// }
|
|
1152
1151
|
// --------------------------------------------------------------------------------------------------
|
|
1153
1152
|
if (modifiedLight !== undefined && modifiedLight.metadata !== undefined && modifiedLight.metadata.name !== undefined) {
|
|
1154
|
-
receivedHUEObject.lightName = modifiedLight.metadata.name
|
|
1153
|
+
receivedHUEObject.lightName = modifiedLight.metadata.name
|
|
1155
1154
|
}
|
|
1156
|
-
node.send(receivedHUEObject)
|
|
1157
|
-
return
|
|
1155
|
+
node.send(receivedHUEObject)
|
|
1156
|
+
return
|
|
1158
1157
|
}
|
|
1159
|
-
|
|
1158
|
+
// #endregion
|
|
1160
1159
|
|
|
1161
1160
|
if (receivedHUEObject.id === node.hueDevice) {
|
|
1162
1161
|
// Output the msg to the flow
|
|
1163
|
-
node.send(receivedHUEObject)
|
|
1162
|
+
node.send(receivedHUEObject)
|
|
1164
1163
|
|
|
1165
1164
|
// // DEBUG testing enable/disable HTML UI Tabs
|
|
1166
|
-
//delete _event.dimming;
|
|
1167
|
-
//delete _event.color;
|
|
1168
|
-
//delete _event.color_temperature;
|
|
1169
|
-
//delete _event.color_temperature_delta;
|
|
1165
|
+
// delete _event.dimming;
|
|
1166
|
+
// delete _event.color;
|
|
1167
|
+
// delete _event.color_temperature;
|
|
1168
|
+
// delete _event.color_temperature_delta;
|
|
1170
1169
|
|
|
1171
1170
|
if (receivedHUEObject.on !== undefined) {
|
|
1172
|
-
node.updateKNXLightState(receivedHUEObject.on.on)
|
|
1171
|
+
node.updateKNXLightState(receivedHUEObject.on.on)
|
|
1173
1172
|
// In case of switch off, set the dim to zero
|
|
1174
|
-
if (receivedHUEObject.on.on === false && (config.updateKNXBrightnessStatusOnHUEOnOff === undefined || config.updateKNXBrightnessStatusOnHUEOnOff ===
|
|
1175
|
-
node.updateKNXBrightnessState(0)
|
|
1176
|
-
if (receivedHUEObject.dimming !== undefined) delete receivedHUEObject.dimming
|
|
1173
|
+
if (receivedHUEObject.on.on === false && (config.updateKNXBrightnessStatusOnHUEOnOff === undefined || config.updateKNXBrightnessStatusOnHUEOnOff === 'onhueoff')) {
|
|
1174
|
+
node.updateKNXBrightnessState(0)
|
|
1175
|
+
if (receivedHUEObject.dimming !== undefined) delete receivedHUEObject.dimming // Remove event.dimming, because has beem handled by this function and i don't want the function below to take care of it.
|
|
1177
1176
|
} else if (receivedHUEObject.on.on === true && node.currentHUEDevice.on.on === false) {
|
|
1178
1177
|
// Turn on: update the dimming KNX Status value as well, but only if we have a reliable value.
|
|
1179
1178
|
// For grouped_light, the bridge exposes an aggregated brightness value via /resource/grouped_light/{id}.
|
|
1180
|
-
let brightVal
|
|
1179
|
+
let brightVal
|
|
1181
1180
|
if (receivedHUEObject.dimming !== undefined && receivedHUEObject.dimming.brightness !== undefined) {
|
|
1182
|
-
brightVal = receivedHUEObject.dimming.brightness
|
|
1183
|
-
} else if (node.isGrouped_light === true && typeof node.serverHue?.getHueResourceSnapshot ===
|
|
1181
|
+
brightVal = receivedHUEObject.dimming.brightness
|
|
1182
|
+
} else if (node.isGrouped_light === true && typeof node.serverHue?.getHueResourceSnapshot === 'function' && config.GALightBrightnessState) {
|
|
1184
1183
|
try {
|
|
1185
|
-
const snapshot = await node.serverHue.getHueResourceSnapshot(node.hueDevice, { forceRefresh: true })
|
|
1186
|
-
if (snapshot?.dimming?.brightness !== undefined) brightVal = snapshot.dimming.brightness
|
|
1184
|
+
const snapshot = await node.serverHue.getHueResourceSnapshot(node.hueDevice, { forceRefresh: true })
|
|
1185
|
+
if (snapshot?.dimming?.brightness !== undefined) brightVal = snapshot.dimming.brightness
|
|
1187
1186
|
} catch (error) { /* empty */ }
|
|
1188
1187
|
} else if (node.currentHUEDevice.dimming !== undefined && node.currentHUEDevice.dimming.brightness !== undefined) {
|
|
1189
|
-
brightVal = node.currentHUEDevice.dimming.brightness
|
|
1188
|
+
brightVal = node.currentHUEDevice.dimming.brightness
|
|
1190
1189
|
}
|
|
1191
|
-
if (brightVal !== undefined) node.updateKNXBrightnessState(brightVal)
|
|
1190
|
+
if (brightVal !== undefined) node.updateKNXBrightnessState(brightVal)
|
|
1192
1191
|
}
|
|
1193
|
-
node.currentHUEDevice.on.on = receivedHUEObject.on.on
|
|
1192
|
+
node.currentHUEDevice.on.on = receivedHUEObject.on.on
|
|
1194
1193
|
}
|
|
1195
1194
|
|
|
1196
1195
|
if (receivedHUEObject.color !== undefined && receivedHUEObject.color.xy !== undefined) { // fixed https://github.com/Supergiovane/node-red-contrib-knx-ultimate/issues/287
|
|
1197
|
-
node.updateKNXLightColorState(receivedHUEObject.color)
|
|
1198
|
-
node.currentHUEDevice.color = receivedHUEObject.color
|
|
1196
|
+
node.updateKNXLightColorState(receivedHUEObject.color)
|
|
1197
|
+
node.currentHUEDevice.color = receivedHUEObject.color
|
|
1199
1198
|
}
|
|
1200
1199
|
|
|
1201
1200
|
if (receivedHUEObject.dimming !== undefined && receivedHUEObject.dimming.brightness !== undefined) {
|
|
1202
|
-
const zeroBrightnessWhenOff = (config.updateKNXBrightnessStatusOnHUEOnOff === undefined || config.updateKNXBrightnessStatusOnHUEOnOff ===
|
|
1201
|
+
const zeroBrightnessWhenOff = (config.updateKNXBrightnessStatusOnHUEOnOff === undefined || config.updateKNXBrightnessStatusOnHUEOnOff === 'onhueoff')
|
|
1203
1202
|
// Once upon n a time, the light transmit the brightness value of 0.39.
|
|
1204
1203
|
// To avoid wrongly turn light state on, exit
|
|
1205
|
-
if (receivedHUEObject.dimming.brightness < 1) receivedHUEObject.dimming.brightness = 0
|
|
1204
|
+
if (receivedHUEObject.dimming.brightness < 1) receivedHUEObject.dimming.brightness = 0
|
|
1206
1205
|
// If the light is OFF and the user wants KNX brightness status to stay 0 while OFF,
|
|
1207
1206
|
// don't propagate Hue's cached brightness (usually the last/boot brightness) back to KNX.
|
|
1208
1207
|
if (zeroBrightnessWhenOff === true && node.currentHUEDevice?.on?.on === false && (receivedHUEObject.on === undefined || receivedHUEObject.on.on === false)) {
|
|
1209
|
-
if (node.currentHUEDevice.dimming !== undefined) node.currentHUEDevice.dimming.brightness = receivedHUEObject.dimming.brightness
|
|
1208
|
+
if (node.currentHUEDevice.dimming !== undefined) node.currentHUEDevice.dimming.brightness = receivedHUEObject.dimming.brightness
|
|
1210
1209
|
} else if (node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === false && receivedHUEObject.dimming.brightness === 0) {
|
|
1211
1210
|
// Do nothing, because the light is off and the dimming also is 0
|
|
1212
1211
|
} else {
|
|
1213
|
-
if (node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === false && (receivedHUEObject.on === undefined || (receivedHUEObject.on !== undefined && receivedHUEObject.on.on === true))) node.updateKNXLightState(receivedHUEObject.dimming.brightness > 0)
|
|
1214
|
-
node.updateKNXBrightnessState(receivedHUEObject.dimming.brightness)
|
|
1212
|
+
if (node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === false && (receivedHUEObject.on === undefined || (receivedHUEObject.on !== undefined && receivedHUEObject.on.on === true))) node.updateKNXLightState(receivedHUEObject.dimming.brightness > 0)
|
|
1213
|
+
node.updateKNXBrightnessState(receivedHUEObject.dimming.brightness)
|
|
1215
1214
|
// If the brightness reaches zero, the hue lamp "on" property must be set to zero as well
|
|
1216
1215
|
if (receivedHUEObject.dimming.brightness === 0 && node.currentHUEDevice.on !== undefined && node.currentHUEDevice.on.on === true) {
|
|
1217
|
-
node.writeHueState({ on: { on: false } })
|
|
1218
|
-
node.currentHUEDevice.on.on = false
|
|
1216
|
+
node.writeHueState({ on: { on: false } })
|
|
1217
|
+
node.currentHUEDevice.on.on = false
|
|
1219
1218
|
}
|
|
1220
|
-
node.currentHUEDevice.dimming.brightness = receivedHUEObject.dimming.brightness
|
|
1219
|
+
node.currentHUEDevice.dimming.brightness = receivedHUEObject.dimming.brightness
|
|
1221
1220
|
}
|
|
1222
1221
|
}
|
|
1223
1222
|
|
|
1224
1223
|
if (receivedHUEObject.color_temperature !== undefined && receivedHUEObject.color_temperature.mirek !== undefined) {
|
|
1225
|
-
node.updateKNXLightKelvinPercentageState(receivedHUEObject.color_temperature.mirek)
|
|
1226
|
-
node.updateKNXLightKelvinState(receivedHUEObject.color_temperature.mirek)
|
|
1227
|
-
node.currentHUEDevice.color_temperature.mirek = receivedHUEObject.color_temperature.mirek
|
|
1224
|
+
node.updateKNXLightKelvinPercentageState(receivedHUEObject.color_temperature.mirek)
|
|
1225
|
+
node.updateKNXLightKelvinState(receivedHUEObject.color_temperature.mirek)
|
|
1226
|
+
node.currentHUEDevice.color_temperature.mirek = receivedHUEObject.color_temperature.mirek
|
|
1228
1227
|
}
|
|
1229
1228
|
}
|
|
1230
1229
|
} catch (error) {
|
|
1231
1230
|
node.status({
|
|
1232
|
-
fill:
|
|
1233
|
-
shape:
|
|
1234
|
-
text: `HUE->KNX error ${node.id} ${error.message}. Seee Log
|
|
1235
|
-
})
|
|
1236
|
-
RED.log.error(`knxUltimateHueLight: node.handleSendHUE = (_event): ${error.stack}`)
|
|
1231
|
+
fill: 'red',
|
|
1232
|
+
shape: 'dot',
|
|
1233
|
+
text: `HUE->KNX error ${node.id} ${error.message}. Seee Log`
|
|
1234
|
+
})
|
|
1235
|
+
RED.log.error(`knxUltimateHueLight: node.handleSendHUE = (_event): ${error.stack}`)
|
|
1237
1236
|
}
|
|
1238
1237
|
// })();
|
|
1239
|
-
}
|
|
1240
|
-
|
|
1238
|
+
}
|
|
1241
1239
|
|
|
1242
1240
|
// Leave the name after "function", to avoid <anonymous function> in the stack trace, in caso of errors.
|
|
1243
|
-
node.updateKNXBrightnessState = function updateKNXBrightnessState(_value, _outputtype =
|
|
1244
|
-
if (config.GALightBrightnessState !== undefined && config.GALightBrightnessState !==
|
|
1245
|
-
const knxMsgPayload = {}
|
|
1246
|
-
knxMsgPayload.topic = config.GALightBrightnessState
|
|
1247
|
-
knxMsgPayload.dpt = config.dptLightBrightnessState
|
|
1248
|
-
knxMsgPayload.payload = _value
|
|
1241
|
+
node.updateKNXBrightnessState = function updateKNXBrightnessState (_value, _outputtype = 'write') {
|
|
1242
|
+
if (config.GALightBrightnessState !== undefined && config.GALightBrightnessState !== '') {
|
|
1243
|
+
const knxMsgPayload = {}
|
|
1244
|
+
knxMsgPayload.topic = config.GALightBrightnessState
|
|
1245
|
+
knxMsgPayload.dpt = config.dptLightBrightnessState
|
|
1246
|
+
knxMsgPayload.payload = _value
|
|
1249
1247
|
// Send to KNX bus
|
|
1250
|
-
if (knxMsgPayload.topic !==
|
|
1248
|
+
if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined) {
|
|
1251
1249
|
if (node.serverKNX !== null && node.serverKNX !== undefined) {
|
|
1252
1250
|
node.serverKNX.sendKNXTelegramToKNXEngine({
|
|
1253
1251
|
grpaddr: knxMsgPayload.topic,
|
|
1254
1252
|
payload: knxMsgPayload.payload,
|
|
1255
1253
|
dpt: knxMsgPayload.dpt,
|
|
1256
1254
|
outputtype: _outputtype,
|
|
1257
|
-
nodecallerid: node.id
|
|
1258
|
-
})
|
|
1255
|
+
nodecallerid: node.id
|
|
1256
|
+
})
|
|
1259
1257
|
}
|
|
1260
1258
|
}
|
|
1261
1259
|
node.setNodeStatusHue({
|
|
1262
|
-
fill:
|
|
1263
|
-
shape:
|
|
1264
|
-
text:
|
|
1265
|
-
payload: knxMsgPayload.payload
|
|
1266
|
-
})
|
|
1260
|
+
fill: 'blue',
|
|
1261
|
+
shape: 'ring',
|
|
1262
|
+
text: 'HUE->KNX Bright',
|
|
1263
|
+
payload: knxMsgPayload.payload
|
|
1264
|
+
})
|
|
1267
1265
|
}
|
|
1268
|
-
}
|
|
1266
|
+
}
|
|
1269
1267
|
|
|
1270
|
-
node.updateKNXLightState = function updateKNXLightState(_value, _outputtype =
|
|
1268
|
+
node.updateKNXLightState = function updateKNXLightState (_value, _outputtype = 'write') {
|
|
1271
1269
|
try {
|
|
1272
|
-
const knxMsgPayload = {}
|
|
1273
|
-
knxMsgPayload.topic = config.GALightState
|
|
1274
|
-
knxMsgPayload.dpt = config.dptLightState
|
|
1275
|
-
knxMsgPayload.payload = _value
|
|
1276
|
-
if (config.GALightState !== undefined && config.GALightState !==
|
|
1277
|
-
|
|
1270
|
+
const knxMsgPayload = {}
|
|
1271
|
+
knxMsgPayload.topic = config.GALightState
|
|
1272
|
+
knxMsgPayload.dpt = config.dptLightState
|
|
1273
|
+
knxMsgPayload.payload = _value
|
|
1274
|
+
if (config.GALightState !== undefined && config.GALightState !== '') {
|
|
1278
1275
|
// Check not to have already sent the value
|
|
1279
1276
|
// Send to KNX bus
|
|
1280
|
-
if (knxMsgPayload.topic !==
|
|
1277
|
+
if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined) {
|
|
1281
1278
|
if (node.serverKNX !== null && node.serverKNX !== undefined) {
|
|
1282
1279
|
node.serverKNX.sendKNXTelegramToKNXEngine({
|
|
1283
1280
|
grpaddr: knxMsgPayload.topic,
|
|
1284
1281
|
payload: knxMsgPayload.payload,
|
|
1285
1282
|
dpt: knxMsgPayload.dpt,
|
|
1286
1283
|
outputtype: _outputtype,
|
|
1287
|
-
nodecallerid: node.id
|
|
1288
|
-
})
|
|
1284
|
+
nodecallerid: node.id
|
|
1285
|
+
})
|
|
1289
1286
|
}
|
|
1290
1287
|
}
|
|
1291
1288
|
node.setNodeStatusHue({
|
|
1292
|
-
fill:
|
|
1293
|
-
shape:
|
|
1294
|
-
text:
|
|
1295
|
-
payload: knxMsgPayload.payload
|
|
1296
|
-
})
|
|
1289
|
+
fill: 'blue',
|
|
1290
|
+
shape: 'ring',
|
|
1291
|
+
text: 'HUE->KNX On/Off',
|
|
1292
|
+
payload: knxMsgPayload.payload
|
|
1293
|
+
})
|
|
1297
1294
|
}
|
|
1298
1295
|
} catch (error) {
|
|
1299
1296
|
/* empty */
|
|
1300
1297
|
}
|
|
1301
|
-
}
|
|
1302
|
-
|
|
1303
|
-
node.updateKNXLightKelvinPercentageState = function updateKNXLightKelvinPercentageState(_value, _outputtype =
|
|
1304
|
-
if (config.GALightKelvinPercentageState !== undefined && config.GALightKelvinPercentageState !==
|
|
1305
|
-
const knxMsgPayload = {}
|
|
1306
|
-
knxMsgPayload.topic = config.GALightKelvinPercentageState
|
|
1307
|
-
knxMsgPayload.dpt = config.dptLightKelvinPercentageState
|
|
1308
|
-
if (config.dptLightKelvinPercentageState ===
|
|
1309
|
-
const retPercent = hueColorConverter.ColorConverter.scale(_value, [153, 500], [0, 100])
|
|
1310
|
-
knxMsgPayload.payload = 100 - retPercent
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
node.updateKNXLightKelvinPercentageState = function updateKNXLightKelvinPercentageState (_value, _outputtype = 'write') {
|
|
1301
|
+
if (config.GALightKelvinPercentageState !== undefined && config.GALightKelvinPercentageState !== '') {
|
|
1302
|
+
const knxMsgPayload = {}
|
|
1303
|
+
knxMsgPayload.topic = config.GALightKelvinPercentageState
|
|
1304
|
+
knxMsgPayload.dpt = config.dptLightKelvinPercentageState
|
|
1305
|
+
if (config.dptLightKelvinPercentageState === '5.001') {
|
|
1306
|
+
const retPercent = hueColorConverter.ColorConverter.scale(_value, [153, 500], [0, 100])
|
|
1307
|
+
knxMsgPayload.payload = 100 - retPercent
|
|
1311
1308
|
}
|
|
1312
1309
|
// Send to KNX bus
|
|
1313
|
-
if (knxMsgPayload.topic !==
|
|
1310
|
+
if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined) {
|
|
1314
1311
|
if (node.serverKNX !== null && node.serverKNX !== undefined) {
|
|
1315
1312
|
node.serverKNX.sendKNXTelegramToKNXEngine({
|
|
1316
1313
|
grpaddr: knxMsgPayload.topic,
|
|
1317
1314
|
payload: knxMsgPayload.payload,
|
|
1318
1315
|
dpt: knxMsgPayload.dpt,
|
|
1319
1316
|
outputtype: _outputtype,
|
|
1320
|
-
nodecallerid: node.id
|
|
1321
|
-
})
|
|
1317
|
+
nodecallerid: node.id
|
|
1318
|
+
})
|
|
1322
1319
|
}
|
|
1323
1320
|
}
|
|
1324
1321
|
node.setNodeStatusHue({
|
|
1325
|
-
fill:
|
|
1326
|
-
shape:
|
|
1327
|
-
text:
|
|
1328
|
-
payload: knxMsgPayload.payload
|
|
1329
|
-
})
|
|
1322
|
+
fill: 'blue',
|
|
1323
|
+
shape: 'ring',
|
|
1324
|
+
text: 'HUE->KNX Tunable White',
|
|
1325
|
+
payload: knxMsgPayload.payload
|
|
1326
|
+
})
|
|
1330
1327
|
}
|
|
1331
|
-
}
|
|
1328
|
+
}
|
|
1332
1329
|
|
|
1333
1330
|
// /**
|
|
1334
1331
|
// * Update the internal HSV variable status and send the valuge in % to the KNX BUS
|
|
@@ -1406,178 +1403,178 @@ module.exports = function (RED) {
|
|
|
1406
1403
|
* @param {string} _outputtype "write" is the default KNX command
|
|
1407
1404
|
* @returns {}
|
|
1408
1405
|
*/
|
|
1409
|
-
node.updateKNXLightColorState = function updateKNXLightColorState(_value, _outputtype =
|
|
1410
|
-
if (config.GALightColorState !== undefined && config.GALightColorState !==
|
|
1411
|
-
if (_value.xy === undefined || _value.xy.x === undefined) return
|
|
1412
|
-
const knxMsgPayload = {}
|
|
1413
|
-
knxMsgPayload.topic = config.GALightColorState
|
|
1414
|
-
knxMsgPayload.dpt = config.dptLightColorState
|
|
1406
|
+
node.updateKNXLightColorState = function updateKNXLightColorState (_value, _outputtype = 'write') {
|
|
1407
|
+
if (config.GALightColorState !== undefined && config.GALightColorState !== '') {
|
|
1408
|
+
if (_value.xy === undefined || _value.xy.x === undefined) return
|
|
1409
|
+
const knxMsgPayload = {}
|
|
1410
|
+
knxMsgPayload.topic = config.GALightColorState
|
|
1411
|
+
knxMsgPayload.dpt = config.dptLightColorState
|
|
1415
1412
|
try {
|
|
1416
1413
|
knxMsgPayload.payload = hueColorConverter.ColorConverter.xyBriToRgb(
|
|
1417
1414
|
_value.xy.x,
|
|
1418
1415
|
_value.xy.y,
|
|
1419
|
-
node.currentHUEDevice !== undefined && node.currentHUEDevice.dimming !== undefined && node.currentHUEDevice.dimming.brightness === undefined ? node.currentHUEDevice.dimming.brightness : 100
|
|
1420
|
-
)
|
|
1421
|
-
knxMsgPayload.payload = { red: knxMsgPayload.payload.r, green: knxMsgPayload.payload.g, blue: knxMsgPayload.payload.b }
|
|
1416
|
+
node.currentHUEDevice !== undefined && node.currentHUEDevice.dimming !== undefined && node.currentHUEDevice.dimming.brightness === undefined ? node.currentHUEDevice.dimming.brightness : 100
|
|
1417
|
+
)
|
|
1418
|
+
knxMsgPayload.payload = { red: knxMsgPayload.payload.r, green: knxMsgPayload.payload.g, blue: knxMsgPayload.payload.b }
|
|
1422
1419
|
// Send to KNX bus
|
|
1423
|
-
if (knxMsgPayload.topic !==
|
|
1420
|
+
if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined) {
|
|
1424
1421
|
if (node.serverKNX !== null && node.serverKNX !== undefined) {
|
|
1425
1422
|
node.serverKNX.sendKNXTelegramToKNXEngine({
|
|
1426
1423
|
grpaddr: knxMsgPayload.topic,
|
|
1427
1424
|
payload: knxMsgPayload.payload,
|
|
1428
1425
|
dpt: knxMsgPayload.dpt,
|
|
1429
1426
|
outputtype: _outputtype,
|
|
1430
|
-
nodecallerid: node.id
|
|
1431
|
-
})
|
|
1427
|
+
nodecallerid: node.id
|
|
1428
|
+
})
|
|
1432
1429
|
}
|
|
1433
1430
|
}
|
|
1434
1431
|
node.setNodeStatusHue({
|
|
1435
|
-
fill:
|
|
1436
|
-
shape:
|
|
1437
|
-
text:
|
|
1438
|
-
payload: knxMsgPayload.payload
|
|
1439
|
-
})
|
|
1432
|
+
fill: 'blue',
|
|
1433
|
+
shape: 'ring',
|
|
1434
|
+
text: 'HUE->KNX Color',
|
|
1435
|
+
payload: knxMsgPayload.payload
|
|
1436
|
+
})
|
|
1440
1437
|
} catch (error) { }
|
|
1441
1438
|
}
|
|
1442
|
-
if (config.GALightHSV_S_State !== undefined && config.GALightHSV_S_State !==
|
|
1443
|
-
const knxMsgPayload = {}
|
|
1444
|
-
knxMsgPayload.topic = config.GALightHSV_S_State
|
|
1445
|
-
knxMsgPayload.dpt = config.dptLightHSV_S_State
|
|
1446
|
-
if (config.dptLightHSV_S_State ===
|
|
1447
|
-
knxMsgPayload.payload = hueColorConverter.ColorConverter.xyBrightnessToHsv(_value.xy.x, _value.xy.y, node.currentHUEDevice !== undefined && node.currentHUEDevice.dimming !== undefined && node.currentHUEDevice.dimming.brightness === undefined ? node.currentHUEDevice.dimming.brightness : 100, false)
|
|
1448
|
-
knxMsgPayload.payload = knxMsgPayload.payload.s
|
|
1439
|
+
if (config.GALightHSV_S_State !== undefined && config.GALightHSV_S_State !== '') {
|
|
1440
|
+
const knxMsgPayload = {}
|
|
1441
|
+
knxMsgPayload.topic = config.GALightHSV_S_State
|
|
1442
|
+
knxMsgPayload.dpt = config.dptLightHSV_S_State
|
|
1443
|
+
if (config.dptLightHSV_S_State === '5.001') {
|
|
1444
|
+
knxMsgPayload.payload = hueColorConverter.ColorConverter.xyBrightnessToHsv(_value.xy.x, _value.xy.y, node.currentHUEDevice !== undefined && node.currentHUEDevice.dimming !== undefined && node.currentHUEDevice.dimming.brightness === undefined ? node.currentHUEDevice.dimming.brightness : 100, false)
|
|
1445
|
+
knxMsgPayload.payload = knxMsgPayload.payload.s
|
|
1449
1446
|
}
|
|
1450
1447
|
// Send to KNX bus
|
|
1451
|
-
if (knxMsgPayload.topic !==
|
|
1448
|
+
if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined) {
|
|
1452
1449
|
if (node.serverKNX !== null && node.serverKNX !== undefined) {
|
|
1453
1450
|
node.serverKNX.sendKNXTelegramToKNXEngine({
|
|
1454
1451
|
grpaddr: knxMsgPayload.topic,
|
|
1455
1452
|
payload: knxMsgPayload.payload,
|
|
1456
1453
|
dpt: knxMsgPayload.dpt,
|
|
1457
|
-
outputtype: _outputtype ||
|
|
1458
|
-
nodecallerid: node.id
|
|
1459
|
-
})
|
|
1454
|
+
outputtype: _outputtype || 'write',
|
|
1455
|
+
nodecallerid: node.id
|
|
1456
|
+
})
|
|
1460
1457
|
}
|
|
1461
1458
|
}
|
|
1462
1459
|
node.setNodeStatusHue({
|
|
1463
|
-
fill:
|
|
1464
|
-
shape:
|
|
1465
|
-
text:
|
|
1466
|
-
payload: knxMsgPayload.payload
|
|
1467
|
-
})
|
|
1460
|
+
fill: 'blue',
|
|
1461
|
+
shape: 'ring',
|
|
1462
|
+
text: 'HUE->KNX HSV (S)',
|
|
1463
|
+
payload: knxMsgPayload.payload
|
|
1464
|
+
})
|
|
1468
1465
|
}
|
|
1469
|
-
if (config.GALightHSV_H_State !== undefined && config.GALightHSV_H_State !==
|
|
1470
|
-
const knxMsgPayload = {}
|
|
1471
|
-
knxMsgPayload.topic = config.GALightHSV_H_State
|
|
1472
|
-
knxMsgPayload.dpt = config.dptLightHSV_H_State
|
|
1473
|
-
if (config.dptLightHSV_H_State ===
|
|
1474
|
-
knxMsgPayload.payload = hueColorConverter.ColorConverter.xyBrightnessToHsv(_value.xy.x, _value.xy.y, node.currentHUEDevice !== undefined && node.currentHUEDevice.dimming !== undefined && node.currentHUEDevice.dimming.brightness === undefined ? node.currentHUEDevice.dimming.brightness : 100, false)
|
|
1475
|
-
knxMsgPayload.payload = 100 - knxMsgPayload.payload.h
|
|
1466
|
+
if (config.GALightHSV_H_State !== undefined && config.GALightHSV_H_State !== '') {
|
|
1467
|
+
const knxMsgPayload = {}
|
|
1468
|
+
knxMsgPayload.topic = config.GALightHSV_H_State
|
|
1469
|
+
knxMsgPayload.dpt = config.dptLightHSV_H_State
|
|
1470
|
+
if (config.dptLightHSV_H_State === '5.001') {
|
|
1471
|
+
knxMsgPayload.payload = hueColorConverter.ColorConverter.xyBrightnessToHsv(_value.xy.x, _value.xy.y, node.currentHUEDevice !== undefined && node.currentHUEDevice.dimming !== undefined && node.currentHUEDevice.dimming.brightness === undefined ? node.currentHUEDevice.dimming.brightness : 100, false)
|
|
1472
|
+
knxMsgPayload.payload = 100 - knxMsgPayload.payload.h
|
|
1476
1473
|
}
|
|
1477
1474
|
// Send to KNX bus
|
|
1478
|
-
if (knxMsgPayload.topic !==
|
|
1475
|
+
if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined) {
|
|
1479
1476
|
if (node.serverKNX !== null && node.serverKNX !== undefined) {
|
|
1480
1477
|
node.serverKNX.sendKNXTelegramToKNXEngine({
|
|
1481
1478
|
grpaddr: knxMsgPayload.topic,
|
|
1482
1479
|
payload: knxMsgPayload.payload,
|
|
1483
1480
|
dpt: knxMsgPayload.dpt,
|
|
1484
|
-
outputtype: _outputtype ||
|
|
1485
|
-
nodecallerid: node.id
|
|
1486
|
-
})
|
|
1481
|
+
outputtype: _outputtype || 'write',
|
|
1482
|
+
nodecallerid: node.id
|
|
1483
|
+
})
|
|
1487
1484
|
}
|
|
1488
1485
|
}
|
|
1489
1486
|
node.setNodeStatusHue({
|
|
1490
|
-
fill:
|
|
1491
|
-
shape:
|
|
1492
|
-
text:
|
|
1493
|
-
payload: knxMsgPayload.payload
|
|
1494
|
-
})
|
|
1487
|
+
fill: 'blue',
|
|
1488
|
+
shape: 'ring',
|
|
1489
|
+
text: 'HUE->KNX HSV (H)',
|
|
1490
|
+
payload: knxMsgPayload.payload
|
|
1491
|
+
})
|
|
1495
1492
|
}
|
|
1496
|
-
}
|
|
1497
|
-
|
|
1498
|
-
node.updateKNXLightKelvinState = function updateKNXLightKelvinState(_value, _outputtype =
|
|
1499
|
-
if (config.GALightKelvinState !== undefined && config.GALightKelvinState !==
|
|
1500
|
-
const knxMsgPayload = {}
|
|
1501
|
-
|
|
1502
|
-
knxMsgPayload.topic = config.GALightKelvinState
|
|
1503
|
-
knxMsgPayload.dpt = config.dptLightKelvinState
|
|
1504
|
-
if (config.dptLightKelvinState ===
|
|
1505
|
-
knxMsgPayload.payload = hueColorConverter.ColorConverter.mirekToKelvin(_value)
|
|
1506
|
-
//knxMsgPayload.payload = hueColorConverter.ColorConverter.scale(kelvinValue, [2000, 6535], [0, 65535]);
|
|
1507
|
-
} else if (config.dptLightKelvinState ===
|
|
1508
|
-
knxMsgPayload.payload = hueColorConverter.ColorConverter.mirekToKelvin(_value)
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
node.updateKNXLightKelvinState = function updateKNXLightKelvinState (_value, _outputtype = 'write') {
|
|
1496
|
+
if (config.GALightKelvinState !== undefined && config.GALightKelvinState !== '') {
|
|
1497
|
+
const knxMsgPayload = {}
|
|
1498
|
+
const kelvinValue = 0
|
|
1499
|
+
knxMsgPayload.topic = config.GALightKelvinState
|
|
1500
|
+
knxMsgPayload.dpt = config.dptLightKelvinState
|
|
1501
|
+
if (config.dptLightKelvinState === '7.600') {
|
|
1502
|
+
knxMsgPayload.payload = hueColorConverter.ColorConverter.mirekToKelvin(_value)
|
|
1503
|
+
// knxMsgPayload.payload = hueColorConverter.ColorConverter.scale(kelvinValue, [2000, 6535], [0, 65535]);
|
|
1504
|
+
} else if (config.dptLightKelvinState === '9.002') {
|
|
1505
|
+
knxMsgPayload.payload = hueColorConverter.ColorConverter.mirekToKelvin(_value)
|
|
1509
1506
|
}
|
|
1510
1507
|
// Send to KNX bus
|
|
1511
|
-
if (knxMsgPayload.topic !==
|
|
1508
|
+
if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined) {
|
|
1512
1509
|
if (node.serverKNX !== null && node.serverKNX !== undefined) {
|
|
1513
1510
|
node.serverKNX.sendKNXTelegramToKNXEngine({
|
|
1514
1511
|
grpaddr: knxMsgPayload.topic,
|
|
1515
1512
|
payload: knxMsgPayload.payload,
|
|
1516
1513
|
dpt: knxMsgPayload.dpt,
|
|
1517
1514
|
outputtype: _outputtype,
|
|
1518
|
-
nodecallerid: node.id
|
|
1519
|
-
})
|
|
1515
|
+
nodecallerid: node.id
|
|
1516
|
+
})
|
|
1520
1517
|
}
|
|
1521
1518
|
|
|
1522
1519
|
node.setNodeStatusHue({
|
|
1523
|
-
fill:
|
|
1524
|
-
shape:
|
|
1525
|
-
text:
|
|
1526
|
-
payload: knxMsgPayload.payload
|
|
1527
|
-
})
|
|
1520
|
+
fill: 'blue',
|
|
1521
|
+
shape: 'ring',
|
|
1522
|
+
text: 'HUE->KNX Kelvin',
|
|
1523
|
+
payload: knxMsgPayload.payload
|
|
1524
|
+
})
|
|
1528
1525
|
}
|
|
1529
1526
|
}
|
|
1530
|
-
}
|
|
1527
|
+
}
|
|
1531
1528
|
|
|
1532
1529
|
// On each deploy, unsubscribe+resubscribe
|
|
1533
1530
|
if (node.serverKNX) {
|
|
1534
|
-
node.serverKNX.removeClient(node)
|
|
1535
|
-
node.serverKNX.addClient(node)
|
|
1531
|
+
node.serverKNX.removeClient(node)
|
|
1532
|
+
node.serverKNX.addClient(node)
|
|
1536
1533
|
}
|
|
1537
1534
|
if (node.serverHue) {
|
|
1538
1535
|
try {
|
|
1539
|
-
node.serverHue.removeClient(node)
|
|
1540
|
-
node.serverHue.addClient(node)
|
|
1536
|
+
node.serverHue.removeClient(node)
|
|
1537
|
+
node.serverHue.addClient(node)
|
|
1541
1538
|
} catch (error) {
|
|
1542
|
-
RED.log.error(
|
|
1539
|
+
RED.log.error('knxUltimateHueLight: if (node.serverKNX): ' + error.message)
|
|
1543
1540
|
}
|
|
1544
1541
|
}
|
|
1545
1542
|
|
|
1546
1543
|
node.on('input', (msg, send, done) => {
|
|
1547
1544
|
try {
|
|
1548
|
-
const state = RED.util.cloneMessage(msg)
|
|
1549
|
-
node.writeHueState(state)
|
|
1545
|
+
const state = RED.util.cloneMessage(msg)
|
|
1546
|
+
node.writeHueState(state)
|
|
1550
1547
|
node.setNodeStatusHue({
|
|
1551
|
-
fill:
|
|
1552
|
-
shape:
|
|
1553
|
-
text:
|
|
1554
|
-
payload:
|
|
1555
|
-
})
|
|
1548
|
+
fill: 'green',
|
|
1549
|
+
shape: 'dot',
|
|
1550
|
+
text: '->HUE',
|
|
1551
|
+
payload: 'Flow msg.'
|
|
1552
|
+
})
|
|
1556
1553
|
} catch (error) {
|
|
1557
1554
|
node.setNodeStatusHue({
|
|
1558
|
-
fill:
|
|
1559
|
-
shape:
|
|
1560
|
-
text:
|
|
1561
|
-
payload: error.message
|
|
1562
|
-
})
|
|
1555
|
+
fill: 'red',
|
|
1556
|
+
shape: 'dot',
|
|
1557
|
+
text: '->HUE',
|
|
1558
|
+
payload: error.message
|
|
1559
|
+
})
|
|
1563
1560
|
}
|
|
1564
1561
|
// Once finished, call 'done'.
|
|
1565
1562
|
// This call is wrapped in a check that 'done' exists
|
|
1566
1563
|
// so the node will work in earlier versions of Node-RED (<1.0)
|
|
1567
1564
|
if (done) {
|
|
1568
|
-
done()
|
|
1565
|
+
done()
|
|
1569
1566
|
}
|
|
1570
|
-
})
|
|
1567
|
+
})
|
|
1571
1568
|
|
|
1572
|
-
node.on(
|
|
1569
|
+
node.on('close', (done) => {
|
|
1573
1570
|
if (node.serverKNX) {
|
|
1574
|
-
node.serverKNX.removeClient(node)
|
|
1571
|
+
node.serverKNX.removeClient(node)
|
|
1575
1572
|
}
|
|
1576
1573
|
if (node.serverHue) {
|
|
1577
|
-
node.serverHue.removeClient(node)
|
|
1574
|
+
node.serverHue.removeClient(node)
|
|
1578
1575
|
}
|
|
1579
|
-
done()
|
|
1580
|
-
})
|
|
1576
|
+
done()
|
|
1577
|
+
})
|
|
1581
1578
|
}
|
|
1582
|
-
RED.nodes.registerType(
|
|
1583
|
-
}
|
|
1579
|
+
RED.nodes.registerType('knxUltimateHueLight', knxUltimateHueLight)
|
|
1580
|
+
}
|