From 7c86ea7e16c0574159c6fbb246929274e2482ac8 Mon Sep 17 00:00:00 2001 From: Jonas Fors Lellky Date: Sun, 21 Jan 2024 12:04:46 +0100 Subject: [PATCH] Add sensors to the flexit_bacnet integration (#108297) * Adds sensors to the flexit_bacnet integration * Add one platform at a time * Removes commented out code And restores attributes that are needed * Review changes * More review fixes * Adds translations for the flexit_bacnet sensors * Review comments * Adds test for flexit_bacnet sensor * Refactors the sensor test * Review comment * Review comment * Review comments --- .../components/flexit_bacnet/__init__.py | 2 +- .../components/flexit_bacnet/sensor.py | 186 +++++ .../components/flexit_bacnet/strings.json | 49 ++ tests/components/flexit_bacnet/conftest.py | 15 + .../flexit_bacnet/snapshots/test_sensor.ambr | 708 ++++++++++++++++++ tests/components/flexit_bacnet/test_sensor.py | 33 + 6 files changed, 992 insertions(+), 1 deletion(-) create mode 100644 homeassistant/components/flexit_bacnet/sensor.py create mode 100644 tests/components/flexit_bacnet/snapshots/test_sensor.ambr create mode 100644 tests/components/flexit_bacnet/test_sensor.py diff --git a/homeassistant/components/flexit_bacnet/__init__.py b/homeassistant/components/flexit_bacnet/__init__.py index 39e06156a59..40537306c0b 100644 --- a/homeassistant/components/flexit_bacnet/__init__.py +++ b/homeassistant/components/flexit_bacnet/__init__.py @@ -8,7 +8,7 @@ from homeassistant.core import HomeAssistant from .const import DOMAIN from .coordinator import FlexitCoordinator -PLATFORMS: list[Platform] = [Platform.CLIMATE] +PLATFORMS: list[Platform] = [Platform.CLIMATE, Platform.SENSOR] async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: diff --git a/homeassistant/components/flexit_bacnet/sensor.py b/homeassistant/components/flexit_bacnet/sensor.py new file mode 100644 index 00000000000..590136ad5f7 --- /dev/null +++ b/homeassistant/components/flexit_bacnet/sensor.py @@ -0,0 +1,186 @@ +"""The Flexit Nordic (BACnet) integration.""" +from collections.abc import Callable +from dataclasses import dataclass + +from flexit_bacnet import FlexitBACnet + +from homeassistant.components.sensor import ( + SensorDeviceClass, + SensorEntity, + SensorEntityDescription, + SensorStateClass, + StateType, +) +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import ( + PERCENTAGE, + REVOLUTIONS_PER_MINUTE, + UnitOfPower, + UnitOfTemperature, + UnitOfTime, +) +from homeassistant.core import HomeAssistant +from homeassistant.helpers.entity_platform import AddEntitiesCallback + +from . import FlexitCoordinator +from .const import DOMAIN +from .entity import FlexitEntity + + +@dataclass(kw_only=True, frozen=True) +class FlexitSensorEntityDescription(SensorEntityDescription): + """Describes a Flexit sensor entity.""" + + value_fn: Callable[[FlexitBACnet], float] + + +SENSOR_TYPES: tuple[FlexitSensorEntityDescription, ...] = ( + FlexitSensorEntityDescription( + key="outside_air_temperature", + device_class=SensorDeviceClass.TEMPERATURE, + native_unit_of_measurement=UnitOfTemperature.CELSIUS, + translation_key="outside_air_temperature", + value_fn=lambda data: data.outside_air_temperature, + ), + FlexitSensorEntityDescription( + key="supply_air_temperature", + device_class=SensorDeviceClass.TEMPERATURE, + native_unit_of_measurement=UnitOfTemperature.CELSIUS, + translation_key="supply_air_temperature", + value_fn=lambda data: data.supply_air_temperature, + ), + FlexitSensorEntityDescription( + key="exhaust_air_temperature", + device_class=SensorDeviceClass.TEMPERATURE, + native_unit_of_measurement=UnitOfTemperature.CELSIUS, + translation_key="exhaust_air_temperature", + value_fn=lambda data: data.exhaust_air_temperature, + ), + FlexitSensorEntityDescription( + key="extract_air_temperature", + device_class=SensorDeviceClass.TEMPERATURE, + native_unit_of_measurement=UnitOfTemperature.CELSIUS, + translation_key="extract_air_temperature", + value_fn=lambda data: data.extract_air_temperature, + ), + FlexitSensorEntityDescription( + key="room_temperature", + device_class=SensorDeviceClass.TEMPERATURE, + native_unit_of_measurement=UnitOfTemperature.CELSIUS, + translation_key="room_temperature", + value_fn=lambda data: data.room_temperature, + ), + FlexitSensorEntityDescription( + key="fireplace_ventilation_remaining_duration", + device_class=SensorDeviceClass.DURATION, + state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement=UnitOfTime.MINUTES, + translation_key="fireplace_ventilation_remaining_duration", + value_fn=lambda data: data.fireplace_ventilation_remaining_duration, + suggested_display_precision=0, + ), + FlexitSensorEntityDescription( + key="rapid_ventilation_remaining_duration", + device_class=SensorDeviceClass.DURATION, + state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement=UnitOfTime.MINUTES, + translation_key="rapid_ventilation_remaining_duration", + value_fn=lambda data: data.rapid_ventilation_remaining_duration, + suggested_display_precision=0, + ), + FlexitSensorEntityDescription( + key="supply_air_fan_control_signal", + state_class=SensorStateClass.MEASUREMENT, + translation_key="supply_air_fan_control_signal", + native_unit_of_measurement=PERCENTAGE, + value_fn=lambda data: data.supply_air_fan_control_signal, + ), + FlexitSensorEntityDescription( + key="supply_air_fan_rpm", + state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement=REVOLUTIONS_PER_MINUTE, + translation_key="supply_air_fan_rpm", + value_fn=lambda data: data.supply_air_fan_rpm, + ), + FlexitSensorEntityDescription( + key="exhaust_air_fan_control_signal", + state_class=SensorStateClass.MEASUREMENT, + translation_key="exhaust_air_fan_control_signal", + value_fn=lambda data: data.exhaust_air_fan_control_signal, + native_unit_of_measurement=PERCENTAGE, + ), + FlexitSensorEntityDescription( + key="exhaust_air_fan_rpm", + state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement=REVOLUTIONS_PER_MINUTE, + translation_key="exhaust_air_fan_rpm", + value_fn=lambda data: data.exhaust_air_fan_rpm, + ), + FlexitSensorEntityDescription( + key="electric_heater_power", + device_class=SensorDeviceClass.POWER, + native_unit_of_measurement=UnitOfPower.KILO_WATT, + translation_key="electric_heater_power", + value_fn=lambda data: data.electric_heater_power, + suggested_display_precision=3, + ), + FlexitSensorEntityDescription( + key="air_filter_operating_time", + state_class=SensorStateClass.TOTAL_INCREASING, + suggested_display_precision=0, + native_unit_of_measurement=UnitOfTime.HOURS, + translation_key="air_filter_operating_time", + value_fn=lambda data: data.air_filter_operating_time, + ), + FlexitSensorEntityDescription( + key="heat_exchanger_efficiency", + state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement=PERCENTAGE, + translation_key="heat_exchanger_efficiency", + value_fn=lambda data: data.heat_exchanger_efficiency, + ), + FlexitSensorEntityDescription( + key="heat_exchanger_speed", + state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement=PERCENTAGE, + translation_key="heat_exchanger_speed", + value_fn=lambda data: data.heat_exchanger_speed, + ), +) + + +async def async_setup_entry( + hass: HomeAssistant, + config_entry: ConfigEntry, + async_add_entities: AddEntitiesCallback, +) -> None: + """Set up Flexit (bacnet) sensor from a config entry.""" + coordinator: FlexitCoordinator = hass.data[DOMAIN][config_entry.entry_id] + + async_add_entities( + FlexitSensor(coordinator, description) for description in SENSOR_TYPES + ) + + +class FlexitSensor(FlexitEntity, SensorEntity): + """Representation of a Flexit (bacnet) Sensor.""" + + entity_description: FlexitSensorEntityDescription + + def __init__( + self, + coordinator: FlexitCoordinator, + entity_description: FlexitSensorEntityDescription, + ) -> None: + """Initialize Flexit (bacnet) sensor.""" + super().__init__(coordinator) + + self.entity_description = entity_description + self._attr_unique_id = ( + f"{coordinator.device.serial_number}-{entity_description.key}" + ) + + @property + def native_value(self) -> StateType: + """Return value of sensor.""" + return self.entity_description.value_fn(self.coordinator.data) diff --git a/homeassistant/components/flexit_bacnet/strings.json b/homeassistant/components/flexit_bacnet/strings.json index fd2725c6403..b9348ebedcd 100644 --- a/homeassistant/components/flexit_bacnet/strings.json +++ b/homeassistant/components/flexit_bacnet/strings.json @@ -15,5 +15,54 @@ "abort": { "already_configured": "[%key:common::config_flow::abort::already_configured_device%]" } + }, + "entity": { + "sensor": { + "outside_air_temperature": { + "name": "Outside air temperature" + }, + "supply_air_temperature": { + "name": "Supply air temperature" + }, + "exhaust_air_temperature": { + "name": "Exhaust air temperature" + }, + "extract_air_temperature": { + "name": "Extract air temperature" + }, + "room_temperature": { + "name": "Room temperature" + }, + "fireplace_ventilation_remaining_duration": { + "name": "Fireplace ventilation remaining duration" + }, + "rapid_ventilation_remaining_duration": { + "name": "Rapid ventilation remaining duration" + }, + "supply_air_fan_control_signal": { + "name": "Supply air fan control signal" + }, + "supply_air_fan_rpm": { + "name": "Supply air fan" + }, + "exhaust_air_fan_control_signal": { + "name": "Exhaust air fan control signal" + }, + "exhaust_air_fan_rpm": { + "name": "Exhaust air fan" + }, + "electric_heater_power": { + "name": "Electric heater power" + }, + "air_filter_operating_time": { + "name": "Air filter operating time" + }, + "heat_exchanger_efficiency": { + "name": "Heat exchanger efficiency" + }, + "heat_exchanger_speed": { + "name": "Heat exchanger speed" + } + } } } diff --git a/tests/components/flexit_bacnet/conftest.py b/tests/components/flexit_bacnet/conftest.py index 0c6153e81c0..6fc715da28e 100644 --- a/tests/components/flexit_bacnet/conftest.py +++ b/tests/components/flexit_bacnet/conftest.py @@ -44,6 +44,21 @@ def mock_flexit_bacnet() -> Generator[AsyncMock, None, None]: flexit_bacnet.air_temp_setpoint_away = 18.0 flexit_bacnet.air_temp_setpoint_home = 22.0 flexit_bacnet.ventilation_mode = 4 + flexit_bacnet.air_filter_operating_time = 8000 + flexit_bacnet.outside_air_temperature = -8.6 + flexit_bacnet.supply_air_temperature = 19.1 + flexit_bacnet.exhaust_air_temperature = -3.3 + flexit_bacnet.extract_air_temperature = 19.0 + flexit_bacnet.fireplace_ventilation_remaining_duration = 10.0 + flexit_bacnet.rapid_ventilation_remaining_duration = 30.0 + flexit_bacnet.supply_air_fan_control_signal = 74 + flexit_bacnet.supply_air_fan_rpm = 2784 + flexit_bacnet.exhaust_air_fan_control_signal = 70 + flexit_bacnet.exhaust_air_fan_rpm = 2606 + flexit_bacnet.electric_heater_power = 0.39636585116386414 + flexit_bacnet.air_filter_operating_time = 8820.0 + flexit_bacnet.heat_exchanger_efficiency = 81 + flexit_bacnet.heat_exchanger_speed = 100 yield flexit_bacnet diff --git a/tests/components/flexit_bacnet/snapshots/test_sensor.ambr b/tests/components/flexit_bacnet/snapshots/test_sensor.ambr new file mode 100644 index 00000000000..c1f8ad73eb1 --- /dev/null +++ b/tests/components/flexit_bacnet/snapshots/test_sensor.ambr @@ -0,0 +1,708 @@ +# serializer version: 1 +# name: test_sensors[sensor.device_name_air_filter_operating_time-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.device_name_air_filter_operating_time', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Air filter operating time', + 'platform': 'flexit_bacnet', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'air_filter_operating_time', + 'unique_id': '0000-0001-air_filter_operating_time', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.device_name_air_filter_operating_time-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Device Name Air filter operating time', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.device_name_air_filter_operating_time', + 'last_changed': , + 'last_updated': , + 'state': '8820.0', + }) +# --- +# name: test_sensors[sensor.device_name_electric_heater_power-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.device_name_electric_heater_power', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 3, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Electric heater power', + 'platform': 'flexit_bacnet', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'electric_heater_power', + 'unique_id': '0000-0001-electric_heater_power', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.device_name_electric_heater_power-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'Device Name Electric heater power', + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.device_name_electric_heater_power', + 'last_changed': , + 'last_updated': , + 'state': '0.396365851163864', + }) +# --- +# name: test_sensors[sensor.device_name_exhaust_air_fan-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.device_name_exhaust_air_fan', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Exhaust air fan', + 'platform': 'flexit_bacnet', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'exhaust_air_fan_rpm', + 'unique_id': '0000-0001-exhaust_air_fan_rpm', + 'unit_of_measurement': 'rpm', + }) +# --- +# name: test_sensors[sensor.device_name_exhaust_air_fan-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Device Name Exhaust air fan', + 'state_class': , + 'unit_of_measurement': 'rpm', + }), + 'context': , + 'entity_id': 'sensor.device_name_exhaust_air_fan', + 'last_changed': , + 'last_updated': , + 'state': '2606', + }) +# --- +# name: test_sensors[sensor.device_name_exhaust_air_fan_control_signal-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.device_name_exhaust_air_fan_control_signal', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Exhaust air fan control signal', + 'platform': 'flexit_bacnet', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'exhaust_air_fan_control_signal', + 'unique_id': '0000-0001-exhaust_air_fan_control_signal', + 'unit_of_measurement': '%', + }) +# --- +# name: test_sensors[sensor.device_name_exhaust_air_fan_control_signal-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Device Name Exhaust air fan control signal', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.device_name_exhaust_air_fan_control_signal', + 'last_changed': , + 'last_updated': , + 'state': '70', + }) +# --- +# name: test_sensors[sensor.device_name_exhaust_air_temperature-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.device_name_exhaust_air_temperature', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Exhaust air temperature', + 'platform': 'flexit_bacnet', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'exhaust_air_temperature', + 'unique_id': '0000-0001-exhaust_air_temperature', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.device_name_exhaust_air_temperature-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'temperature', + 'friendly_name': 'Device Name Exhaust air temperature', + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.device_name_exhaust_air_temperature', + 'last_changed': , + 'last_updated': , + 'state': '-3.3', + }) +# --- +# name: test_sensors[sensor.device_name_extract_air_temperature-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.device_name_extract_air_temperature', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Extract air temperature', + 'platform': 'flexit_bacnet', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'extract_air_temperature', + 'unique_id': '0000-0001-extract_air_temperature', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.device_name_extract_air_temperature-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'temperature', + 'friendly_name': 'Device Name Extract air temperature', + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.device_name_extract_air_temperature', + 'last_changed': , + 'last_updated': , + 'state': '19.0', + }) +# --- +# name: test_sensors[sensor.device_name_fireplace_ventilation_remaining_duration-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.device_name_fireplace_ventilation_remaining_duration', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Fireplace ventilation remaining duration', + 'platform': 'flexit_bacnet', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'fireplace_ventilation_remaining_duration', + 'unique_id': '0000-0001-fireplace_ventilation_remaining_duration', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.device_name_fireplace_ventilation_remaining_duration-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'duration', + 'friendly_name': 'Device Name Fireplace ventilation remaining duration', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.device_name_fireplace_ventilation_remaining_duration', + 'last_changed': , + 'last_updated': , + 'state': '10.0', + }) +# --- +# name: test_sensors[sensor.device_name_heat_exchanger_efficiency-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.device_name_heat_exchanger_efficiency', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Heat exchanger efficiency', + 'platform': 'flexit_bacnet', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'heat_exchanger_efficiency', + 'unique_id': '0000-0001-heat_exchanger_efficiency', + 'unit_of_measurement': '%', + }) +# --- +# name: test_sensors[sensor.device_name_heat_exchanger_efficiency-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Device Name Heat exchanger efficiency', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.device_name_heat_exchanger_efficiency', + 'last_changed': , + 'last_updated': , + 'state': '81', + }) +# --- +# name: test_sensors[sensor.device_name_heat_exchanger_speed-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.device_name_heat_exchanger_speed', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Heat exchanger speed', + 'platform': 'flexit_bacnet', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'heat_exchanger_speed', + 'unique_id': '0000-0001-heat_exchanger_speed', + 'unit_of_measurement': '%', + }) +# --- +# name: test_sensors[sensor.device_name_heat_exchanger_speed-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Device Name Heat exchanger speed', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.device_name_heat_exchanger_speed', + 'last_changed': , + 'last_updated': , + 'state': '100', + }) +# --- +# name: test_sensors[sensor.device_name_outside_air_temperature-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.device_name_outside_air_temperature', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Outside air temperature', + 'platform': 'flexit_bacnet', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'outside_air_temperature', + 'unique_id': '0000-0001-outside_air_temperature', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.device_name_outside_air_temperature-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'temperature', + 'friendly_name': 'Device Name Outside air temperature', + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.device_name_outside_air_temperature', + 'last_changed': , + 'last_updated': , + 'state': '-8.6', + }) +# --- +# name: test_sensors[sensor.device_name_rapid_ventilation_remaining_duration-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.device_name_rapid_ventilation_remaining_duration', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Rapid ventilation remaining duration', + 'platform': 'flexit_bacnet', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'rapid_ventilation_remaining_duration', + 'unique_id': '0000-0001-rapid_ventilation_remaining_duration', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.device_name_rapid_ventilation_remaining_duration-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'duration', + 'friendly_name': 'Device Name Rapid ventilation remaining duration', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.device_name_rapid_ventilation_remaining_duration', + 'last_changed': , + 'last_updated': , + 'state': '30.0', + }) +# --- +# name: test_sensors[sensor.device_name_room_temperature-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.device_name_room_temperature', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Room temperature', + 'platform': 'flexit_bacnet', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'room_temperature', + 'unique_id': '0000-0001-room_temperature', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.device_name_room_temperature-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'temperature', + 'friendly_name': 'Device Name Room temperature', + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.device_name_room_temperature', + 'last_changed': , + 'last_updated': , + 'state': '19.0', + }) +# --- +# name: test_sensors[sensor.device_name_supply_air_fan-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.device_name_supply_air_fan', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Supply air fan', + 'platform': 'flexit_bacnet', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'supply_air_fan_rpm', + 'unique_id': '0000-0001-supply_air_fan_rpm', + 'unit_of_measurement': 'rpm', + }) +# --- +# name: test_sensors[sensor.device_name_supply_air_fan-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Device Name Supply air fan', + 'state_class': , + 'unit_of_measurement': 'rpm', + }), + 'context': , + 'entity_id': 'sensor.device_name_supply_air_fan', + 'last_changed': , + 'last_updated': , + 'state': '2784', + }) +# --- +# name: test_sensors[sensor.device_name_supply_air_fan_control_signal-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.device_name_supply_air_fan_control_signal', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Supply air fan control signal', + 'platform': 'flexit_bacnet', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'supply_air_fan_control_signal', + 'unique_id': '0000-0001-supply_air_fan_control_signal', + 'unit_of_measurement': '%', + }) +# --- +# name: test_sensors[sensor.device_name_supply_air_fan_control_signal-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Device Name Supply air fan control signal', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.device_name_supply_air_fan_control_signal', + 'last_changed': , + 'last_updated': , + 'state': '74', + }) +# --- +# name: test_sensors[sensor.device_name_supply_air_temperature-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.device_name_supply_air_temperature', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Supply air temperature', + 'platform': 'flexit_bacnet', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'supply_air_temperature', + 'unique_id': '0000-0001-supply_air_temperature', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.device_name_supply_air_temperature-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'temperature', + 'friendly_name': 'Device Name Supply air temperature', + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.device_name_supply_air_temperature', + 'last_changed': , + 'last_updated': , + 'state': '19.1', + }) +# --- diff --git a/tests/components/flexit_bacnet/test_sensor.py b/tests/components/flexit_bacnet/test_sensor.py new file mode 100644 index 00000000000..2285b4c8692 --- /dev/null +++ b/tests/components/flexit_bacnet/test_sensor.py @@ -0,0 +1,33 @@ +"""Tests for the Flexit Nordic (BACnet) sensor entities.""" +from unittest.mock import AsyncMock + +from syrupy.assertion import SnapshotAssertion + +from homeassistant.const import Platform +from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry as er + +from tests.common import MockConfigEntry +from tests.components.flexit_bacnet import setup_with_selected_platforms + + +async def test_sensors( + hass: HomeAssistant, + snapshot: SnapshotAssertion, + entity_registry: er.EntityRegistry, + mock_flexit_bacnet: AsyncMock, + mock_config_entry: MockConfigEntry, +) -> None: + """Test sensor states are correctly collected from library.""" + + await setup_with_selected_platforms(hass, mock_config_entry, [Platform.SENSOR]) + entity_entries = er.async_entries_for_config_entry( + entity_registry, mock_config_entry.entry_id + ) + + assert entity_entries + for entity_entry in entity_entries: + assert entity_entry == snapshot(name=f"{entity_entry.entity_id}-entry") + assert hass.states.get(entity_entry.entity_id) == snapshot( + name=f"{entity_entry.entity_id}-state" + )