Rename zwave_mqtt to ozw (#35631)
This commit is contained in:
parent
626f72b97a
commit
0be20ec6ab
54 changed files with 67 additions and 78 deletions
405
homeassistant/components/ozw/binary_sensor.py
Normal file
405
homeassistant/components/ozw/binary_sensor.py
Normal file
|
@ -0,0 +1,405 @@
|
|||
"""Representation of Z-Wave binary_sensors."""
|
||||
|
||||
import logging
|
||||
|
||||
from openzwavemqtt.const import CommandClass, ValueIndex, ValueType
|
||||
|
||||
from homeassistant.components.binary_sensor import (
|
||||
DEVICE_CLASS_DOOR,
|
||||
DEVICE_CLASS_GAS,
|
||||
DEVICE_CLASS_HEAT,
|
||||
DEVICE_CLASS_LOCK,
|
||||
DEVICE_CLASS_MOISTURE,
|
||||
DEVICE_CLASS_MOTION,
|
||||
DEVICE_CLASS_POWER,
|
||||
DEVICE_CLASS_PROBLEM,
|
||||
DEVICE_CLASS_SAFETY,
|
||||
DEVICE_CLASS_SMOKE,
|
||||
DEVICE_CLASS_SOUND,
|
||||
DOMAIN as BINARY_SENSOR_DOMAIN,
|
||||
BinarySensorEntity,
|
||||
)
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
|
||||
from .const import DATA_UNSUBSCRIBE, DOMAIN
|
||||
from .entity import ZWaveDeviceEntity
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
NOTIFICATION_TYPE = "index"
|
||||
NOTIFICATION_VALUES = "values"
|
||||
NOTIFICATION_DEVICE_CLASS = "device_class"
|
||||
NOTIFICATION_SENSOR_ENABLED = "enabled"
|
||||
NOTIFICATION_OFF_VALUE = "off_value"
|
||||
|
||||
NOTIFICATION_VALUE_CLEAR = 0
|
||||
|
||||
# Translation from values in Notification CC to binary sensors
|
||||
# https://github.com/OpenZWave/open-zwave/blob/master/config/NotificationCCTypes.xml
|
||||
NOTIFICATION_SENSORS = [
|
||||
{
|
||||
# Index 1: Smoke Alarm - Value Id's 1 and 2
|
||||
# Assuming here that Value 1 and 2 are not present at the same time
|
||||
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_SMOKE_ALARM,
|
||||
NOTIFICATION_VALUES: [1, 2],
|
||||
NOTIFICATION_DEVICE_CLASS: DEVICE_CLASS_SMOKE,
|
||||
},
|
||||
{
|
||||
# Index 1: Smoke Alarm - All other Value Id's
|
||||
# Create as disabled sensors
|
||||
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_SMOKE_ALARM,
|
||||
NOTIFICATION_VALUES: [3, 4, 5, 6, 7, 8],
|
||||
NOTIFICATION_DEVICE_CLASS: DEVICE_CLASS_SMOKE,
|
||||
NOTIFICATION_SENSOR_ENABLED: False,
|
||||
},
|
||||
{
|
||||
# Index 2: Carbon Monoxide - Value Id's 1 and 2
|
||||
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_CARBON_MONOOXIDE,
|
||||
NOTIFICATION_VALUES: [1, 2],
|
||||
NOTIFICATION_DEVICE_CLASS: DEVICE_CLASS_GAS,
|
||||
},
|
||||
{
|
||||
# Index 2: Carbon Monoxide - All other Value Id's
|
||||
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_CARBON_MONOOXIDE,
|
||||
NOTIFICATION_VALUES: [4, 5, 7],
|
||||
NOTIFICATION_DEVICE_CLASS: DEVICE_CLASS_GAS,
|
||||
NOTIFICATION_SENSOR_ENABLED: False,
|
||||
},
|
||||
{
|
||||
# Index 3: Carbon Dioxide - Value Id's 1 and 2
|
||||
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_CARBON_DIOXIDE,
|
||||
NOTIFICATION_VALUES: [1, 2],
|
||||
NOTIFICATION_DEVICE_CLASS: DEVICE_CLASS_GAS,
|
||||
},
|
||||
{
|
||||
# Index 3: Carbon Dioxide - All other Value Id's
|
||||
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_CARBON_DIOXIDE,
|
||||
NOTIFICATION_VALUES: [4, 5, 7],
|
||||
NOTIFICATION_DEVICE_CLASS: DEVICE_CLASS_GAS,
|
||||
NOTIFICATION_SENSOR_ENABLED: False,
|
||||
},
|
||||
{
|
||||
# Index 4: Heat - Value Id's 1, 2, 5, 6 (heat/underheat)
|
||||
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_HEAT,
|
||||
NOTIFICATION_VALUES: [1, 2, 5, 6],
|
||||
NOTIFICATION_DEVICE_CLASS: DEVICE_CLASS_HEAT,
|
||||
},
|
||||
{
|
||||
# Index 4: Heat - All other Value Id's
|
||||
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_HEAT,
|
||||
NOTIFICATION_VALUES: [3, 4, 8, 10, 11],
|
||||
NOTIFICATION_DEVICE_CLASS: DEVICE_CLASS_HEAT,
|
||||
NOTIFICATION_SENSOR_ENABLED: False,
|
||||
},
|
||||
{
|
||||
# Index 5: Water - Value Id's 1, 2, 3, 4
|
||||
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_WATER,
|
||||
NOTIFICATION_VALUES: [1, 2, 3, 4],
|
||||
NOTIFICATION_DEVICE_CLASS: DEVICE_CLASS_MOISTURE,
|
||||
},
|
||||
{
|
||||
# Index 5: Water - All other Value Id's
|
||||
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_WATER,
|
||||
NOTIFICATION_VALUES: [5],
|
||||
NOTIFICATION_DEVICE_CLASS: DEVICE_CLASS_MOISTURE,
|
||||
NOTIFICATION_SENSOR_ENABLED: False,
|
||||
},
|
||||
{
|
||||
# Index 6: Access Control - Value Id's 1, 2, 3, 4 (Lock)
|
||||
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_ACCESS_CONTROL,
|
||||
NOTIFICATION_VALUES: [1, 2, 3, 4],
|
||||
NOTIFICATION_DEVICE_CLASS: DEVICE_CLASS_LOCK,
|
||||
},
|
||||
{
|
||||
# Index 6: Access Control - Value Id 22 (door/window open)
|
||||
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_ACCESS_CONTROL,
|
||||
NOTIFICATION_VALUES: [22],
|
||||
NOTIFICATION_DEVICE_CLASS: DEVICE_CLASS_DOOR,
|
||||
NOTIFICATION_OFF_VALUE: 23,
|
||||
},
|
||||
{
|
||||
# Index 7: Home Security - Value Id's 1, 2 (intrusion)
|
||||
# Assuming that value 1 and 2 are not present at the same time
|
||||
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_HOME_SECURITY,
|
||||
NOTIFICATION_VALUES: [1, 2],
|
||||
NOTIFICATION_DEVICE_CLASS: DEVICE_CLASS_SAFETY,
|
||||
},
|
||||
{
|
||||
# Index 7: Home Security - Value Id's 3, 4, 9 (tampering)
|
||||
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_HOME_SECURITY,
|
||||
NOTIFICATION_VALUES: [3, 4, 9],
|
||||
NOTIFICATION_DEVICE_CLASS: DEVICE_CLASS_SAFETY,
|
||||
},
|
||||
{
|
||||
# Index 7: Home Security - Value Id's 5, 6 (glass breakage)
|
||||
# Assuming that value 5 and 6 are not present at the same time
|
||||
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_HOME_SECURITY,
|
||||
NOTIFICATION_VALUES: [5, 6],
|
||||
NOTIFICATION_DEVICE_CLASS: DEVICE_CLASS_SAFETY,
|
||||
},
|
||||
{
|
||||
# Index 7: Home Security - Value Id's 7, 8 (motion)
|
||||
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_HOME_SECURITY,
|
||||
NOTIFICATION_VALUES: [7, 8],
|
||||
NOTIFICATION_DEVICE_CLASS: DEVICE_CLASS_MOTION,
|
||||
},
|
||||
{
|
||||
# Index 8: Power management - Values 1...9
|
||||
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_POWER_MANAGEMENT,
|
||||
NOTIFICATION_VALUES: [1, 2, 3, 4, 5, 6, 7, 8, 9],
|
||||
NOTIFICATION_DEVICE_CLASS: DEVICE_CLASS_POWER,
|
||||
NOTIFICATION_SENSOR_ENABLED: False,
|
||||
},
|
||||
{
|
||||
# Index 8: Power management - Values 10...15
|
||||
# Battery values (mutually exclusive)
|
||||
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_POWER_MANAGEMENT,
|
||||
NOTIFICATION_VALUES: [10, 11, 12, 13, 14, 15],
|
||||
NOTIFICATION_DEVICE_CLASS: DEVICE_CLASS_POWER,
|
||||
NOTIFICATION_SENSOR_ENABLED: False,
|
||||
NOTIFICATION_OFF_VALUE: None,
|
||||
},
|
||||
{
|
||||
# Index 9: System - Value Id's 1, 2, 6, 7
|
||||
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_SYSTEM,
|
||||
NOTIFICATION_VALUES: [1, 2, 6, 7],
|
||||
NOTIFICATION_DEVICE_CLASS: DEVICE_CLASS_PROBLEM,
|
||||
NOTIFICATION_SENSOR_ENABLED: False,
|
||||
},
|
||||
{
|
||||
# Index 10: Emergency - Value Id's 1, 2, 3
|
||||
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_EMERGENCY,
|
||||
NOTIFICATION_VALUES: [1, 2, 3],
|
||||
NOTIFICATION_DEVICE_CLASS: DEVICE_CLASS_PROBLEM,
|
||||
},
|
||||
{
|
||||
# Index 11: Clock - Value Id's 1, 2
|
||||
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_CLOCK,
|
||||
NOTIFICATION_VALUES: [1, 2],
|
||||
NOTIFICATION_DEVICE_CLASS: None,
|
||||
NOTIFICATION_SENSOR_ENABLED: False,
|
||||
},
|
||||
{
|
||||
# Index 12: Appliance - All Value Id's
|
||||
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_APPLIANCE,
|
||||
NOTIFICATION_VALUES: [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
],
|
||||
NOTIFICATION_DEVICE_CLASS: None,
|
||||
},
|
||||
{
|
||||
# Index 13: Home Health - Value Id's 1,2,3,4,5
|
||||
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_APPLIANCE,
|
||||
NOTIFICATION_VALUES: [1, 2, 3, 4, 5],
|
||||
NOTIFICATION_DEVICE_CLASS: None,
|
||||
},
|
||||
{
|
||||
# Index 14: Siren
|
||||
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_SIREN,
|
||||
NOTIFICATION_VALUES: [1],
|
||||
NOTIFICATION_DEVICE_CLASS: DEVICE_CLASS_SOUND,
|
||||
},
|
||||
{
|
||||
# Index 15: Water valve
|
||||
# ignore non-boolean values
|
||||
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_WATER_VALVE,
|
||||
NOTIFICATION_VALUES: [3, 4],
|
||||
NOTIFICATION_DEVICE_CLASS: DEVICE_CLASS_PROBLEM,
|
||||
},
|
||||
{
|
||||
# Index 16: Weather
|
||||
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_WEATHER,
|
||||
NOTIFICATION_VALUES: [1, 2],
|
||||
NOTIFICATION_DEVICE_CLASS: DEVICE_CLASS_PROBLEM,
|
||||
},
|
||||
{
|
||||
# Index 17: Irrigation
|
||||
# ignore non-boolean values
|
||||
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_IRRIGATION,
|
||||
NOTIFICATION_VALUES: [1, 2, 3, 4, 5],
|
||||
NOTIFICATION_DEVICE_CLASS: None,
|
||||
},
|
||||
{
|
||||
# Index 18: Gas
|
||||
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_GAS,
|
||||
NOTIFICATION_VALUES: [1, 2, 3, 4],
|
||||
NOTIFICATION_DEVICE_CLASS: DEVICE_CLASS_GAS,
|
||||
},
|
||||
{
|
||||
# Index 18: Gas
|
||||
NOTIFICATION_TYPE: ValueIndex.NOTIFICATION_GAS,
|
||||
NOTIFICATION_VALUES: [6],
|
||||
NOTIFICATION_DEVICE_CLASS: DEVICE_CLASS_PROBLEM,
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
"""Set up Z-Wave binary_sensor from config entry."""
|
||||
|
||||
@callback
|
||||
def async_add_binary_sensor(values):
|
||||
"""Add Z-Wave Binary Sensor(s)."""
|
||||
async_add_entities(VALUE_TYPE_SENSORS[values.primary.type](values))
|
||||
|
||||
hass.data[DOMAIN][config_entry.entry_id][DATA_UNSUBSCRIBE].append(
|
||||
async_dispatcher_connect(
|
||||
hass, f"{DOMAIN}_new_{BINARY_SENSOR_DOMAIN}", async_add_binary_sensor
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@callback
|
||||
def async_get_legacy_binary_sensors(values):
|
||||
"""Add Legacy/classic Z-Wave Binary Sensor."""
|
||||
return [ZWaveBinarySensor(values)]
|
||||
|
||||
|
||||
@callback
|
||||
def async_get_notification_sensors(values):
|
||||
"""Convert Notification values into binary sensors."""
|
||||
sensors_to_add = []
|
||||
for list_value in values.primary.value["List"]:
|
||||
# check if we have a mapping for this value
|
||||
for item in NOTIFICATION_SENSORS:
|
||||
if item[NOTIFICATION_TYPE] != values.primary.index:
|
||||
continue
|
||||
if list_value["Value"] not in item[NOTIFICATION_VALUES]:
|
||||
continue
|
||||
sensors_to_add.append(
|
||||
ZWaveListValueSensor(
|
||||
# required values
|
||||
values,
|
||||
list_value["Value"],
|
||||
item[NOTIFICATION_DEVICE_CLASS],
|
||||
# optional values
|
||||
item.get(NOTIFICATION_SENSOR_ENABLED, True),
|
||||
item.get(NOTIFICATION_OFF_VALUE, NOTIFICATION_VALUE_CLEAR),
|
||||
)
|
||||
)
|
||||
return sensors_to_add
|
||||
|
||||
|
||||
VALUE_TYPE_SENSORS = {
|
||||
ValueType.BOOL: async_get_legacy_binary_sensors,
|
||||
ValueType.LIST: async_get_notification_sensors,
|
||||
}
|
||||
|
||||
|
||||
class ZWaveBinarySensor(ZWaveDeviceEntity, BinarySensorEntity):
|
||||
"""Representation of a Z-Wave binary_sensor."""
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return if the sensor is on or off."""
|
||||
return self.values.primary.value
|
||||
|
||||
@property
|
||||
def entity_registry_enabled_default(self) -> bool:
|
||||
"""Return if the entity should be enabled when first added to the entity registry."""
|
||||
# Legacy binary sensors are phased out (replaced by notification sensors)
|
||||
# Disable by default to not confuse users
|
||||
for item in self.values.primary.node.values():
|
||||
if item.command_class == CommandClass.NOTIFICATION:
|
||||
# This device properly implements the Notification CC, legacy sensor can be disabled
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
class ZWaveListValueSensor(ZWaveDeviceEntity, BinarySensorEntity):
|
||||
"""Representation of a binary_sensor from values in the Z-Wave Notification CommandClass."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
values,
|
||||
on_value,
|
||||
device_class=None,
|
||||
default_enabled=True,
|
||||
off_value=NOTIFICATION_VALUE_CLEAR,
|
||||
):
|
||||
"""Initialize a ZWaveListValueSensor entity."""
|
||||
super().__init__(values)
|
||||
self._on_value = on_value
|
||||
self._device_class = device_class
|
||||
self._default_enabled = default_enabled
|
||||
self._off_value = off_value
|
||||
# make sure the correct value is selected at startup
|
||||
self._state = False
|
||||
self.on_value_update()
|
||||
|
||||
@callback
|
||||
def on_value_update(self):
|
||||
"""Call when a value is added/updated in the underlying EntityValues Collection."""
|
||||
if self.values.primary.value["Selected_id"] == self._on_value:
|
||||
# Only when the active ID exactly matches our watched ON value, set sensor state to ON
|
||||
self._state = True
|
||||
elif self.values.primary.value["Selected_id"] == self._off_value:
|
||||
# Only when the active ID exactly matches our watched OFF value, set sensor state to OFF
|
||||
self._state = False
|
||||
elif (
|
||||
self._off_value is None
|
||||
and self.values.primary.value["Selected_id"] != self._on_value
|
||||
):
|
||||
# Off value not explicitly specified
|
||||
# Some values are reset by the simple fact they're overruled by another value coming in
|
||||
# For example the battery charging values in Power Management Index
|
||||
self._state = False
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the entity."""
|
||||
# Append value label to base name
|
||||
base_name = super().name
|
||||
value_label = ""
|
||||
for item in self.values.primary.value["List"]:
|
||||
if item["Value"] == self._on_value:
|
||||
value_label = item["Label"]
|
||||
break
|
||||
# Strip "on location" / "at location" from name
|
||||
# Note: We're assuming that we don't retrieve 2 values with different location
|
||||
value_label = value_label.split(" on ")[0]
|
||||
value_label = value_label.split(" at ")[0]
|
||||
return f"{base_name}: {value_label}"
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
"""Return the unique_id of the entity."""
|
||||
unique_id = super().unique_id
|
||||
return f"{unique_id}.{self._on_value}"
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return if the sensor is on or off."""
|
||||
return self._state
|
||||
|
||||
@property
|
||||
def device_class(self):
|
||||
"""Return the class of this device, from component DEVICE_CLASSES."""
|
||||
return self._device_class
|
||||
|
||||
@property
|
||||
def entity_registry_enabled_default(self) -> bool:
|
||||
"""Return if the entity should be enabled when first added to the entity registry."""
|
||||
# We hide the more advanced sensors by default to not overwhelm users
|
||||
return self._default_enabled
|
Loading…
Add table
Add a link
Reference in a new issue