Skip to content

Commit

Permalink
feat: improve HASS discovery of cover devices (#783)
Browse files Browse the repository at this point in the history
  • Loading branch information
p4p3r authored Oct 13, 2020
1 parent b5396be commit 17bfbfe
Show file tree
Hide file tree
Showing 5 changed files with 339 additions and 24 deletions.
11 changes: 7 additions & 4 deletions hass/configurations.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,14 +226,17 @@ module.exports = {
},
cover_position: {
type: 'cover',
object_id: 'cover',
object_id: 'position',
discovery_payload: {
state_topic: true,
command_topic: true,
position_topic: true,
set_position_topic: true,
set_position_template: '{ "value": {{ position }} }',
value_template: '{{ value_json.value }}',
state_topic: false
value_template: '{{ value_json.value | round(0) }}',
position_open: 99,
position_closed: 0,
payload_open: '99',
payload_close: '0'
}
},

Expand Down
248 changes: 248 additions & 0 deletions lib/Constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -370,5 +370,253 @@ module.exports = {
},
commandClass (cmd) {
return this._commandClassMap[cmd] || 'unknownClass_' + cmd
},
_genericDeviceClassMap: {
// https://github.com/OpenZWave/open-zwave/blob/master/config/device_classes.xml
// https://github.com/home-assistant/core/blob/dev/homeassistant/components/zwave/const.py#L196
// 0x00: specific_type_not_used // Available in all Generic types
0x01: {
generic: 'generic_type_generic_controller',
specific: {
0x01: 'specific_type_portable_controller',
0x02: 'specific_type_portable_scene_controller',
0x03: 'specific_type_portable_installer_tool',
0x04: 'specific_type_control_av',
0x06: 'specific_type_control_simple'
}
},
0x02: {
generic: 'generic_type_static_controller',
specific: {
0x01: 'specific_type_pc_controller',
0x02: 'specific_type_scene_controller',
0x03: 'specific_type_static_installer_tool',
0x04: 'specific_type_set_top_box',
0x05: 'specific_type_sub_system_controller',
0x06: 'specific_type_tv',
0x07: 'specific_type_gateway'
}
},
0x03: {
generic: 'generic_type_av_control_point',
specific: {
0x01: 'specific_type_sound_switch',
0x04: 'specific_type_satellite_receiver',
0x11: 'specific_type_satellite_receiver_v2',
0x12: 'specific_type_doorbell'
}
},
0x04: {
generic: 'generic_type_display',
specific: {
0x01: 'specific_type_simple_display'
}
},
0x05: {
generic: 'generic_type_network_extender',
specific: {
0x01: 'specific_type_secure_extender'
}
},
0x06: {
generic: 'generic_type_appliance',
specific: {
0x01: 'specific_type_general_appliance',
0x02: 'specific_type_kitchen_appliance',
0x03: 'specific_type_laundry_appliance'
}
},
0x07: {
generic: 'generic_type_sensor_notification',
specific: {
0x01: 'specific_type_notification_sensor'
}
},
0x08: {
generic: 'generic_type_thermostat',
specific: {
0x01: 'specific_type_thermostat_heating',
0x02: 'specific_type_thermostat_general',
0x03: 'specific_type_setback_schedule_thermostat',
0x04: 'specific_type_setpoint_thermostat',
0x05: 'specific_type_setback_thermostat',
0x06: 'specific_type_thermostat_general_v2'
}
},
0x09: {
generic: 'generic_type_windows_covering',
specific: {
0x01: 'specific_type_simple_window_covering'
}
},
0x0f: {
generic: 'generic_type_repeater_slave',
specific: {
0x01: 'specific_type_repeater_slave',
0x02: 'specific_type_virtual_node'
}
},
0x10: {
generic: 'generic_type_switch_binary',
specific: {
0x01: 'specific_type_power_switch_binary',
0x02: 'specific_type_color_tunable_binary',
0x03: 'specific_type_scene_switch_binary',
0x04: 'specific_type_power_strip',
0x05: 'specific_type_siren',
0x06: 'specific_type_valve_open_close',
0x07: 'specific_type_irrigation_controller'
}
},
0x11: {
generic: 'generic_type_switch_multilevel',
specific: {
0x01: 'specific_type_power_switch_multilevel',
0x02: 'specific_type_color_tunable_multilevel',
0x03: 'specific_type_motor_multiposition',
0x04: 'specific_type_scene_switch_multilevel',
0x05: 'specific_type_class_a_motor_control',
0x06: 'specific_type_class_b_motor_control',
0x07: 'specific_type_class_c_motor_control',
0x08: 'specific_type_fan_switch'
}
},
0x12: {
generic: 'generic_type_switch_remote',
specific: {
0x01: 'specific_type_remote_binary',
0x02: 'specific_type_remote_multilevel',
0x03: 'specific_type_remove_toggle_binary',
0x04: 'specific_type_remote_toggle_multilevel'
}
},
0x13: {
generic: 'generic_type_switch_toggle',
specific: {
0x01: 'specific_type_switch_toggle_binary',
0x02: 'specific_type_switch_toggle_multilevel'
}
},
0x14: {
generic: 'generic_type_zip_gateway',
specific: {
0x01: 'specific_type_zip_tun_gateway',
0x02: 'specific_type_zip_adv_gateway'
}
},
0x15: {
generic: 'generic_type_zip_node',
specific: {
0x01: 'specific_type_zip_tun_node',
0x02: 'specific_type_zip_adv_node'
}
},
0x16: {
generic: 'generic_type_ventilation',
specific: {
0x01: 'specific_type_residential_hrv'
}
},
0x17: {
generic: 'generic_type_security_panel',
specific: {
0x01: 'specific_type_zoned_security_panel'
}
},
0x18: {
generic: 'generic_type_wall_controller',
specific: {
0x01: 'specific_type_basic_wall_controller'
}
},
0x20: {
generic: 'generic_type_sensor_binary',
specific: {
0x01: 'specific_type_routing_sensor_binary'
}
},
0x21: {
generic: 'generic_type_sensor_multilevel',
specific: {
0x01: 'specific_type_routing_sensor_multilevel',
0x02: 'specific_type_chimney_fan'
}
},
0x30: {
generic: 'generic_type_meter_pulse',
specific: {}
},
0x31: {
generic: 'generic_type_meter',
specific: {
0x01: 'specific_type_simple_meter',
0x02: 'specific_type_adv_energy_control',
0x03: 'specific_type_whole_home_meter_simple'
}
},
0x40: {
generic: 'generic_type_entry_control',
specific: {
0x01: 'specific_type_door_lock',
0x02: 'specific_type_advanced_door_lock',
0x03: 'specific_type_secure_keypad_door_lock',
0x04: 'specific_type_secure_keypad_door_lock_deadbolt',
0x05: 'specific_type_secure_door',
0x06: 'specific_type_secure_gate',
0x07: 'specific_type_secure_barrier_addon',
0x08: 'specific_type_secure_barrier_open_only',
0x09: 'specific_type_secure_barrier_close_only',
0x0a: 'specific_type_secure_lockbox',
0x0b: 'specific_type_secure_keypad'
}
},
0x50: {
generic: 'generic_type_semi_interoperable',
specific: {
0x01: 'specific_type_energy_production'
}
},
0xa1: {
generic: 'generic_type_sensor_alarm',
specific: {
0x01: 'specific_type_basic_routing_alarm_sensor',
0x02: 'specific_type_routing_alarm_sensor',
0x03: 'specific_type_basic_zensor_net_alarm_sensor',
0x04: 'specific_type_zensor_net_alarm_sensor',
0x05: 'specific_type_adv_zensor_net_alarm_sensor',
0x06: 'specific_type_basic_routing_smoke_sensor',
0x07: 'specific_type_routing_smoke_sensor',
0x08: 'specific_type_basic_zensor_net_smoke_sensor',
0x09: 'specific_type_zensor_net_smoke_sensor',
0x0a: 'specific_type_adv_zensor_net_smoke_sensor',
0x0b: 'specific_type_alarm_sensor'
}
},
0xff: {
generic: 'generic_type_non_interoperable',
specific: {}
}
},
genericDeviceClassAttributes (cls) {
return this._genericDeviceClassMap[cls]
},
genericDeviceClass (cls) {
var clsAttr = this.genericDeviceClassAttributes(cls)
if (clsAttr) {
return clsAttr.generic
} else {
return 'unknownGenericDeviceType_' + cls
}
},
specificDeviceClass (genericCls, specificCls) {
var clsAttr = this.genericDeviceClassAttributes(genericCls)
if (clsAttr) {
return (
clsAttr.specific[specificCls] ||
'unknownSpecificDeviceType_' + specificCls
)
} else {
return 'unknownGenericDeviceType_' + genericCls
}
}
}
64 changes: 44 additions & 20 deletions lib/Gateway.js
Original file line number Diff line number Diff line change
Expand Up @@ -1095,28 +1095,52 @@ Gateway.prototype.discoverValue = function (node, valueId) {
break
case 'switch_multilevel':
case 'switch_toggle_multilevel':
// cfg = copy(hassCfg.cover_position)
// cfg.discovery_payload.position_open = valueId.max || 100
// cfg.discovery_payload.position_closed = valueId.min || 0
// cfg.discovery_payload.position_topic = this.mqtt.getTopic(topic)
// cfg.discovery_payload.set_position_topic = cfg.discovery_payload.position_topic + '/set'
if (valueId.index === 0) {
// brightness level
const rgb = node.values['51-1-0']
if (rgb) {
cfg = copy(hassCfg.light_rgb_dimmer)
cfg.discovery_payload.rgb_state_topic = this.mqtt.getTopic(
this.valueTopic(node, rgb)
)
cfg.discovery_payload.rgb_command_topic =
cfg.discovery_payload.rgb_state_topic + '/set'
cfg.discovery_payload.brightness_state_topic = this.mqtt.getTopic(
topic
)
cfg.discovery_payload.brightness_command_topic =
cfg.discovery_payload.brightness_state_topic + '/set'
var specificDeviceClass = Constants.specificDeviceClass(
node.generic_device_class,
node.specific_device_class
)
// Use a cover_position configuration if ...
if (
[
'specific_type_class_a_motor_control',
'specific_type_class_b_motor_control',
'specific_type_class_c_motor_control',
'specific_type_class_motor_multiposition'
].includes(specificDeviceClass)
) {
cfg = copy(hassCfg.cover_position)
cfg.discovery_payload.state_topic = this.mqtt.getTopic(topic)
cfg.discovery_payload.command_topic =
cfg.discovery_payload.state_topic + '/set'
cfg.discovery_payload.position_topic = this.mqtt.getTopic(topic)
cfg.discovery_payload.set_position_topic =
cfg.discovery_payload.position_topic + '/set'
cfg.discovery_payload.value_template =
'{{ value_json.value | round(0) }}'
cfg.discovery_payload.position_open = 99
cfg.discovery_payload.position_closed = 0
cfg.discovery_payload.payload_open = 99
cfg.discovery_payload.payload_close = 0
} else {
cfg = copy(hassCfg.light_dimmer)
// ... otherwise use a light dimmer configuration
// brightness level
const rgb = node.values['51-1-0']
if (rgb) {
cfg = copy(hassCfg.light_rgb_dimmer)
cfg.discovery_payload.rgb_state_topic = this.mqtt.getTopic(
this.valueTopic(node, rgb)
)
cfg.discovery_payload.rgb_command_topic =
cfg.discovery_payload.rgb_state_topic + '/set'
cfg.discovery_payload.brightness_state_topic = this.mqtt.getTopic(
topic
)
cfg.discovery_payload.brightness_command_topic =
cfg.discovery_payload.brightness_state_topic + '/set'
} else {
cfg = copy(hassCfg.light_dimmer)
}
}
} else return
break
Expand Down
4 changes: 4 additions & 0 deletions lib/ZwaveClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -906,6 +906,10 @@ ZwaveClient.prototype.initNode = function (ozwnode, nodeinfo) {
var deviceID = getDeviceID(ozwnode)
ozwnode.device_id = deviceID

ozwnode.basic_device_class = this.client.getNodeBasic(nodeid)
ozwnode.generic_device_class = this.client.getNodeGeneric(nodeid)
ozwnode.specific_device_class = this.client.getNodeSpecific(nodeid)

// if scan is complete update node groups (for nodes added 'on fly')
if (this.scanComplete) {
this.getGroups(nodeid)
Expand Down
Loading

0 comments on commit 17bfbfe

Please sign in to comment.