From 571b245b7e56e9abe73b4f433041a1a45c35f077 Mon Sep 17 00:00:00 2001 From: Peeter N Date: Fri, 17 Dec 2021 16:02:28 +0200 Subject: [PATCH] Add battery entity for Maxcube devices (#58699) --- .../components/maxcube/binary_sensor.py | 59 ++++++++++++------- tests/components/maxcube/conftest.py | 3 + .../maxcube/test_maxcube_binary_sensor.py | 35 ++++++++++- 3 files changed, 75 insertions(+), 22 deletions(-) diff --git a/homeassistant/components/maxcube/binary_sensor.py b/homeassistant/components/maxcube/binary_sensor.py index 999d7af01c5..f24f56e52d7 100644 --- a/homeassistant/components/maxcube/binary_sensor.py +++ b/homeassistant/components/maxcube/binary_sensor.py @@ -1,8 +1,9 @@ """Support for MAX! binary sensors via MAX! Cube.""" from homeassistant.components.binary_sensor import ( - DEVICE_CLASS_WINDOW, + BinarySensorDeviceClass, BinarySensorEntity, ) +from homeassistant.helpers.entity import EntityCategory from . import DATA_KEY @@ -12,6 +13,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): devices = [] for handler in hass.data[DATA_KEY].values(): for device in handler.cube.devices: + devices.append(MaxCubeBattery(handler, device)) # Only add Window Shutters if device.is_windowshutter(): devices.append(MaxCubeShutter(handler, device)) @@ -20,36 +22,53 @@ def setup_platform(hass, config, add_entities, discovery_info=None): add_entities(devices) -class MaxCubeShutter(BinarySensorEntity): - """Representation of a MAX! Cube Binary Sensor device.""" +class MaxCubeBinarySensorBase(BinarySensorEntity): + """Base class for maxcube binary sensors.""" + + _attr_entity_category = EntityCategory.DIAGNOSTIC def __init__(self, handler, device): """Initialize MAX! Cube BinarySensorEntity.""" - room = handler.cube.room_by_id(device.room_id) - self._name = f"{room.name} {device.name}" self._cubehandle = handler self._device = device + self._room = handler.cube.room_by_id(device.room_id) - @property - def name(self): - """Return the name of the BinarySensorEntity.""" - return self._name + def update(self): + """Get latest data from MAX! Cube.""" + self._cubehandle.update() - @property - def unique_id(self): - """Return a unique ID.""" - return self._device.serial - @property - def device_class(self): - """Return the class of this sensor.""" - return DEVICE_CLASS_WINDOW +class MaxCubeShutter(MaxCubeBinarySensorBase): + """Representation of a MAX! Cube Binary Sensor device.""" + + _attr_device_class = BinarySensorDeviceClass.WINDOW + + def __init__(self, handler, device): + """Initialize MAX! Cube BinarySensorEntity.""" + super().__init__(handler, device) + + self._attr_name = f"{self._room.name} {self._device.name}" + self._attr_unique_id = self._device.serial @property def is_on(self): """Return true if the binary sensor is on/open.""" return self._device.is_open - def update(self): - """Get latest data from MAX! Cube.""" - self._cubehandle.update() + +class MaxCubeBattery(MaxCubeBinarySensorBase): + """Representation of a MAX! Cube Binary Sensor device.""" + + _attr_device_class = BinarySensorDeviceClass.BATTERY + + def __init__(self, handler, device): + """Initialize MAX! Cube BinarySensorEntity.""" + super().__init__(handler, device) + + self._attr_name = f"{self._room.name} {device.name} battery" + self._attr_unique_id = f"{self._device.serial}_battery" + + @property + def is_on(self): + """Return true if the binary sensor is on/open.""" + return self._device.battery == 1 diff --git a/tests/components/maxcube/conftest.py b/tests/components/maxcube/conftest.py index b36072190c4..f0dd12eb6c6 100644 --- a/tests/components/maxcube/conftest.py +++ b/tests/components/maxcube/conftest.py @@ -41,6 +41,7 @@ def thermostat(): t.max_temperature = None t.min_temperature = None t.valve_position = 25 # 25% + t.battery = 1 return t @@ -62,6 +63,7 @@ def wallthermostat(): t.actual_temperature = 19.0 t.max_temperature = 29.0 t.min_temperature = 4.5 + t.battery = 1 return t @@ -77,6 +79,7 @@ def windowshutter(): shutter.is_thermostat.return_value = False shutter.is_wallthermostat.return_value = False shutter.is_windowshutter.return_value = True + shutter.battery = 1 return shutter diff --git a/tests/components/maxcube/test_maxcube_binary_sensor.py b/tests/components/maxcube/test_maxcube_binary_sensor.py index 48d34a0df4e..39e1fb54740 100644 --- a/tests/components/maxcube/test_maxcube_binary_sensor.py +++ b/tests/components/maxcube/test_maxcube_binary_sensor.py @@ -4,7 +4,7 @@ from datetime import timedelta from maxcube.cube import MaxCube from maxcube.windowshutter import MaxWindowShutter -from homeassistant.components.binary_sensor import DEVICE_CLASS_WINDOW +from homeassistant.components.binary_sensor import BinarySensorDeviceClass from homeassistant.const import ( ATTR_DEVICE_CLASS, ATTR_FRIENDLY_NAME, @@ -12,11 +12,13 @@ from homeassistant.const import ( STATE_ON, ) from homeassistant.helpers import entity_registry as er +from homeassistant.helpers.entity import EntityCategory from homeassistant.util import utcnow from tests.common import async_fire_time_changed ENTITY_ID = "binary_sensor.testroom_testshutter" +BATTERY_ENTITY_ID = f"{ENTITY_ID}_battery" async def test_window_shuttler(hass, cube: MaxCube, windowshutter: MaxWindowShutter): @@ -25,12 +27,13 @@ async def test_window_shuttler(hass, cube: MaxCube, windowshutter: MaxWindowShut assert entity_registry.async_is_registered(ENTITY_ID) entity = entity_registry.async_get(ENTITY_ID) assert entity.unique_id == "AABBCCDD03" + assert entity.entity_category == EntityCategory.DIAGNOSTIC state = hass.states.get(ENTITY_ID) assert state is not None assert state.state == STATE_ON assert state.attributes.get(ATTR_FRIENDLY_NAME) == "TestRoom TestShutter" - assert state.attributes.get(ATTR_DEVICE_CLASS) == DEVICE_CLASS_WINDOW + assert state.attributes.get(ATTR_DEVICE_CLASS) == BinarySensorDeviceClass.WINDOW windowshutter.is_open = False async_fire_time_changed(hass, utcnow() + timedelta(minutes=5)) @@ -38,3 +41,31 @@ async def test_window_shuttler(hass, cube: MaxCube, windowshutter: MaxWindowShut state = hass.states.get(ENTITY_ID) assert state.state == STATE_OFF + + +async def test_window_shuttler_battery( + hass, cube: MaxCube, windowshutter: MaxWindowShutter +): + """Test battery binary_state with a shuttler device.""" + entity_registry = er.async_get(hass) + assert entity_registry.async_is_registered(BATTERY_ENTITY_ID) + entity = entity_registry.async_get(BATTERY_ENTITY_ID) + assert entity.unique_id == "AABBCCDD03_battery" + assert entity.entity_category == EntityCategory.DIAGNOSTIC + + state = hass.states.get(BATTERY_ENTITY_ID) + assert state is not None + assert state.attributes.get(ATTR_DEVICE_CLASS) == BinarySensorDeviceClass.BATTERY + assert state.attributes.get(ATTR_FRIENDLY_NAME) == "TestRoom TestShutter battery" + + windowshutter.battery = 1 # maxcube-api MAX_DEVICE_BATTERY_LOW + async_fire_time_changed(hass, utcnow() + timedelta(minutes=5)) + await hass.async_block_till_done() + state = hass.states.get(BATTERY_ENTITY_ID) + assert state.state == STATE_ON # on means low + + windowshutter.battery = 0 # maxcube-api MAX_DEVICE_BATTERY_OK + async_fire_time_changed(hass, utcnow() + timedelta(minutes=5)) + await hass.async_block_till_done() + state = hass.states.get(BATTERY_ENTITY_ID) + assert state.state == STATE_OFF # off means normal