From ca9ac489389196438f19d1bb1f0339e7f65a8820 Mon Sep 17 00:00:00 2001 From: Brett Date: Sat, 17 Oct 2020 03:12:24 +1000 Subject: [PATCH] Add Binary Sensor Platform to Advantage Air (#41871) * Binary Sensor Platform * Parent Binary Sensor Class * Fix DOMAIN namespace * Use parent class --- .../components/advantage_air/__init__.py | 2 +- .../components/advantage_air/binary_sensor.py | 79 +++++++++++++++++++ .../advantage_air/test_binary_sensor.py | 69 ++++++++++++++++ .../fixtures/advantage_air/getSystemData.json | 8 +- 4 files changed, 153 insertions(+), 5 deletions(-) create mode 100644 homeassistant/components/advantage_air/binary_sensor.py create mode 100644 tests/components/advantage_air/test_binary_sensor.py diff --git a/homeassistant/components/advantage_air/__init__.py b/homeassistant/components/advantage_air/__init__.py index 7eccc4d05c5..cd676728e0d 100644 --- a/homeassistant/components/advantage_air/__init__.py +++ b/homeassistant/components/advantage_air/__init__.py @@ -17,7 +17,7 @@ from homeassistant.helpers.update_coordinator import ( from .const import ADVANTAGE_AIR_RETRY, DOMAIN ADVANTAGE_AIR_SYNC_INTERVAL = 15 -ADVANTAGE_AIR_PLATFORMS = ["climate", "cover"] +ADVANTAGE_AIR_PLATFORMS = ["binary_sensor", "climate", "cover"] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/advantage_air/binary_sensor.py b/homeassistant/components/advantage_air/binary_sensor.py new file mode 100644 index 00000000000..25a1bb8a805 --- /dev/null +++ b/homeassistant/components/advantage_air/binary_sensor.py @@ -0,0 +1,79 @@ +"""Binary Sensor platform for Advantage Air integration.""" + +from homeassistant.components.advantage_air import AdvantageAirEntity +from homeassistant.components.binary_sensor import ( + DEVICE_CLASS_MOTION, + DEVICE_CLASS_PROBLEM, + BinarySensorEntity, +) + +from .const import DOMAIN as ADVANTAGE_AIR_DOMAIN + + +async def async_setup_entry(hass, config_entry, async_add_entities): + """Set up AdvantageAir motion platform.""" + + instance = hass.data[ADVANTAGE_AIR_DOMAIN][config_entry.entry_id] + + if "aircons" in instance["coordinator"].data: + entities = [] + for ac_key, ac_device in instance["coordinator"].data["aircons"].items(): + entities.append(AdvantageAirZoneFilter(instance, ac_key)) + for zone_key, zone in ac_device["zones"].items(): + # Only add motion sensor when motion is enabled + if zone["motionConfig"] == 2: + entities.append(AdvantageAirZoneMotion(instance, ac_key, zone_key)) + async_add_entities(entities) + + +class AdvantageAirZoneFilter(AdvantageAirEntity, BinarySensorEntity): + """AdvantageAir Filter.""" + + @property + def name(self): + """Return the name.""" + return f'{self._ac["name"]} Filter' + + @property + def unique_id(self): + """Return a unique id.""" + return f'{self.coordinator.data["system"]["rid"]}-{self.ac_key}-filter' + + @property + def device_class(self): + """Return the device class of the vent.""" + return DEVICE_CLASS_PROBLEM + + @property + def is_on(self): + """Return if filter needs cleaning.""" + return self._ac["filterCleanStatus"] + + +class AdvantageAirZoneMotion(AdvantageAirEntity, BinarySensorEntity): + """AdvantageAir Zone Motion.""" + + @property + def name(self): + """Return the name.""" + return f'{self._zone["name"]} Motion' + + @property + def unique_id(self): + """Return a unique id.""" + return f'{self.coordinator.data["system"]["rid"]}-{self.ac_key}-{self.zone_key}-motion' + + @property + def device_class(self): + """Return the device class of the vent.""" + return DEVICE_CLASS_MOTION + + @property + def is_on(self): + """Return if motion is detect.""" + return self._zone["motion"] + + @property + def device_state_attributes(self): + """Return additional motion configuration.""" + return {"motionConfig": self._zone["motionConfig"]} diff --git a/tests/components/advantage_air/test_binary_sensor.py b/tests/components/advantage_air/test_binary_sensor.py new file mode 100644 index 00000000000..d0b1a90aaad --- /dev/null +++ b/tests/components/advantage_air/test_binary_sensor.py @@ -0,0 +1,69 @@ +"""Test the Advantage Air Binary Sensor Platform.""" + +from homeassistant.const import STATE_OFF, STATE_ON + +from tests.components.advantage_air import ( + TEST_SET_RESPONSE, + TEST_SET_URL, + TEST_SYSTEM_DATA, + TEST_SYSTEM_URL, + add_mock_config, +) + + +async def test_binary_sensor_async_setup_entry(hass, aioclient_mock): + """Test binary sensor setup.""" + + aioclient_mock.get( + TEST_SYSTEM_URL, + text=TEST_SYSTEM_DATA, + ) + aioclient_mock.get( + TEST_SET_URL, + text=TEST_SET_RESPONSE, + ) + await add_mock_config(hass) + + registry = await hass.helpers.entity_registry.async_get_registry() + + assert len(aioclient_mock.mock_calls) == 1 + + # Test First Air Filter + entity_id = "binary_sensor.ac_one_filter" + state = hass.states.get(entity_id) + assert state + assert state.state == STATE_OFF + + entry = registry.async_get(entity_id) + assert entry + assert entry.unique_id == "uniqueid-ac1-filter" + + # Test Second Air Filter + entity_id = "binary_sensor.ac_two_filter" + state = hass.states.get(entity_id) + assert state + assert state.state == STATE_ON + + entry = registry.async_get(entity_id) + assert entry + assert entry.unique_id == "uniqueid-ac2-filter" + + # Test First Motion Sensor + entity_id = "binary_sensor.zone_open_with_sensor_motion" + state = hass.states.get(entity_id) + assert state + assert state.state == STATE_ON + + entry = registry.async_get(entity_id) + assert entry + assert entry.unique_id == "uniqueid-ac1-z01-motion" + + # Test Second Motion Sensor + entity_id = "binary_sensor.zone_closed_with_sensor_motion" + state = hass.states.get(entity_id) + assert state + assert state.state == STATE_OFF + + entry = registry.async_get(entity_id) + assert entry + assert entry.unique_id == "uniqueid-ac1-z02-motion" diff --git a/tests/fixtures/advantage_air/getSystemData.json b/tests/fixtures/advantage_air/getSystemData.json index ebeadaa84b3..fe4de0faed9 100644 --- a/tests/fixtures/advantage_air/getSystemData.json +++ b/tests/fixtures/advantage_air/getSystemData.json @@ -21,7 +21,7 @@ "measuredTemp": 25, "minDamper": 0, "motion": 1, - "motionConfig": 1, + "motionConfig": 2, "name": "Zone open with Sensor", "number": 1, "rssi": -50, @@ -35,8 +35,8 @@ "maxDamper": 100, "measuredTemp": 25, "minDamper": 0, - "motion": 1, - "motionConfig": 1, + "motion": 0, + "motionConfig": 2, "name": "Zone closed with Sensor", "number": 1, "rssi": -50, @@ -53,7 +53,7 @@ "countDownToOff": 0, "countDownToOn": 0, "fan": "low", - "filterCleanStatus": 0, + "filterCleanStatus": 1, "freshAirStatus": "none", "mode": "cool", "myZone": 1,