From 4beadd71e1cf70e4c81f4aadb41c0e80285e948f Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Fri, 11 Dec 2020 15:37:23 +0100 Subject: [PATCH 1/4] fix: improve hass discovery of climates --- README.md | 4 ++-- lib/Gateway.js | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 8dc529ad2bc..4a247c3b724 100644 --- a/README.md +++ b/README.md @@ -528,8 +528,8 @@ You can specify your custom devices configuration inside `store/customDevices(.j ], mode_map: { off: 0, heat: 1, cool: 2 }, setpoint_topic: { - 'Heat (Default)': '67-0-setpoint-1', - Cool: '67-0-setpoint-2' + 1: '67-0-setpoint-1', + 2: '67-0-setpoint-2' }, default_setpoint: '67-0-setpoint-1', discovery_payload: { diff --git a/lib/Gateway.js b/lib/Gateway.js index 9d1ea02496b..f212ac52921 100755 --- a/lib/Gateway.js +++ b/lib/Gateway.js @@ -1219,7 +1219,7 @@ Gateway.prototype.discoverClimates = function (node) { const availableModes = mode.states.map(s => s.value) // Zwave modes: https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/commandclass/ThermostatModeCC.ts#L54 - // Available hass modes: [“auto”, “off”, “cool”, “heat”, “dry”, “fan_only”] + const allowedModes = ['off', 'heat', 'cool', 'auto', 'dry', 'fan_only'] const hassModes = [ 'off', 'heat', @@ -1253,8 +1253,17 @@ Gateway.prototype.discoverClimates = function (node) { for (const m of availableModes) { if (hassModes[m] === undefined) continue - config.mode_map[hassModes[m]] = availableModes[m] - config.discovery_payload.modes.push(hassModes[m]) + let hM = hassModes[m] + + // it could happen that mode_map already have defined a mode for this value, in this case + // map that mode to the first one available in the allowed hass modes + const i = 1 // skip 'off' + while (config.mode_map.hasOwnProperty(hM) && i < allowedModes.length) { + hM = allowedModes[i] + } + + config.mode_map[hM] = availableModes[m] + config.discovery_payload.modes.push(hM) if (m > 0) { // find the mode setpoint, ignore off const setId = setpoints.find(v => v.endsWith('-' + m)) From 43509e4f571ab575a63b99a416244f6a1c2ce6be Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Mon, 14 Dec 2020 10:34:54 +0100 Subject: [PATCH 2/4] fix: handle single mode setpoints and add mode command topic --- lib/Gateway.js | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/lib/Gateway.js b/lib/Gateway.js index f212ac52921..641924e22cf 100755 --- a/lib/Gateway.js +++ b/lib/Gateway.js @@ -1242,13 +1242,20 @@ Gateway.prototype.discoverClimates = function (node) { // generic configuration const config = copy(hassCfg.thermostat) - config.mode_map = {} - config.setpoint_topic = {} config.values = [modeId, temperatureId] - config.discovery_payload.mode_state_topic = modeId config.discovery_payload.current_temperature_topic = temperatureId + // if there is more then one mode available we need to + // add mode command/state + if (setpoints.length > 1) { + config.discovery_payload.mode_state_topic = modeId + config.discovery_payload.mode_command_topic = modeId + '/set' + } + + config.mode_map = {} + config.setpoint_topic = {} + // for all available modes update the modes map and setpoint topics for (const m of availableModes) { if (hassModes[m] === undefined) continue @@ -1258,7 +1265,10 @@ Gateway.prototype.discoverClimates = function (node) { // it could happen that mode_map already have defined a mode for this value, in this case // map that mode to the first one available in the allowed hass modes const i = 1 // skip 'off' - while (config.mode_map.hasOwnProperty(hM) && i < allowedModes.length) { + while ( + config.discovery_payload.modes.includes(hM) && + i < allowedModes.length + ) { hM = allowedModes[i] } @@ -1269,16 +1279,17 @@ Gateway.prototype.discoverClimates = function (node) { const setId = setpoints.find(v => v.endsWith('-' + m)) const setpoint = node.values[setId] if (setpoint) { - if (setpoint.propertyKey === 1) { - config.default_setpoint = setId - } - config.values.push(setId) config.setpoint_topic[m] = setId } } } + // set the default setpoint to 'heat' or to the first setpoint available + config.default_setpoint = + config.setpoint_topic[1] || + config.setpoint_topic[Object.keys(config.setpoint)[0]] + // add the new climate config to the nodeDevices so it will be // discovered later when we call `discoverDevice` nodeDevices.push(config) From 1c7d692d3fd2486669d76b9e3365f9d2ecbe4adf Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Mon, 14 Dec 2020 10:44:33 +0100 Subject: [PATCH 3/4] fix: climate discovery for single mode thermostat like danfoss --- lib/Gateway.js | 136 +++++++++++++++++++++++++------------------------ 1 file changed, 69 insertions(+), 67 deletions(-) diff --git a/lib/Gateway.js b/lib/Gateway.js index 641924e22cf..b562c94ee04 100755 --- a/lib/Gateway.js +++ b/lib/Gateway.js @@ -1200,95 +1200,97 @@ Gateway.prototype.discoverClimates = function (node) { } } - // take the first as valid (there shouldn't be more then one) - const modeId = modes[0] - // TODO: if the device supports multiple endpoints how could we identify the correct one to use? const temperatureId = temperatures[0] - if (!temperatureId || !modeId) { + if (!temperatureId) { debug( - 'Unable to discover climate device, there is no valid temperature/thermostat mode valueIds' + 'Unable to discover climate device, there is no valid temperature valueId' ) return } - const mode = node.values[modeId] - - // [0, 1, 2 ... ] (['off', 'heat', 'cold', ...]) - const availableModes = mode.states.map(s => s.value) - - // Zwave modes: https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/commandclass/ThermostatModeCC.ts#L54 - const allowedModes = ['off', 'heat', 'cool', 'auto', 'dry', 'fan_only'] - const hassModes = [ - 'off', - 'heat', - 'cool', - 'auto', - undefined, // auxiliary - undefined, // resume - 'fan_only', - undefined, // furnace - 'dry', - undefined, // moist - 'auto', // auto changeover - 'heat', // energy heat - 'cool', // energy cool - 'off', // away - 'heat', // full power - undefined // manufacturer specific - ] - // generic configuration const config = copy(hassCfg.thermostat) - - config.values = [modeId, temperatureId] - config.discovery_payload.current_temperature_topic = temperatureId - // if there is more then one mode available we need to - // add mode command/state - if (setpoints.length > 1) { - config.discovery_payload.mode_state_topic = modeId - config.discovery_payload.mode_command_topic = modeId + '/set' - } + config.values = [temperatureId] - config.mode_map = {} - config.setpoint_topic = {} + // take the first as valid + const modeId = modes[0] - // for all available modes update the modes map and setpoint topics - for (const m of availableModes) { - if (hassModes[m] === undefined) continue + // some thermostats could support just one mode so haven't a thermostat mode CC + if (modeId) { + config.values.push(modeId) - let hM = hassModes[m] + const mode = node.values[modeId] - // it could happen that mode_map already have defined a mode for this value, in this case - // map that mode to the first one available in the allowed hass modes - const i = 1 // skip 'off' - while ( - config.discovery_payload.modes.includes(hM) && + config.discovery_payload.mode_state_topic = modeId + config.discovery_payload.mode_command_topic = modeId + '/set' + + // [0, 1, 2 ... ] (['off', 'heat', 'cold', ...]) + const availableModes = mode.states.map(s => s.value) + + // Zwave modes: https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/commandclass/ThermostatModeCC.ts#L54 + const allowedModes = ['off', 'heat', 'cool', 'auto', 'dry', 'fan_only'] + const hassModes = [ + 'off', + 'heat', + 'cool', + 'auto', + undefined, // auxiliary + undefined, // resume + 'fan_only', + undefined, // furnace + 'dry', + undefined, // moist + 'auto', // auto changeover + 'heat', // energy heat + 'cool', // energy cool + 'off', // away + 'heat', // full power + undefined // manufacturer specific + ] + + config.mode_map = {} + config.setpoint_topic = {} + + // for all available modes update the modes map and setpoint topics + for (const m of availableModes) { + if (hassModes[m] === undefined) continue + + let hM = hassModes[m] + + // it could happen that mode_map already have defined a mode for this value, in this case + // map that mode to the first one available in the allowed hass modes + const i = 1 // skip 'off' + while ( + config.discovery_payload.modes.includes(hM) && i < allowedModes.length - ) { - hM = allowedModes[i] - } + ) { + hM = allowedModes[i] + } - config.mode_map[hM] = availableModes[m] - config.discovery_payload.modes.push(hM) - if (m > 0) { + config.mode_map[hM] = availableModes[m] + config.discovery_payload.modes.push(hM) + if (m > 0) { // find the mode setpoint, ignore off - const setId = setpoints.find(v => v.endsWith('-' + m)) - const setpoint = node.values[setId] - if (setpoint) { - config.values.push(setId) - config.setpoint_topic[m] = setId + const setId = setpoints.find(v => v.endsWith('-' + m)) + const setpoint = node.values[setId] + if (setpoint) { + config.values.push(setId) + config.setpoint_topic[m] = setId + } } } - } - // set the default setpoint to 'heat' or to the first setpoint available - config.default_setpoint = - config.setpoint_topic[1] || - config.setpoint_topic[Object.keys(config.setpoint)[0]] + // set the default setpoint to 'heat' or to the first setpoint available + config.default_setpoint = + config.setpoint_topic[1] || + config.setpoint_topic[Object.keys(config.setpoint)[0]] + } else { + config.default_setpoint = setpoints[0] + } // add the new climate config to the nodeDevices so it will be // discovered later when we call `discoverDevice` From d4ddd30fcc5322eadb15df135c1bf5470dc65e4a Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Mon, 14 Dec 2020 10:47:07 +0100 Subject: [PATCH 4/4] fix: lint issues --- lib/Gateway.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Gateway.js b/lib/Gateway.js index b562c94ee04..5cd901c9e9d 100755 --- a/lib/Gateway.js +++ b/lib/Gateway.js @@ -1266,7 +1266,7 @@ Gateway.prototype.discoverClimates = function (node) { const i = 1 // skip 'off' while ( config.discovery_payload.modes.includes(hM) && - i < allowedModes.length + i < allowedModes.length ) { hM = allowedModes[i] } @@ -1274,7 +1274,7 @@ Gateway.prototype.discoverClimates = function (node) { config.mode_map[hM] = availableModes[m] config.discovery_payload.modes.push(hM) if (m > 0) { - // find the mode setpoint, ignore off + // find the mode setpoint, ignore off const setId = setpoints.find(v => v.endsWith('-' + m)) const setpoint = node.values[setId] if (setpoint) { @@ -1286,8 +1286,8 @@ Gateway.prototype.discoverClimates = function (node) { // set the default setpoint to 'heat' or to the first setpoint available config.default_setpoint = - config.setpoint_topic[1] || - config.setpoint_topic[Object.keys(config.setpoint)[0]] + config.setpoint_topic[1] || + config.setpoint_topic[Object.keys(config.setpoint)[0]] } else { config.default_setpoint = setpoints[0] }