263 lines
9.8 KiB
Python
263 lines
9.8 KiB
Python
"""Map Z-Wave nodes and values to Home Assistant entities."""
|
|
import openzwavemqtt.const as const_ozw
|
|
from openzwavemqtt.const import CommandClass, ValueGenre, ValueIndex, ValueType
|
|
|
|
from . import const
|
|
|
|
DISCOVERY_SCHEMAS = (
|
|
{ # Binary sensors
|
|
const.DISC_COMPONENT: "binary_sensor",
|
|
const.DISC_VALUES: {
|
|
const.DISC_PRIMARY: {
|
|
const.DISC_COMMAND_CLASS: CommandClass.SENSOR_BINARY,
|
|
const.DISC_TYPE: ValueType.BOOL,
|
|
const.DISC_GENRE: ValueGenre.USER,
|
|
},
|
|
"off_delay": {
|
|
const.DISC_COMMAND_CLASS: CommandClass.CONFIGURATION,
|
|
const.DISC_INDEX: 9,
|
|
const.DISC_OPTIONAL: True,
|
|
},
|
|
},
|
|
},
|
|
{ # Notification CommandClass translates to binary_sensor
|
|
const.DISC_COMPONENT: "binary_sensor",
|
|
const.DISC_VALUES: {
|
|
const.DISC_PRIMARY: {
|
|
const.DISC_COMMAND_CLASS: CommandClass.NOTIFICATION,
|
|
const.DISC_GENRE: ValueGenre.USER,
|
|
const.DISC_TYPE: (ValueType.BOOL, ValueType.LIST),
|
|
}
|
|
},
|
|
},
|
|
{ # Z-Wave Thermostat device translates to Climate entity
|
|
const.DISC_COMPONENT: "climate",
|
|
const.DISC_GENERIC_DEVICE_CLASS: (
|
|
const_ozw.GENERIC_TYPE_THERMOSTAT,
|
|
const_ozw.GENERIC_TYPE_SENSOR_MULTILEVEL,
|
|
),
|
|
const.DISC_SPECIFIC_DEVICE_CLASS: (
|
|
const_ozw.SPECIFIC_TYPE_THERMOSTAT_GENERAL,
|
|
const_ozw.SPECIFIC_TYPE_THERMOSTAT_GENERAL_V2,
|
|
const_ozw.SPECIFIC_TYPE_SETBACK_THERMOSTAT,
|
|
const_ozw.SPECIFIC_TYPE_THERMOSTAT_HEATING,
|
|
const_ozw.SPECIFIC_TYPE_SETPOINT_THERMOSTAT,
|
|
const_ozw.SPECIFIC_TYPE_NOT_USED,
|
|
),
|
|
const.DISC_VALUES: {
|
|
const.DISC_PRIMARY: {
|
|
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_MODE,)
|
|
},
|
|
"mode": {
|
|
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_MODE,),
|
|
const.DISC_OPTIONAL: True,
|
|
},
|
|
"temperature": {
|
|
const.DISC_COMMAND_CLASS: (CommandClass.SENSOR_MULTILEVEL,),
|
|
const.DISC_INDEX: (1,),
|
|
const.DISC_OPTIONAL: True,
|
|
},
|
|
"fan_mode": {
|
|
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_FAN_MODE,),
|
|
const.DISC_OPTIONAL: True,
|
|
},
|
|
"operating_state": {
|
|
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_OPERATING_STATE,),
|
|
const.DISC_OPTIONAL: True,
|
|
},
|
|
"fan_action": {
|
|
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_FAN_STATE,),
|
|
const.DISC_OPTIONAL: True,
|
|
},
|
|
"valve_position": {
|
|
const.DISC_COMMAND_CLASS: (CommandClass.SWITCH_MULTILEVEL,),
|
|
const.DISC_INDEX: (0,),
|
|
const.DISC_OPTIONAL: True,
|
|
},
|
|
"setpoint_heating": {
|
|
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_SETPOINT,),
|
|
const.DISC_INDEX: (1,),
|
|
const.DISC_OPTIONAL: True,
|
|
},
|
|
"setpoint_cooling": {
|
|
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_SETPOINT,),
|
|
const.DISC_INDEX: (2,),
|
|
const.DISC_OPTIONAL: True,
|
|
},
|
|
"setpoint_furnace": {
|
|
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_SETPOINT,),
|
|
const.DISC_INDEX: (7,),
|
|
const.DISC_OPTIONAL: True,
|
|
},
|
|
"setpoint_dry_air": {
|
|
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_SETPOINT,),
|
|
const.DISC_INDEX: (8,),
|
|
const.DISC_OPTIONAL: True,
|
|
},
|
|
"setpoint_moist_air": {
|
|
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_SETPOINT,),
|
|
const.DISC_INDEX: (9,),
|
|
const.DISC_OPTIONAL: True,
|
|
},
|
|
"setpoint_auto_changeover": {
|
|
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_SETPOINT,),
|
|
const.DISC_INDEX: (10,),
|
|
const.DISC_OPTIONAL: True,
|
|
},
|
|
"setpoint_eco_heating": {
|
|
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_SETPOINT,),
|
|
const.DISC_INDEX: (11,),
|
|
const.DISC_OPTIONAL: True,
|
|
},
|
|
"setpoint_eco_cooling": {
|
|
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_SETPOINT,),
|
|
const.DISC_INDEX: (12,),
|
|
const.DISC_OPTIONAL: True,
|
|
},
|
|
"setpoint_away_heating": {
|
|
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_SETPOINT,),
|
|
const.DISC_INDEX: (13,),
|
|
const.DISC_OPTIONAL: True,
|
|
},
|
|
"setpoint_away_cooling": {
|
|
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_SETPOINT,),
|
|
const.DISC_INDEX: (14,),
|
|
const.DISC_OPTIONAL: True,
|
|
},
|
|
"setpoint_full_power": {
|
|
const.DISC_COMMAND_CLASS: (CommandClass.THERMOSTAT_SETPOINT,),
|
|
const.DISC_INDEX: (15,),
|
|
const.DISC_OPTIONAL: True,
|
|
},
|
|
},
|
|
},
|
|
{ # Light
|
|
const.DISC_COMPONENT: "light",
|
|
const.DISC_GENERIC_DEVICE_CLASS: (
|
|
const_ozw.GENERIC_TYPE_SWITCH_MULTILEVEL,
|
|
const_ozw.GENERIC_TYPE_SWITCH_REMOTE,
|
|
),
|
|
const.DISC_SPECIFIC_DEVICE_CLASS: (
|
|
const_ozw.SPECIFIC_TYPE_POWER_SWITCH_MULTILEVEL,
|
|
const_ozw.SPECIFIC_TYPE_SCENE_SWITCH_MULTILEVEL,
|
|
const_ozw.SPECIFIC_TYPE_NOT_USED,
|
|
),
|
|
const.DISC_VALUES: {
|
|
const.DISC_PRIMARY: {
|
|
const.DISC_COMMAND_CLASS: (CommandClass.SWITCH_MULTILEVEL,),
|
|
const.DISC_INDEX: ValueIndex.SWITCH_MULTILEVEL_LEVEL,
|
|
const.DISC_TYPE: ValueType.BYTE,
|
|
},
|
|
"dimming_duration": {
|
|
const.DISC_COMMAND_CLASS: (CommandClass.SWITCH_MULTILEVEL,),
|
|
const.DISC_INDEX: ValueIndex.SWITCH_MULTILEVEL_DURATION,
|
|
const.DISC_OPTIONAL: True,
|
|
},
|
|
"color": {
|
|
const.DISC_COMMAND_CLASS: (CommandClass.SWITCH_COLOR,),
|
|
const.DISC_INDEX: ValueIndex.SWITCH_COLOR_COLOR,
|
|
const.DISC_OPTIONAL: True,
|
|
},
|
|
"color_channels": {
|
|
const.DISC_COMMAND_CLASS: (CommandClass.SWITCH_COLOR,),
|
|
const.DISC_INDEX: ValueIndex.SWITCH_COLOR_CHANNELS,
|
|
const.DISC_OPTIONAL: True,
|
|
},
|
|
},
|
|
},
|
|
{ # All other text/numeric sensors
|
|
const.DISC_COMPONENT: "sensor",
|
|
const.DISC_VALUES: {
|
|
const.DISC_PRIMARY: {
|
|
const.DISC_COMMAND_CLASS: (
|
|
CommandClass.SENSOR_MULTILEVEL,
|
|
CommandClass.METER,
|
|
CommandClass.ALARM,
|
|
CommandClass.SENSOR_ALARM,
|
|
CommandClass.INDICATOR,
|
|
CommandClass.BATTERY,
|
|
CommandClass.NOTIFICATION,
|
|
CommandClass.BASIC,
|
|
),
|
|
const.DISC_TYPE: (
|
|
ValueType.DECIMAL,
|
|
ValueType.INT,
|
|
ValueType.STRING,
|
|
ValueType.BYTE,
|
|
ValueType.LIST,
|
|
),
|
|
}
|
|
},
|
|
},
|
|
{ # Switch platform
|
|
const.DISC_COMPONENT: "switch",
|
|
const.DISC_VALUES: {
|
|
const.DISC_PRIMARY: {
|
|
const.DISC_COMMAND_CLASS: (CommandClass.SWITCH_BINARY,),
|
|
const.DISC_TYPE: ValueType.BOOL,
|
|
const.DISC_GENRE: ValueGenre.USER,
|
|
}
|
|
},
|
|
},
|
|
{ # Lock platform
|
|
const.DISC_COMPONENT: "lock",
|
|
const.DISC_VALUES: {
|
|
const.DISC_PRIMARY: {
|
|
const.DISC_COMMAND_CLASS: (CommandClass.DOOR_LOCK,),
|
|
const.DISC_TYPE: ValueType.BOOL,
|
|
const.DISC_GENRE: ValueGenre.USER,
|
|
}
|
|
},
|
|
},
|
|
)
|
|
|
|
|
|
def check_node_schema(node, schema):
|
|
"""Check if node matches the passed node schema."""
|
|
if const.DISC_NODE_ID in schema and node.node_id not in schema[const.DISC_NODE_ID]:
|
|
return False
|
|
if const.DISC_GENERIC_DEVICE_CLASS in schema and not eq_or_in(
|
|
node.node_generic, schema[const.DISC_GENERIC_DEVICE_CLASS]
|
|
):
|
|
return False
|
|
if const.DISC_SPECIFIC_DEVICE_CLASS in schema and not eq_or_in(
|
|
node.node_specific, schema[const.DISC_SPECIFIC_DEVICE_CLASS]
|
|
):
|
|
return False
|
|
return True
|
|
|
|
|
|
def check_value_schema(value, schema):
|
|
"""Check if the value matches the passed value schema."""
|
|
if const.DISC_COMMAND_CLASS in schema and not eq_or_in(
|
|
value.parent.command_class_id, schema[const.DISC_COMMAND_CLASS]
|
|
):
|
|
return False
|
|
if const.DISC_TYPE in schema and not eq_or_in(value.type, schema[const.DISC_TYPE]):
|
|
return False
|
|
if const.DISC_GENRE in schema and not eq_or_in(
|
|
value.genre, schema[const.DISC_GENRE]
|
|
):
|
|
return False
|
|
if const.DISC_INDEX in schema and not eq_or_in(
|
|
value.index, schema[const.DISC_INDEX]
|
|
):
|
|
return False
|
|
if const.DISC_INSTANCE in schema and not eq_or_in(
|
|
value.instance, schema[const.DISC_INSTANCE]
|
|
):
|
|
return False
|
|
if const.DISC_SCHEMAS in schema:
|
|
found = False
|
|
for schema_item in schema[const.DISC_SCHEMAS]:
|
|
found = found or check_value_schema(value, schema_item)
|
|
if not found:
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
def eq_or_in(val, options):
|
|
"""Return True if options contains value or if value is equal to options."""
|
|
return val in options if isinstance(options, tuple) else val == options
|