Skip to content

Commit

Permalink
feat: Support for fans in climate and better sensor multilevel discov…
Browse files Browse the repository at this point in the history
…ery based on units #218 #213
  • Loading branch information
robertsLando committed Jan 27, 2020
1 parent e21dd72 commit e2bf5b0
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 15 deletions.
17 changes: 17 additions & 0 deletions hass/configurations.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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',
Expand Down
70 changes: 55 additions & 15 deletions lib/Gateway.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down Expand Up @@ -382,27 +410,28 @@ 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 = {}

for (let i = 0; i < valueId.values.length; i++) {
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 + '\'' }
}

/**
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit e2bf5b0

Please sign in to comment.