From b97ec2cfce484d56010e61c4b7f03b39f193e654 Mon Sep 17 00:00:00 2001 From: Shay Levy Date: Fri, 6 Oct 2023 11:26:18 +0300 Subject: [PATCH] Add support for Aranet2 devices (#101495) --- homeassistant/components/aranet/manifest.json | 2 +- homeassistant/components/aranet/sensor.py | 30 ++++---- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/aranet/__init__.py | 8 ++ tests/components/aranet/test_sensor.py | 77 ++++++++++++++----- 6 files changed, 85 insertions(+), 36 deletions(-) diff --git a/homeassistant/components/aranet/manifest.json b/homeassistant/components/aranet/manifest.json index 589cdc56e85..0d22a0d1859 100644 --- a/homeassistant/components/aranet/manifest.json +++ b/homeassistant/components/aranet/manifest.json @@ -19,5 +19,5 @@ "documentation": "https://www.home-assistant.io/integrations/aranet", "integration_type": "device", "iot_class": "local_push", - "requirements": ["aranet4==2.1.3"] + "requirements": ["aranet4==2.2.2"] } diff --git a/homeassistant/components/aranet/sensor.py b/homeassistant/components/aranet/sensor.py index b47af54a51f..ad11b4bdbdc 100644 --- a/homeassistant/components/aranet/sensor.py +++ b/homeassistant/components/aranet/sensor.py @@ -2,6 +2,7 @@ from __future__ import annotations from dataclasses import dataclass +from typing import Any from aranet4.client import Aranet4Advertisement from bleak.backends.device import BLEDevice @@ -32,6 +33,7 @@ from homeassistant.const import ( ) from homeassistant.core import HomeAssistant from homeassistant.helpers.device_registry import DeviceInfo +from homeassistant.helpers.entity import EntityDescription from homeassistant.helpers.entity_platform import AddEntitiesCallback from .const import DOMAIN @@ -121,22 +123,22 @@ def sensor_update_to_bluetooth_data_update( adv: Aranet4Advertisement, ) -> PassiveBluetoothDataUpdate: """Convert a sensor update to a Bluetooth data update.""" + data: dict[PassiveBluetoothEntityKey, Any] = {} + names: dict[PassiveBluetoothEntityKey, str | None] = {} + descs: dict[PassiveBluetoothEntityKey, EntityDescription] = {} + for key, desc in SENSOR_DESCRIPTIONS.items(): + tag = _device_key_to_bluetooth_entity_key(adv.device, key) + val = getattr(adv.readings, key) + if val == -1: + continue + data[tag] = val + names[tag] = desc.name + descs[tag] = desc return PassiveBluetoothDataUpdate( devices={adv.device.address: _sensor_device_info_to_hass(adv)}, - entity_descriptions={ - _device_key_to_bluetooth_entity_key(adv.device, key): desc - for key, desc in SENSOR_DESCRIPTIONS.items() - }, - entity_data={ - _device_key_to_bluetooth_entity_key(adv.device, key): getattr( - adv.readings, key, None - ) - for key in SENSOR_DESCRIPTIONS - }, - entity_names={ - _device_key_to_bluetooth_entity_key(adv.device, key): desc.name - for key, desc in SENSOR_DESCRIPTIONS.items() - }, + entity_descriptions=descs, + entity_data=data, + entity_names=names, ) diff --git a/requirements_all.txt b/requirements_all.txt index c4a0d14dae7..37d5b012372 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -435,7 +435,7 @@ aprslib==0.7.0 aqualogic==2.6 # homeassistant.components.aranet -aranet4==2.1.3 +aranet4==2.2.2 # homeassistant.components.arcam_fmj arcam-fmj==1.4.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 30dcc0ba712..692fd0b161d 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -398,7 +398,7 @@ apprise==1.5.0 aprslib==0.7.0 # homeassistant.components.aranet -aranet4==2.1.3 +aranet4==2.2.2 # homeassistant.components.arcam_fmj arcam-fmj==1.4.0 diff --git a/tests/components/aranet/__init__.py b/tests/components/aranet/__init__.py index c85748abea4..b559743067d 100644 --- a/tests/components/aranet/__init__.py +++ b/tests/components/aranet/__init__.py @@ -57,3 +57,11 @@ VALID_DATA_SERVICE_INFO = fake_service_info( 1794: b'\x21\x00\x02\x01\x00\x00\x00\x01\x8a\x02\xa5\x01\xb1&"Y\x01,\x01\xe8\x00\x88' }, ) + +VALID_ARANET2_DATA_SERVICE_INFO = fake_service_info( + "Aranet2 12345", + "0000fce0-0000-1000-8000-00805f9b34fb", + { + 1794: b"\x01!\x04\x04\x01\x00\x00\x00\x00\x00\xf0\x01\x00\x00\x0c\x02\x00O\x00<\x00\x01\x00\x80" + }, +) diff --git a/tests/components/aranet/test_sensor.py b/tests/components/aranet/test_sensor.py index 7d531bf6111..0b2b4771069 100644 --- a/tests/components/aranet/test_sensor.py +++ b/tests/components/aranet/test_sensor.py @@ -4,16 +4,70 @@ from homeassistant.components.sensor import ATTR_STATE_CLASS from homeassistant.const import ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT from homeassistant.core import HomeAssistant -from . import DISABLED_INTEGRATIONS_SERVICE_INFO, VALID_DATA_SERVICE_INFO +from . import ( + DISABLED_INTEGRATIONS_SERVICE_INFO, + VALID_ARANET2_DATA_SERVICE_INFO, + VALID_DATA_SERVICE_INFO, +) from tests.common import MockConfigEntry from tests.components.bluetooth import inject_bluetooth_service_info -async def test_sensors( +async def test_sensors_aranet2( hass: HomeAssistant, entity_registry_enabled_by_default: None ) -> None: - """Test setting up creates the sensors.""" + """Test setting up creates the sensors for Aranet2 device.""" + entry = MockConfigEntry( + domain=DOMAIN, + unique_id="aa:bb:cc:dd:ee:ff", + ) + entry.add_to_hass(hass) + + assert await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + assert len(hass.states.async_all("sensor")) == 0 + inject_bluetooth_service_info(hass, VALID_ARANET2_DATA_SERVICE_INFO) + await hass.async_block_till_done() + assert len(hass.states.async_all("sensor")) == 4 + + batt_sensor = hass.states.get("sensor.aranet2_12345_battery") + batt_sensor_attrs = batt_sensor.attributes + assert batt_sensor.state == "79" + assert batt_sensor_attrs[ATTR_FRIENDLY_NAME] == "Aranet2 12345 Battery" + assert batt_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "%" + assert batt_sensor_attrs[ATTR_STATE_CLASS] == "measurement" + + humid_sensor = hass.states.get("sensor.aranet2_12345_humidity") + humid_sensor_attrs = humid_sensor.attributes + assert humid_sensor.state == "52.4" + assert humid_sensor_attrs[ATTR_FRIENDLY_NAME] == "Aranet2 12345 Humidity" + assert humid_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "%" + assert humid_sensor_attrs[ATTR_STATE_CLASS] == "measurement" + + temp_sensor = hass.states.get("sensor.aranet2_12345_temperature") + temp_sensor_attrs = temp_sensor.attributes + assert temp_sensor.state == "24.8" + assert temp_sensor_attrs[ATTR_FRIENDLY_NAME] == "Aranet2 12345 Temperature" + assert temp_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "°C" + assert temp_sensor_attrs[ATTR_STATE_CLASS] == "measurement" + + interval_sensor = hass.states.get("sensor.aranet2_12345_update_interval") + interval_sensor_attrs = interval_sensor.attributes + assert interval_sensor.state == "60" + assert interval_sensor_attrs[ATTR_FRIENDLY_NAME] == "Aranet2 12345 Update Interval" + assert interval_sensor_attrs[ATTR_UNIT_OF_MEASUREMENT] == "s" + assert interval_sensor_attrs[ATTR_STATE_CLASS] == "measurement" + + assert await hass.config_entries.async_unload(entry.entry_id) + await hass.async_block_till_done() + + +async def test_sensors_aranet4( + hass: HomeAssistant, entity_registry_enabled_by_default: None +) -> None: + """Test setting up creates the sensors for Aranet4 device.""" entry = MockConfigEntry( domain=DOMAIN, unique_id="aa:bb:cc:dd:ee:ff", @@ -90,22 +144,7 @@ async def test_smart_home_integration_disabled( assert len(hass.states.async_all("sensor")) == 0 inject_bluetooth_service_info(hass, DISABLED_INTEGRATIONS_SERVICE_INFO) await hass.async_block_till_done() - assert len(hass.states.async_all("sensor")) == 6 - - batt_sensor = hass.states.get("sensor.aranet4_12345_battery") - assert batt_sensor.state == "unavailable" - - co2_sensor = hass.states.get("sensor.aranet4_12345_carbon_dioxide") - assert co2_sensor.state == "unavailable" - - humid_sensor = hass.states.get("sensor.aranet4_12345_humidity") - assert humid_sensor.state == "unavailable" - - temp_sensor = hass.states.get("sensor.aranet4_12345_temperature") - assert temp_sensor.state == "unavailable" - - press_sensor = hass.states.get("sensor.aranet4_12345_pressure") - assert press_sensor.state == "unavailable" + assert len(hass.states.async_all("sensor")) == 0 assert await hass.config_entries.async_unload(entry.entry_id) await hass.async_block_till_done()