Remove binary sensors for ZHA remotes and controllers (#24370)

* remove remote binary sensor profiles
* fix contact sensors
This commit is contained in:
David F. Mulcahey 2019-06-07 11:13:55 -04:00 committed by Alexei Chetroi
parent a79224aba8
commit 592d30d495
3 changed files with 21 additions and 123 deletions

View File

@ -1,27 +1,31 @@
"""Binary sensors on Zigbee Home Automation networks.""" """Binary sensors on Zigbee Home Automation networks."""
import logging import logging
from homeassistant.components.binary_sensor import DOMAIN, BinarySensorDevice from homeassistant.components.binary_sensor import (
DOMAIN, BinarySensorDevice, DEVICE_CLASS_MOVING, DEVICE_CLASS_MOTION,
DEVICE_CLASS_OPENING, DEVICE_CLASS_MOISTURE, DEVICE_CLASS_SMOKE,
DEVICE_CLASS_GAS, DEVICE_CLASS_VIBRATION, DEVICE_CLASS_OCCUPANCY
)
from homeassistant.const import STATE_ON from homeassistant.const import STATE_ON
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.dispatcher import async_dispatcher_connect
from .core.const import ( from .core.const import (
DATA_ZHA, DATA_ZHA_DISPATCHERS, ZHA_DISCOVERY_NEW, ON_OFF_CHANNEL, DATA_ZHA, DATA_ZHA_DISPATCHERS, ZHA_DISCOVERY_NEW, ON_OFF_CHANNEL,
LEVEL_CHANNEL, ZONE_CHANNEL, SIGNAL_ATTR_UPDATED, SIGNAL_MOVE_LEVEL, ZONE_CHANNEL, SIGNAL_ATTR_UPDATED, ATTRIBUTE_CHANNEL, UNKNOWN, OPENING,
SIGNAL_SET_LEVEL, ATTRIBUTE_CHANNEL, UNKNOWN, OPENING, ZONE, OCCUPANCY, ZONE, OCCUPANCY, SENSOR_TYPE, ACCELERATION
ATTR_LEVEL, SENSOR_TYPE, ACCELERATION) )
from .entity import ZhaEntity from .entity import ZhaEntity
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
# Zigbee Cluster Library Zone Type to Home Assistant device class # Zigbee Cluster Library Zone Type to Home Assistant device class
CLASS_MAPPING = { CLASS_MAPPING = {
0x000d: 'motion', 0x000d: DEVICE_CLASS_MOTION,
0x0015: 'opening', 0x0015: DEVICE_CLASS_OPENING,
0x0028: 'smoke', 0x0028: DEVICE_CLASS_SMOKE,
0x002a: 'moisture', 0x002a: DEVICE_CLASS_MOISTURE,
0x002b: 'gas', 0x002b: DEVICE_CLASS_GAS,
0x002d: 'vibration', 0x002d: DEVICE_CLASS_VIBRATION,
} }
@ -33,10 +37,10 @@ async def get_ias_device_class(channel):
DEVICE_CLASS_REGISTRY = { DEVICE_CLASS_REGISTRY = {
UNKNOWN: None, UNKNOWN: None,
OPENING: OPENING, OPENING: DEVICE_CLASS_OPENING,
ZONE: get_ias_device_class, ZONE: get_ias_device_class,
OCCUPANCY: OCCUPANCY, OCCUPANCY: DEVICE_CLASS_OCCUPANCY,
ACCELERATION: 'moving', ACCELERATION: DEVICE_CLASS_MOVING,
} }
@ -85,10 +89,8 @@ class BinarySensor(ZhaEntity, BinarySensorDevice):
self._device_state_attributes = {} self._device_state_attributes = {}
self._zone_channel = self.cluster_channels.get(ZONE_CHANNEL) self._zone_channel = self.cluster_channels.get(ZONE_CHANNEL)
self._on_off_channel = self.cluster_channels.get(ON_OFF_CHANNEL) self._on_off_channel = self.cluster_channels.get(ON_OFF_CHANNEL)
self._level_channel = self.cluster_channels.get(LEVEL_CHANNEL)
self._attr_channel = self.cluster_channels.get(ATTRIBUTE_CHANNEL) self._attr_channel = self.cluster_channels.get(ATTRIBUTE_CHANNEL)
self._zha_sensor_type = kwargs[SENSOR_TYPE] self._zha_sensor_type = kwargs[SENSOR_TYPE]
self._level = None
async def _determine_device_class(self): async def _determine_device_class(self):
"""Determine the device class for this binary sensor.""" """Determine the device class for this binary sensor."""
@ -105,11 +107,6 @@ class BinarySensor(ZhaEntity, BinarySensorDevice):
"""Run when about to be added to hass.""" """Run when about to be added to hass."""
self._device_class = await self._determine_device_class() self._device_class = await self._determine_device_class()
await super().async_added_to_hass() await super().async_added_to_hass()
if self._level_channel:
await self.async_accept_signal(
self._level_channel, SIGNAL_SET_LEVEL, self.set_level)
await self.async_accept_signal(
self._level_channel, SIGNAL_MOVE_LEVEL, self.move_level)
if self._on_off_channel: if self._on_off_channel:
await self.async_accept_signal( await self.async_accept_signal(
self._on_off_channel, SIGNAL_ATTR_UPDATED, self._on_off_channel, SIGNAL_ATTR_UPDATED,
@ -126,8 +123,6 @@ class BinarySensor(ZhaEntity, BinarySensorDevice):
"""Restore previous state.""" """Restore previous state."""
super().async_restore_last_state(last_state) super().async_restore_last_state(last_state)
self._state = last_state.state == STATE_ON self._state = last_state.state == STATE_ON
if 'level' in last_state.attributes:
self._level = last_state.attributes['level']
@property @property
def is_on(self) -> bool: def is_on(self) -> bool:
@ -146,36 +141,9 @@ class BinarySensor(ZhaEntity, BinarySensorDevice):
self._state = bool(state) self._state = bool(state)
self.async_schedule_update_ha_state() self.async_schedule_update_ha_state()
def move_level(self, change):
"""Increment the level, setting state if appropriate."""
level = self._level or 0
if not self._state and change > 0:
level = 0
self._level = min(254, max(0, level + change))
self._state = bool(self._level)
self.async_schedule_update_ha_state()
def set_level(self, level):
"""Set the level, setting state if appropriate."""
self._level = level
self._state = bool(level)
self.async_schedule_update_ha_state()
@property
def device_state_attributes(self):
"""Return the device state attributes."""
if self._level_channel is not None:
self._device_state_attributes.update({
ATTR_LEVEL: self._state and self._level or 0
})
return self._device_state_attributes
async def async_update(self): async def async_update(self):
"""Attempt to retrieve on off state from the binary sensor.""" """Attempt to retrieve on off state from the binary sensor."""
await super().async_update() await super().async_update()
if self._level_channel:
self._level = await self._level_channel.get_attribute_value(
'current_level')
if self._on_off_channel: if self._on_off_channel:
self._state = await self._on_off_channel.get_attribute_value( self._state = await self._on_off_channel.get_attribute_value(
'on_off') 'on_off')

View File

@ -110,17 +110,11 @@ def establish_device_mappings():
BINDABLE_CLUSTERS.append(zcl.clusters.lighting.Color.cluster_id) BINDABLE_CLUSTERS.append(zcl.clusters.lighting.Color.cluster_id)
DEVICE_CLASS[zha.PROFILE_ID].update({ DEVICE_CLASS[zha.PROFILE_ID].update({
zha.DeviceType.ON_OFF_SWITCH: BINARY_SENSOR,
zha.DeviceType.LEVEL_CONTROL_SWITCH: BINARY_SENSOR,
zha.DeviceType.REMOTE_CONTROL: BINARY_SENSOR,
zha.DeviceType.SMART_PLUG: SWITCH, zha.DeviceType.SMART_PLUG: SWITCH,
zha.DeviceType.LEVEL_CONTROLLABLE_OUTPUT: LIGHT, zha.DeviceType.LEVEL_CONTROLLABLE_OUTPUT: LIGHT,
zha.DeviceType.ON_OFF_LIGHT: LIGHT, zha.DeviceType.ON_OFF_LIGHT: LIGHT,
zha.DeviceType.DIMMABLE_LIGHT: LIGHT, zha.DeviceType.DIMMABLE_LIGHT: LIGHT,
zha.DeviceType.COLOR_DIMMABLE_LIGHT: LIGHT, zha.DeviceType.COLOR_DIMMABLE_LIGHT: LIGHT
zha.DeviceType.ON_OFF_LIGHT_SWITCH: BINARY_SENSOR,
zha.DeviceType.DIMMER_SWITCH: BINARY_SENSOR,
zha.DeviceType.COLOR_DIMMER_SWITCH: BINARY_SENSOR,
}) })
DEVICE_CLASS[zll.PROFILE_ID].update({ DEVICE_CLASS[zll.PROFILE_ID].update({
@ -130,12 +124,7 @@ def establish_device_mappings():
zll.DeviceType.DIMMABLE_PLUGIN_UNIT: LIGHT, zll.DeviceType.DIMMABLE_PLUGIN_UNIT: LIGHT,
zll.DeviceType.COLOR_LIGHT: LIGHT, zll.DeviceType.COLOR_LIGHT: LIGHT,
zll.DeviceType.EXTENDED_COLOR_LIGHT: LIGHT, zll.DeviceType.EXTENDED_COLOR_LIGHT: LIGHT,
zll.DeviceType.COLOR_TEMPERATURE_LIGHT: LIGHT, zll.DeviceType.COLOR_TEMPERATURE_LIGHT: LIGHT
zll.DeviceType.COLOR_CONTROLLER: BINARY_SENSOR,
zll.DeviceType.COLOR_SCENE_CONTROLLER: BINARY_SENSOR,
zll.DeviceType.CONTROLLER: BINARY_SENSOR,
zll.DeviceType.SCENE_CONTROLLER: BINARY_SENSOR,
zll.DeviceType.ON_OFF_SENSOR: BINARY_SENSOR,
}) })
SINGLE_INPUT_CLUSTER_DEVICE_CLASS.update({ SINGLE_INPUT_CLUSTER_DEVICE_CLASS.update({
@ -285,7 +274,6 @@ def establish_device_mappings():
}) })
BINARY_SENSOR_CLUSTERS.add(zcl.clusters.general.OnOff.cluster_id) BINARY_SENSOR_CLUSTERS.add(zcl.clusters.general.OnOff.cluster_id)
BINARY_SENSOR_CLUSTERS.add(zcl.clusters.general.LevelControl.cluster_id)
BINARY_SENSOR_CLUSTERS.add(zcl.clusters.security.IasZone.cluster_id) BINARY_SENSOR_CLUSTERS.add(zcl.clusters.security.IasZone.cluster_id)
BINARY_SENSOR_CLUSTERS.add( BINARY_SENSOR_CLUSTERS.add(
zcl.clusters.measurement.OccupancySensing.cluster_id) zcl.clusters.measurement.OccupancySensing.cluster_id)

View File

@ -11,8 +11,7 @@ async def test_binary_sensor(hass, config_entry, zha_gateway):
"""Test zha binary_sensor platform.""" """Test zha binary_sensor platform."""
from zigpy.zcl.clusters.security import IasZone from zigpy.zcl.clusters.security import IasZone
from zigpy.zcl.clusters.measurement import OccupancySensing from zigpy.zcl.clusters.measurement import OccupancySensing
from zigpy.zcl.clusters.general import OnOff, LevelControl, Basic from zigpy.zcl.clusters.general import Basic
from zigpy.profiles.zha import DeviceType
# create zigpy devices # create zigpy devices
zigpy_device_zone = await async_init_zigpy_device( zigpy_device_zone = await async_init_zigpy_device(
@ -23,17 +22,6 @@ async def test_binary_sensor(hass, config_entry, zha_gateway):
zha_gateway zha_gateway
) )
zigpy_device_remote = await async_init_zigpy_device(
hass,
[Basic.cluster_id],
[OnOff.cluster_id, LevelControl.cluster_id],
DeviceType.LEVEL_CONTROL_SWITCH,
zha_gateway,
ieee="00:0d:6f:11:0a:90:69:e7",
manufacturer="FakeManufacturer",
model="FakeRemoteModel"
)
zigpy_device_occupancy = await async_init_zigpy_device( zigpy_device_occupancy = await async_init_zigpy_device(
hass, hass,
[OccupancySensing.cluster_id, Basic.cluster_id], [OccupancySensing.cluster_id, Basic.cluster_id],
@ -63,46 +51,20 @@ async def test_binary_sensor(hass, config_entry, zha_gateway):
DOMAIN, zigpy_device_occupancy, occupancy_cluster) DOMAIN, zigpy_device_occupancy, occupancy_cluster)
occupancy_zha_device = zha_gateway.get_device(zigpy_device_occupancy.ieee) occupancy_zha_device = zha_gateway.get_device(zigpy_device_occupancy.ieee)
# dimmable binary_sensor
remote_on_off_cluster = zigpy_device_remote.endpoints.get(
1).out_clusters[OnOff.cluster_id]
remote_level_cluster = zigpy_device_remote.endpoints.get(
1).out_clusters[LevelControl.cluster_id]
remote_entity_id = make_entity_id(DOMAIN, zigpy_device_remote,
remote_on_off_cluster,
use_suffix=False)
remote_zha_device = zha_gateway.get_device(zigpy_device_remote.ieee)
# test that the sensors exist and are in the unavailable state # test that the sensors exist and are in the unavailable state
assert hass.states.get(zone_entity_id).state == STATE_UNAVAILABLE assert hass.states.get(zone_entity_id).state == STATE_UNAVAILABLE
assert hass.states.get(remote_entity_id).state == STATE_UNAVAILABLE
assert hass.states.get(occupancy_entity_id).state == STATE_UNAVAILABLE assert hass.states.get(occupancy_entity_id).state == STATE_UNAVAILABLE
await async_enable_traffic(hass, zha_gateway, await async_enable_traffic(hass, zha_gateway,
[zone_zha_device, remote_zha_device, [zone_zha_device, occupancy_zha_device])
occupancy_zha_device])
# test that the sensors exist and are in the off state # test that the sensors exist and are in the off state
assert hass.states.get(zone_entity_id).state == STATE_OFF assert hass.states.get(zone_entity_id).state == STATE_OFF
assert hass.states.get(remote_entity_id).state == STATE_OFF
assert hass.states.get(occupancy_entity_id).state == STATE_OFF assert hass.states.get(occupancy_entity_id).state == STATE_OFF
# test getting messages that trigger and reset the sensors # test getting messages that trigger and reset the sensors
await async_test_binary_sensor_on_off(hass, occupancy_cluster, await async_test_binary_sensor_on_off(hass, occupancy_cluster,
occupancy_entity_id) occupancy_entity_id)
await async_test_binary_sensor_on_off(hass, remote_on_off_cluster,
remote_entity_id)
# test changing the level attribute for dimming remotes
await async_test_remote_level(
hass, remote_level_cluster, remote_entity_id, 150, STATE_ON)
await async_test_remote_level(
hass, remote_level_cluster, remote_entity_id, 0, STATE_OFF)
await async_test_remote_level(
hass, remote_level_cluster, remote_entity_id, 255, STATE_ON)
await async_test_remote_move_level(
hass, remote_level_cluster, remote_entity_id, 20, STATE_ON)
# test IASZone binary sensors # test IASZone binary sensors
await async_test_iaszone_on_off(hass, zone_cluster, zone_entity_id) await async_test_iaszone_on_off(hass, zone_cluster, zone_entity_id)
@ -127,26 +89,6 @@ async def async_test_binary_sensor_on_off(hass, cluster, entity_id):
assert hass.states.get(entity_id).state == STATE_OFF assert hass.states.get(entity_id).state == STATE_OFF
async def async_test_remote_level(hass, cluster, entity_id, level,
expected_state):
"""Test dimmer functionality from the remote."""
attr = make_attribute(0, level)
cluster.handle_message(False, 1, 0x0a, [[attr]])
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == expected_state
assert hass.states.get(entity_id).attributes.get('level') == level
async def async_test_remote_move_level(hass, cluster, entity_id, change,
expected_state):
"""Test move to level command."""
level = hass.states.get(entity_id).attributes.get('level')
cluster.listener_event('cluster_command', 1, 1, [1, change])
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == expected_state
assert hass.states.get(entity_id).attributes.get('level') == level - change
async def async_test_iaszone_on_off(hass, cluster, entity_id): async def async_test_iaszone_on_off(hass, cluster, entity_id):
"""Test getting on and off messages for iaszone binary sensors.""" """Test getting on and off messages for iaszone binary sensors."""
# binary sensor on # binary sensor on