From e2bf5b065447f4fdef41857e40305a17d7b6ee93 Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Mon, 27 Jan 2020 08:56:26 +0100 Subject: [PATCH] feat: Support for fans in climate and better sensor multilevel discovery based on units #218 #213 --- hass/configurations.js | 17 ++++++++++ lib/Gateway.js | 70 +++++++++++++++++++++++++++++++++--------- 2 files changed, 72 insertions(+), 15 deletions(-) diff --git a/hass/configurations.js b/hass/configurations.js index cff0eb5426b..77a7c8f11d4 100755 --- a/hass/configurations.js +++ b/hass/configurations.js @@ -200,6 +200,14 @@ module.exports = { value_template: '{{ value_json.value }}' } }, + 'sensor_angle': { + type: 'sensor', + object_id: 'angle', + discovery_payload: { + icon: 'mdi:angle-acute', + value_template: '{{ value_json.value }}' + } + }, 'sensor_power': { type: 'sensor', object_id: 'power', @@ -209,6 +217,15 @@ module.exports = { value_template: '{{ value_json.value }}' } }, + 'sensor_speed': { + type: 'sensor', + object_id: 'speed', + discovery_payload: { + unit_of_measurement: 'Km/h', + icon: 'mdi:speedometer', + value_template: '{{ value_json.value }}' + } + }, 'sensor_action': { type: 'sensor', object_id: 'action', diff --git a/lib/Gateway.js b/lib/Gateway.js index 17bdea56a9a..3bde049f75f 100755 --- a/lib/Gateway.js +++ b/lib/Gateway.js @@ -353,6 +353,34 @@ function copy (obj) { return JSON.parse(JSON.stringify(obj)) } +/** + * Get Hass configurations based on valueID units + * + * @param {String} units The valueID units + * @returns An array with compatible configurations + */ +function typeByUnits (units) { + var cfg = null + + // TODO: Support more units: https://github.com/OpenZWave/open-zwave/blob/master/config/SensorMultiLevelCCTypes.xml + + if (/\b(%)\b/gi.test(units)) { + cfg = ['sensor_illuminance', 'sensor_humidity', 'sensor_gas_density'] + } else if (/\b(m\/s|mph|km\/h|kmh)\b/gi.test(units)) { + cfg = ['sensor_speed'] + } else if (/\b(°)\b/gi.test(units)) { + cfg = ['sensor_angle'] + } else if (/\b(c|f)\b/gi.test(units)) { + cfg = ['sensor_temperature'] + } else if (/\b(w|v|watt|volt|kw|kwh|kw\/h)\b/gi.test(units)) { + cfg = ['sensor_power'] + } else if (/\b(bar|pa|g\/m3|mmhg)\b/gi.test(units)) { + cfg = ['sensor_humidity'] + } + + return cfg +} + /** * Get the device Object to send in discovery payload * @@ -382,19 +410,20 @@ function getDiscoveryTopic (hassDevice, nodeName) { } /** - * Calcolate the correct template string to use for Hass climate mode value + * Calcolate the correct template string to use for modes templates * based on gateway settings and mapped mode values * * @param {Object} valueId Zwave ValueId object * @param {Object} modeMap The Object with mode mapping key : value * @param {Boolean} integerList Gateway setting for sending list values as integer index + * @param {String} defaultValue The default value for the mode * @returns A string with the template to use for mode */ -function getMappedValues (valueId, modeMap, integerList) { +function getMappedValues (valueId, modeMap, integerList, defaultValue) { var map = {} for (const k in modeMap) map[modeMap[k]] = k - if (!integerList) return { map: map, check: 'values[value_json.value] if value_json.value in values.keys() else \'off\'' } + if (!integerList) return { map: map, check: 'values[value_json.value] if value_json.value in values.keys() else \'' + defaultValue + '\'' } var mapi = {} @@ -402,7 +431,7 @@ function getMappedValues (valueId, modeMap, integerList) { mapi[i.toString()] = map[valueId.values[i]] } - return { map: mapi, check: 'values[value_json.value | string] if value_json.value | string in values else \'off\'' } + return { map: mapi, check: 'values[value_json.value | string] if value_json.value | string in values else \'' + defaultValue + '\'' } } /** @@ -635,17 +664,30 @@ Gateway.prototype.discoverDevice = function (node, hassDevice) { var mode = node.values[payload.mode_state_topic] var currTemp = node.values[payload.current_temperature_topic] var setId - var map = getMappedValues(mode, hassDevice.mode_map, this.config.integerList) if (mode !== undefined) { setId = hassDevice.setpoint_topic && hassDevice.setpoint_topic[mode.value] ? hassDevice.setpoint_topic[mode.value] : hassDevice.default_setpoint // only setup modes if a state topic was defined + let map = getMappedValues(mode, hassDevice.mode_map, this.config.integerList, 'off') payload.mode_state_template = `{% set values = ${JSON.stringify(map.map)} %} {{ ${map.check} }}` payload.mode_state_topic = this.mqtt.getTopic(this.valueTopic(node, mode)) payload.mode_command_topic = payload.mode_state_topic + '/set' } else { setId = hassDevice.default_setpoint } + + var fan = node.values[payload.fan_mode_state_topic] + + if (fan !== undefined) { + payload.fan_mode_state_topic = this.mqtt.getTopic(this.valueTopic(node, fan)) + payload.fan_mode_command_topic = payload.fan_mode_state_topic + '/set' + + if (hassDevice.fan_mode_map) { + let map = getMappedValues(mode, hassDevice.fan_mode_map, this.config.integerList, 'auto') + payload.fan_mode_state_template = `{% set values = ${JSON.stringify(map.map)} %} {{ ${map.check} }}` + } + } + var setpoint = node.values[setId] payload.current_temperature_topic = this.mqtt.getTopic(this.valueTopic(node, currTemp)) @@ -863,20 +905,18 @@ Gateway.prototype.discoverValue = function (node, valueId) { } } - if (cfg) cfg = copy(hassCfg[cfg]) - else { - // try to guess sensor type - if (/°|C/gi.test(valueId.units)) { - cfg = copy(hassCfg.sensor_temperature) - } else if (/W/gi.test(valueId.units)) { - cfg = copy(hassCfg.sensor_power) - } else { - cfg = copy(hassCfg.sensor_generic) + if (valueId.units) { + cfg.discovery_payload.unit_of_measurement = valueId.units + let validCfgs = typeByUnits(valueId.units) + + if (validCfgs.length > 0 && validCfgs.indexOf(cfg) < 0) { + cfg = validCfgs[0] } } - if (valueId.units) cfg.discovery_payload.unit_of_measurement = valueId.units + cfg = cfg ? copy(hassCfg[cfg]) : copy(hassCfg.sensor_generic) + // check if there is a custom value configuration for this valueID if (valueConf) { if (valueConf.device_class) { cfg.discovery_payload.device_class = valueConf.device_class