Add support for Aranet2 devices (#101495)

This commit is contained in:
Shay Levy 2023-10-06 11:26:18 +03:00 committed by GitHub
parent fa90b0f41e
commit b97ec2cfce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 85 additions and 36 deletions

View File

@ -19,5 +19,5 @@
"documentation": "https://www.home-assistant.io/integrations/aranet", "documentation": "https://www.home-assistant.io/integrations/aranet",
"integration_type": "device", "integration_type": "device",
"iot_class": "local_push", "iot_class": "local_push",
"requirements": ["aranet4==2.1.3"] "requirements": ["aranet4==2.2.2"]
} }

View File

@ -2,6 +2,7 @@
from __future__ import annotations from __future__ import annotations
from dataclasses import dataclass from dataclasses import dataclass
from typing import Any
from aranet4.client import Aranet4Advertisement from aranet4.client import Aranet4Advertisement
from bleak.backends.device import BLEDevice from bleak.backends.device import BLEDevice
@ -32,6 +33,7 @@ from homeassistant.const import (
) )
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceInfo from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity import EntityDescription
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DOMAIN from .const import DOMAIN
@ -121,22 +123,22 @@ def sensor_update_to_bluetooth_data_update(
adv: Aranet4Advertisement, adv: Aranet4Advertisement,
) -> PassiveBluetoothDataUpdate: ) -> PassiveBluetoothDataUpdate:
"""Convert a sensor update to a Bluetooth data update.""" """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( return PassiveBluetoothDataUpdate(
devices={adv.device.address: _sensor_device_info_to_hass(adv)}, devices={adv.device.address: _sensor_device_info_to_hass(adv)},
entity_descriptions={ entity_descriptions=descs,
_device_key_to_bluetooth_entity_key(adv.device, key): desc entity_data=data,
for key, desc in SENSOR_DESCRIPTIONS.items() entity_names=names,
},
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()
},
) )

View File

@ -435,7 +435,7 @@ aprslib==0.7.0
aqualogic==2.6 aqualogic==2.6
# homeassistant.components.aranet # homeassistant.components.aranet
aranet4==2.1.3 aranet4==2.2.2
# homeassistant.components.arcam_fmj # homeassistant.components.arcam_fmj
arcam-fmj==1.4.0 arcam-fmj==1.4.0

View File

@ -398,7 +398,7 @@ apprise==1.5.0
aprslib==0.7.0 aprslib==0.7.0
# homeassistant.components.aranet # homeassistant.components.aranet
aranet4==2.1.3 aranet4==2.2.2
# homeassistant.components.arcam_fmj # homeassistant.components.arcam_fmj
arcam-fmj==1.4.0 arcam-fmj==1.4.0

View File

@ -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' 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"
},
)

View File

@ -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.const import ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT
from homeassistant.core import HomeAssistant 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.common import MockConfigEntry
from tests.components.bluetooth import inject_bluetooth_service_info 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 hass: HomeAssistant, entity_registry_enabled_by_default: None
) -> 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( entry = MockConfigEntry(
domain=DOMAIN, domain=DOMAIN,
unique_id="aa:bb:cc:dd:ee:ff", 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 assert len(hass.states.async_all("sensor")) == 0
inject_bluetooth_service_info(hass, DISABLED_INTEGRATIONS_SERVICE_INFO) inject_bluetooth_service_info(hass, DISABLED_INTEGRATIONS_SERVICE_INFO)
await hass.async_block_till_done() await hass.async_block_till_done()
assert len(hass.states.async_all("sensor")) == 6 assert len(hass.states.async_all("sensor")) == 0
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 await hass.config_entries.async_unload(entry.entry_id) assert await hass.config_entries.async_unload(entry.entry_id)
await hass.async_block_till_done() await hass.async_block_till_done()