diff --git a/homeassistant/components/fumis/icons.json b/homeassistant/components/fumis/icons.json index 6cfb39c391161..df727450a1220 100644 --- a/homeassistant/components/fumis/icons.json +++ b/homeassistant/components/fumis/icons.json @@ -6,12 +6,55 @@ } }, "sensor": { + "alert": { + "default": "mdi:alert", + "state": { + "airflow_malfunction": "mdi:fan-off", + "door_open": "mdi:door-open", + "flue_gas_warning": "mdi:thermometer-alert", + "low_battery": "mdi:battery-alert", + "low_fuel": "mdi:gauge-empty", + "none": "mdi:check-circle", + "service_due": "mdi:wrench-clock", + "speed_sensor_failure": "mdi:fan-alert" + } + }, "combustion_chamber_temperature": { "default": "mdi:thermometer-high" }, "detailed_stove_status": { "default": "mdi:fireplace" }, + "error": { + "default": "mdi:alert-circle", + "state": { + "chimney_alarm": "mdi:broom", + "chimney_dirty": "mdi:broom", + "door_alarm": "mdi:door-open", + "fire_error": "mdi:fire-alert", + "flue_gas_overtemp": "mdi:thermometer-high", + "fuel_ignition_timeout": "mdi:fire-off", + "gas_alarm": "mdi:alert-circle", + "general_error": "mdi:alert-circle", + "grate_error": "mdi:alert-circle", + "ignition_failed": "mdi:fire-alert", + "mfdoor_alarm": "mdi:door-open", + "no_pellet_alarm": "mdi:gauge-empty", + "none": "mdi:check-circle", + "ntc1_alarm": "mdi:thermometer-alert", + "ntc2_alarm": "mdi:thermometer-alert", + "ntc3_alarm": "mdi:thermometer-alert", + "pressure_alarm": "mdi:gauge-empty", + "pressure_sensor_off": "mdi:gauge-empty", + "safety_switch": "mdi:shield-alert", + "sensor_t01_t02": "mdi:thermometer-alert", + "sensor_t01_t03": "mdi:thermometer-alert", + "sensor_t02": "mdi:thermometer-alert", + "sensor_t03_t05": "mdi:thermometer-alert", + "sensor_t04": "mdi:thermometer-alert", + "tc1_alarm": "mdi:thermometer-alert" + } + }, "fan_1_speed": { "default": "mdi:fan" }, diff --git a/homeassistant/components/fumis/sensor.py b/homeassistant/components/fumis/sensor.py index 78c48b35f4552..024096048f8f9 100644 --- a/homeassistant/components/fumis/sensor.py +++ b/homeassistant/components/fumis/sensor.py @@ -5,8 +5,9 @@ from collections.abc import Callable from dataclasses import dataclass from datetime import datetime, timedelta +from typing import Any -from fumis import FumisInfo, StoveState, StoveStatus +from fumis import FumisInfo, StoveAlert, StoveError, StoveState, StoveStatus from homeassistant.components.sensor import ( SensorDeviceClass, @@ -34,15 +35,52 @@ PARALLEL_UPDATES = 0 +def _code_to_state(code: StoveAlert | StoveError | None) -> str | None: + """Convert a stove alert or error code to a sensor state value. + + Returns "none" when there is no active alert/error, None when the code + is unknown, or the enum member name in lowercase for known codes. + """ + if code is None: + return "none" + if code.name == "UNKNOWN": + return None + return code.name.lower() + + +def _code_to_attr(code: StoveAlert | StoveError | None) -> dict[str, str | None]: + """Convert a stove alert or error code to extra state attributes.""" + if code is None or code.name == "UNKNOWN": + return {"code": None} + return {"code": code.value} + + @dataclass(frozen=True, kw_only=True) class FumisSensorEntityDescription(SensorEntityDescription): """Describes a Fumis sensor entity.""" + attr_fn: Callable[[FumisInfo], dict[str, Any]] | None = None has_fn: Callable[[FumisInfo], bool] = lambda _: True value_fn: Callable[[FumisInfo], datetime | float | int | str | None] SENSORS: tuple[FumisSensorEntityDescription, ...] = ( + FumisSensorEntityDescription( + key="alert", + translation_key="alert", + device_class=SensorDeviceClass.ENUM, + entity_category=EntityCategory.DIAGNOSTIC, + options=[ + "none", + *( + alert.name.lower() + for alert in StoveAlert + if alert != StoveAlert.UNKNOWN + ), + ], + value_fn=lambda data: _code_to_state(data.controller.stove_alert), + attr_fn=lambda data: _code_to_attr(data.controller.stove_alert), + ), FumisSensorEntityDescription( key="combustion_chamber_temperature", translation_key="combustion_chamber_temperature", @@ -69,6 +107,22 @@ class FumisSensorEntityDescription(SensorEntityDescription): else data.controller.stove_status.name.lower() ), ), + FumisSensorEntityDescription( + key="error", + translation_key="error", + device_class=SensorDeviceClass.ENUM, + entity_category=EntityCategory.DIAGNOSTIC, + options=[ + "none", + *( + error.name.lower() + for error in StoveError + if error != StoveError.UNKNOWN + ), + ], + value_fn=lambda data: _code_to_state(data.controller.stove_error), + attr_fn=lambda data: _code_to_attr(data.controller.stove_error), + ), FumisSensorEntityDescription( key="fan_1_speed", translation_key="fan_1_speed", @@ -267,6 +321,13 @@ def __init__( self.entity_description = description self._attr_unique_id = f"{coordinator.config_entry.unique_id}_{description.key}" + @property + def extra_state_attributes(self) -> dict[str, Any] | None: + """Return additional state attributes.""" + if self.entity_description.attr_fn is None: + return None + return self.entity_description.attr_fn(self.coordinator.data) + @property def native_value(self) -> datetime | float | int | str | None: """Return the sensor value.""" diff --git a/homeassistant/components/fumis/strings.json b/homeassistant/components/fumis/strings.json index 85b11a82be3f3..fa3f4a4d9ac65 100644 --- a/homeassistant/components/fumis/strings.json +++ b/homeassistant/components/fumis/strings.json @@ -59,6 +59,19 @@ } }, "sensor": { + "alert": { + "name": "Alert", + "state": { + "airflow_malfunction": "Airflow sensor malfunction", + "door_open": "Door open", + "flue_gas_warning": "Flue gas temperature warning", + "low_battery": "Low battery", + "low_fuel": "Low fuel level", + "none": "No alert", + "service_due": "Service due", + "speed_sensor_failure": "Speed sensor failure" + } + }, "combustion_chamber_temperature": { "name": "Combustion chamber" }, @@ -81,6 +94,36 @@ "wood_start": "Wood start" } }, + "error": { + "name": "Error", + "state": { + "chimney_alarm": "Chimney alarm", + "chimney_dirty": "Chimney or burning pot dirty", + "door_alarm": "Door alarm", + "fire_error": "Fire error", + "flue_gas_overtemp": "Flue gas overtemperature", + "fuel_ignition_timeout": "Fuel ignition timeout", + "gas_alarm": "Gas alarm", + "general_error": "General error", + "grate_error": "Grate error", + "ignition_failed": "Ignition failed", + "mfdoor_alarm": "MFDoor alarm", + "no_pellet_alarm": "No pellet alarm", + "none": "No error", + "ntc1_alarm": "NTC1 alarm", + "ntc2_alarm": "NTC2 alarm", + "ntc3_alarm": "NTC3 alarm", + "pressure_alarm": "Pressure alarm", + "pressure_sensor_off": "Pressure sensor off", + "safety_switch": "Safety switch tripped", + "sensor_t01_t02": "Sensor T01/T02 malfunction", + "sensor_t01_t03": "Sensor T01/T03 malfunction", + "sensor_t02": "Sensor T02 malfunction", + "sensor_t03_t05": "Sensor T03/T05 malfunction", + "sensor_t04": "Sensor T04 malfunction", + "tc1_alarm": "TC1 alarm" + } + }, "fan_1_speed": { "name": "Fan 1 speed" }, diff --git a/tests/components/fumis/fixtures/info_error_alert.json b/tests/components/fumis/fixtures/info_error_alert.json new file mode 100644 index 0000000000000..0c95ce0daefd4 --- /dev/null +++ b/tests/components/fumis/fixtures/info_error_alert.json @@ -0,0 +1,1209 @@ +{ + "apiVersion": "1.3", + "unit": { + "id": "AABBCCDDEEFF", + "type": 3, + "version": "2.5.0", + "command": null, + "rssi": "-60", + "ip": "192.168.1.2", + "timezone": null, + "temperature": 27 + }, + "controller": { + "type": 2, + "version": "2.6.0", + "command": 2, + "status": 30, + "heatingSlope": -0.1, + "stoveLastAvailability": 1776413799, + "mobileLastAvailability": 1776412827, + "currentTime": 1776413805, + "error": 101, + "alert": 1, + "timerEnable": false, + "fuelType": 1, + "timeToService": 2159, + "delayedStartAt": -1, + "delayedStopAt": -1, + "power": { + "setType": 1, + "actualType": 2, + "kw": 4.6, + "actualPower": 0, + "setPower": 5 + }, + "antifreeze": { + "temperature": 5, + "enable": true + }, + "statistic": { + "igniterStarts": 2, + "uptime": 86760, + "heatingTime": 4080, + "serviceTime": 4080, + "overheatings": 0, + "misfires": 0, + "fuelQuantityUsed": 0 + }, + "diagnostic": { + "parameters": [ + { + "id": 0, + "value": 25 + }, + { + "id": 1, + "value": 5 + }, + { + "id": 2, + "value": 0 + }, + { + "id": 3, + "value": 1 + }, + { + "id": 4, + "value": 100 + }, + { + "id": 5, + "value": 85 + }, + { + "id": 6, + "value": 20 + }, + { + "id": 7, + "value": 85 + }, + { + "id": 8, + "value": 25 + }, + { + "id": 9, + "value": 70 + }, + { + "id": 10, + "value": 25 + }, + { + "id": 11, + "value": 90 + }, + { + "id": 12, + "value": 22 + }, + { + "id": 13, + "value": 115 + }, + { + "id": 14, + "value": 31 + }, + { + "id": 15, + "value": 130 + }, + { + "id": 16, + "value": 39 + }, + { + "id": 17, + "value": 145 + }, + { + "id": 18, + "value": 50 + }, + { + "id": 19, + "value": 140 + }, + { + "id": 20, + "value": 200 + }, + { + "id": 21, + "value": 190 + }, + { + "id": 22, + "value": 215 + }, + { + "id": 23, + "value": 200 + }, + { + "id": 24, + "value": 125 + }, + { + "id": 25, + "value": 85 + }, + { + "id": 26, + "value": 108 + }, + { + "id": 27, + "value": 129 + }, + { + "id": 28, + "value": 150 + }, + { + "id": 29, + "value": 85 + }, + { + "id": 30, + "value": 85 + }, + { + "id": 31, + "value": 85 + }, + { + "id": 32, + "value": 85 + }, + { + "id": 33, + "value": 85 + }, + { + "id": 34, + "value": 85 + }, + { + "id": 35, + "value": 105 + }, + { + "id": 36, + "value": 125 + }, + { + "id": 37, + "value": 145 + }, + { + "id": 38, + "value": 165 + }, + { + "id": 39, + "value": 135 + }, + { + "id": 40, + "value": 120 + }, + { + "id": 41, + "value": 0 + }, + { + "id": 42, + "value": 0 + }, + { + "id": 43, + "value": 0 + }, + { + "id": 44, + "value": 0 + }, + { + "id": 45, + "value": 90 + }, + { + "id": 46, + "value": 105 + }, + { + "id": 47, + "value": 120 + }, + { + "id": 48, + "value": 135 + }, + { + "id": 49, + "value": 150 + }, + { + "id": 50, + "value": 5 + }, + { + "id": 51, + "value": 125 + }, + { + "id": 52, + "value": 6 + }, + { + "id": 53, + "value": 0 + }, + { + "id": 54, + "value": 40 + }, + { + "id": 55, + "value": 155 + }, + { + "id": 56, + "value": 35 + }, + { + "id": 57, + "value": 200 + }, + { + "id": 58, + "value": 50 + }, + { + "id": 59, + "value": 37 + }, + { + "id": 60, + "value": 45 + }, + { + "id": 61, + "value": 120 + }, + { + "id": 62, + "value": 230 + }, + { + "id": 63, + "value": 0 + }, + { + "id": 64, + "value": 0 + }, + { + "id": 65, + "value": 0 + }, + { + "id": 66, + "value": 0 + }, + { + "id": 67, + "value": 5 + }, + { + "id": 68, + "value": 40 + }, + { + "id": 69, + "value": 60 + }, + { + "id": 70, + "value": 125 + }, + { + "id": 71, + "value": 2 + }, + { + "id": 72, + "value": 4 + }, + { + "id": 73, + "value": 100 + }, + { + "id": 74, + "value": 100 + }, + { + "id": 75, + "value": 100 + }, + { + "id": 76, + "value": 1 + }, + { + "id": 77, + "value": 0 + }, + { + "id": 78, + "value": 0 + }, + { + "id": 79, + "value": 0 + }, + { + "id": 80, + "value": 0 + }, + { + "id": 81, + "value": 0 + }, + { + "id": 82, + "value": 200 + }, + { + "id": 83, + "value": 90 + }, + { + "id": 84, + "value": 70 + }, + { + "id": 85, + "value": 80 + }, + { + "id": 86, + "value": 90 + }, + { + "id": 87, + "value": 50 + }, + { + "id": 88, + "value": 100 + }, + { + "id": 89, + "value": 1 + }, + { + "id": 90, + "value": 0 + }, + { + "id": 91, + "value": 0 + }, + { + "id": 92, + "value": 2 + }, + { + "id": 93, + "value": 1 + }, + { + "id": 94, + "value": 90 + }, + { + "id": 95, + "value": 0 + }, + { + "id": 96, + "value": 4 + }, + { + "id": 97, + "value": 27 + }, + { + "id": 98, + "value": 0 + }, + { + "id": 99, + "value": 0 + }, + { + "id": 100, + "value": 0 + }, + { + "id": 101, + "value": 60 + }, + { + "id": 102, + "value": 50 + }, + { + "id": 103, + "value": 10 + }, + { + "id": 104, + "value": 5 + }, + { + "id": 105, + "value": 60 + } + ], + "variables": [ + { + "id": 0, + "value": 2 + }, + { + "id": 1, + "value": 17410 + }, + { + "id": 2, + "value": 68 + }, + { + "id": 3, + "value": 0 + }, + { + "id": 4, + "value": 108 + }, + { + "id": 5, + "value": 5 + }, + { + "id": 6, + "value": 0 + }, + { + "id": 7, + "value": 0 + }, + { + "id": 8, + "value": 0 + }, + { + "id": 9, + "value": 6 + }, + { + "id": 10, + "value": 0 + }, + { + "id": 11, + "value": 0 + }, + { + "id": 12, + "value": 0 + }, + { + "id": 13, + "value": 2 + }, + { + "id": 14, + "value": 6 + }, + { + "id": 15, + "value": 24 + }, + { + "id": 16, + "value": 8 + }, + { + "id": 17, + "value": 1 + }, + { + "id": 18, + "value": 8 + }, + { + "id": 19, + "value": 1 + }, + { + "id": 20, + "value": 0 + }, + { + "id": 21, + "value": 0 + }, + { + "id": 22, + "value": 207 + }, + { + "id": 23, + "value": 22 + }, + { + "id": 24, + "value": 8 + }, + { + "id": 25, + "value": 0 + }, + { + "id": 26, + "value": 2 + }, + { + "id": 27, + "value": 2 + }, + { + "id": 28, + "value": 1 + }, + { + "id": 29, + "value": 0 + }, + { + "id": 30, + "value": 1 + }, + { + "id": 31, + "value": 1 + }, + { + "id": 32, + "value": 0 + }, + { + "id": 33, + "value": 1 + }, + { + "id": 34, + "value": 1127 + }, + { + "id": 35, + "value": 675 + }, + { + "id": 36, + "value": 0 + }, + { + "id": 37, + "value": 241 + }, + { + "id": 38, + "value": 20000101 + }, + { + "id": 39, + "value": 8 + }, + { + "id": 40, + "value": 1 + }, + { + "id": 41, + "value": 241 + }, + { + "id": 42, + "value": 20000101 + }, + { + "id": 43, + "value": 10 + }, + { + "id": 44, + "value": 2 + }, + { + "id": 45, + "value": 241 + }, + { + "id": 46, + "value": 20000101 + }, + { + "id": 47, + "value": 2347 + }, + { + "id": 48, + "value": 3 + }, + { + "id": 49, + "value": 0 + }, + { + "id": 50, + "value": 0 + }, + { + "id": 51, + "value": 0 + }, + { + "id": 52, + "value": 4 + }, + { + "id": 53, + "value": 0 + }, + { + "id": 54, + "value": 0 + }, + { + "id": 55, + "value": 0 + }, + { + "id": 56, + "value": 5 + }, + { + "id": 57, + "value": 0 + }, + { + "id": 58, + "value": 0 + }, + { + "id": 59, + "value": 0 + }, + { + "id": 60, + "value": 6 + }, + { + "id": 61, + "value": 0 + }, + { + "id": 62, + "value": 0 + }, + { + "id": 63, + "value": 0 + }, + { + "id": 64, + "value": 7 + }, + { + "id": 65, + "value": 0 + }, + { + "id": 66, + "value": 0 + }, + { + "id": 67, + "value": 0 + }, + { + "id": 68, + "value": 8 + }, + { + "id": 69, + "value": 0 + }, + { + "id": 70, + "value": 0 + }, + { + "id": 71, + "value": 0 + }, + { + "id": 72, + "value": 9 + }, + { + "id": 73, + "value": 0 + }, + { + "id": 74, + "value": 0 + }, + { + "id": 75, + "value": 0 + }, + { + "id": 76, + "value": 10 + }, + { + "id": 77, + "value": 0 + }, + { + "id": 78, + "value": 0 + }, + { + "id": 79, + "value": 0 + }, + { + "id": 80, + "value": 11 + }, + { + "id": 81, + "value": 0 + }, + { + "id": 82, + "value": 0 + }, + { + "id": 83, + "value": 0 + }, + { + "id": 84, + "value": 12 + }, + { + "id": 85, + "value": 0 + }, + { + "id": 86, + "value": 0 + }, + { + "id": 87, + "value": 0 + }, + { + "id": 88, + "value": 13 + }, + { + "id": 89, + "value": 0 + }, + { + "id": 90, + "value": 0 + }, + { + "id": 91, + "value": 0 + }, + { + "id": 92, + "value": 14 + }, + { + "id": 93, + "value": 0 + }, + { + "id": 94, + "value": 0 + }, + { + "id": 95, + "value": 0 + }, + { + "id": 96, + "value": 211 + }, + { + "id": 97, + "value": 15 + }, + { + "id": 98, + "value": 0 + }, + { + "id": 99, + "value": 0 + } + ], + "timers": [ + { + "id": 0, + "value": 5 + }, + { + "id": 1, + "value": 45 + }, + { + "id": 2, + "value": 7 + }, + { + "id": 3, + "value": 30 + }, + { + "id": 4, + "value": 6 + }, + { + "id": 5, + "value": 15 + }, + { + "id": 6, + "value": 8 + }, + { + "id": 7, + "value": 15 + }, + { + "id": 8, + "value": 11 + }, + { + "id": 9, + "value": 30 + }, + { + "id": 10, + "value": 14 + }, + { + "id": 11, + "value": 0 + }, + { + "id": 12, + "value": 12 + }, + { + "id": 13, + "value": 0 + }, + { + "id": 14, + "value": 14 + }, + { + "id": 15, + "value": 30 + }, + { + "id": 16, + "value": 0 + }, + { + "id": 17, + "value": 0 + }, + { + "id": 18, + "value": 0 + }, + { + "id": 19, + "value": 0 + }, + { + "id": 20, + "value": 0 + }, + { + "id": 21, + "value": 0 + }, + { + "id": 22, + "value": 0 + }, + { + "id": 23, + "value": 0 + }, + { + "id": 24, + "value": 0 + }, + { + "id": 25, + "value": 0 + }, + { + "id": 26, + "value": 0 + }, + { + "id": 27, + "value": 0 + }, + { + "id": 28, + "value": 0 + }, + { + "id": 29, + "value": 0 + }, + { + "id": 30, + "value": 16 + }, + { + "id": 31, + "value": 0 + }, + { + "id": 32, + "value": 21 + }, + { + "id": 33, + "value": 0 + }, + { + "id": 34, + "value": 17 + }, + { + "id": 35, + "value": 30 + }, + { + "id": 36, + "value": 22 + }, + { + "id": 37, + "value": 30 + }, + { + "id": 38, + "value": 0 + }, + { + "id": 39, + "value": 0 + }, + { + "id": 40, + "value": 0 + }, + { + "id": 41, + "value": 0 + }, + { + "id": 42, + "value": 0 + }, + { + "id": 43, + "value": 0 + }, + { + "id": 44, + "value": 0 + }, + { + "id": 45, + "value": 160 + }, + { + "id": 46, + "value": 160 + }, + { + "id": 47, + "value": 160 + }, + { + "id": 48, + "value": 160 + }, + { + "id": 49, + "value": 160 + }, + { + "id": 50, + "value": 160 + } + ] + }, + "ecoMode": { + "ecoModeSetType": 1, + "ecoModeEnable": 0 + }, + "hybrid": { + "actualType": 1, + "operation": 0, + "state": 0 + }, + "fans": [ + { + "weight": 0, + "speedType": 0, + "speed": 0, + "id": 1 + } + ], + "fuels": [ + { + "name": null, + "quality": 2, + "qualityType": 0, + "qualityActual": null, + "quantitySetType": 2, + "quantityActualType": 2, + "quantity": 0.95, + "quantityDisplay": 1, + "id": 1 + } + ], + "temperatures": [ + { + "name": null, + "weight": 0, + "setType": 2, + "actualType": 1, + "onMainScreen": true, + "actual": 20.7, + "set": 25, + "id": 1 + }, + { + "name": null, + "weight": 0, + "setType": 0, + "actualType": 0, + "onMainScreen": false, + "actual": 0, + "set": 0, + "id": 2 + }, + { + "name": null, + "weight": 0, + "setType": 0, + "actualType": 0, + "onMainScreen": false, + "actual": 0, + "set": 0, + "id": 3 + }, + { + "name": null, + "weight": 0, + "setType": 0, + "actualType": 0, + "onMainScreen": false, + "actual": 0, + "set": 0, + "id": 4 + }, + { + "name": null, + "weight": 0, + "setType": 0, + "actualType": 0, + "onMainScreen": false, + "actual": 0, + "set": 0, + "id": 5 + }, + { + "name": null, + "weight": 0, + "setType": 0, + "actualType": 0, + "onMainScreen": false, + "actual": 0, + "set": 0, + "id": 6 + }, + { + "name": null, + "weight": 0, + "setType": 0, + "actualType": 10, + "onMainScreen": false, + "actual": 206, + "set": 0, + "id": 7 + }, + { + "name": null, + "weight": 0, + "setType": 1, + "actualType": 1, + "onMainScreen": false, + "actual": 0, + "set": 0.5, + "id": 8 + }, + { + "name": null, + "weight": 0, + "setType": 1, + "actualType": 1, + "onMainScreen": false, + "actual": 0, + "set": 0, + "id": 9 + } + ], + "timers": [] + } +} diff --git a/tests/components/fumis/snapshots/test_sensor.ambr b/tests/components/fumis/snapshots/test_sensor.ambr index 490a7dd7d7706..92515d535b84a 100644 --- a/tests/components/fumis/snapshots/test_sensor.ambr +++ b/tests/components/fumis/snapshots/test_sensor.ambr @@ -1,4 +1,77 @@ # serializer version: 1 +# name: test_sensors[sensor][sensor.clou_duo_alert-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + 'none', + 'low_fuel', + 'service_due', + 'flue_gas_warning', + 'low_battery', + 'speed_sensor_failure', + 'door_open', + 'airflow_malfunction', + ]), + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.clou_duo_alert', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Alert', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Alert', + 'platform': 'fumis', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'alert', + 'unique_id': 'aa:bb:cc:dd:ee:ff_alert', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensors[sensor][sensor.clou_duo_alert-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'code': None, + 'device_class': 'enum', + 'friendly_name': 'Clou Duo Alert', + 'options': list([ + 'none', + 'low_fuel', + 'service_due', + 'flue_gas_warning', + 'low_battery', + 'speed_sensor_failure', + 'door_open', + 'airflow_malfunction', + ]), + }), + 'context': , + 'entity_id': 'sensor.clou_duo_alert', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'none', + }) +# --- # name: test_sensors[sensor][sensor.clou_duo_burning_time-entry] EntityRegistryEntrySnapshot({ 'aliases': list([ @@ -255,6 +328,113 @@ 'state': 'combustion', }) # --- +# name: test_sensors[sensor][sensor.clou_duo_error-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + 'none', + 'ignition_failed', + 'chimney_dirty', + 'sensor_t02', + 'sensor_t03_t05', + 'sensor_t04', + 'safety_switch', + 'pressure_sensor_off', + 'sensor_t01_t02', + 'sensor_t01_t03', + 'flue_gas_overtemp', + 'fuel_ignition_timeout', + 'general_error', + 'mfdoor_alarm', + 'fire_error', + 'chimney_alarm', + 'grate_error', + 'ntc2_alarm', + 'ntc3_alarm', + 'door_alarm', + 'pressure_alarm', + 'ntc1_alarm', + 'tc1_alarm', + 'gas_alarm', + 'no_pellet_alarm', + ]), + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.clou_duo_error', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Error', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Error', + 'platform': 'fumis', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'error', + 'unique_id': 'aa:bb:cc:dd:ee:ff_error', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensors[sensor][sensor.clou_duo_error-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'code': None, + 'device_class': 'enum', + 'friendly_name': 'Clou Duo Error', + 'options': list([ + 'none', + 'ignition_failed', + 'chimney_dirty', + 'sensor_t02', + 'sensor_t03_t05', + 'sensor_t04', + 'safety_switch', + 'pressure_sensor_off', + 'sensor_t01_t02', + 'sensor_t01_t03', + 'flue_gas_overtemp', + 'fuel_ignition_timeout', + 'general_error', + 'mfdoor_alarm', + 'fire_error', + 'chimney_alarm', + 'grate_error', + 'ntc2_alarm', + 'ntc3_alarm', + 'door_alarm', + 'pressure_alarm', + 'ntc1_alarm', + 'tc1_alarm', + 'gas_alarm', + 'no_pellet_alarm', + ]), + }), + 'context': , + 'entity_id': 'sensor.clou_duo_error', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'none', + }) +# --- # name: test_sensors[sensor][sensor.clou_duo_fan_1_speed-entry] EntityRegistryEntrySnapshot({ 'aliases': list([ @@ -1089,3 +1269,70 @@ 'state': '27.0', }) # --- +# name: test_sensors_active_error_and_alert[info_error_alert-sensor] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'code': 'E101', + 'device_class': 'enum', + 'friendly_name': 'Clou Duo Error', + 'options': list([ + 'none', + 'ignition_failed', + 'chimney_dirty', + 'sensor_t02', + 'sensor_t03_t05', + 'sensor_t04', + 'safety_switch', + 'pressure_sensor_off', + 'sensor_t01_t02', + 'sensor_t01_t03', + 'flue_gas_overtemp', + 'fuel_ignition_timeout', + 'general_error', + 'mfdoor_alarm', + 'fire_error', + 'chimney_alarm', + 'grate_error', + 'ntc2_alarm', + 'ntc3_alarm', + 'door_alarm', + 'pressure_alarm', + 'ntc1_alarm', + 'tc1_alarm', + 'gas_alarm', + 'no_pellet_alarm', + ]), + }), + 'context': , + 'entity_id': 'sensor.clou_duo_error', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'ignition_failed', + }) +# --- +# name: test_sensors_active_error_and_alert[info_error_alert-sensor].1 + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'code': 'A001', + 'device_class': 'enum', + 'friendly_name': 'Clou Duo Alert', + 'options': list([ + 'none', + 'low_fuel', + 'service_due', + 'flue_gas_warning', + 'low_battery', + 'speed_sensor_failure', + 'door_open', + 'airflow_malfunction', + ]), + }), + 'context': , + 'entity_id': 'sensor.clou_duo_alert', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'low_fuel', + }) +# --- diff --git a/tests/components/fumis/test_sensor.py b/tests/components/fumis/test_sensor.py index 776ea33e91fdd..a24b383edc32a 100644 --- a/tests/components/fumis/test_sensor.py +++ b/tests/components/fumis/test_sensor.py @@ -66,6 +66,33 @@ async def test_sensors_unknown_status( assert state.state == STATE_UNKNOWN +@pytest.mark.parametrize("device_fixture", ["info_error_alert"]) +@pytest.mark.usefixtures("entity_registry_enabled_by_default", "init_integration") +async def test_sensors_active_error_and_alert( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + snapshot: SnapshotAssertion, +) -> None: + """Test error and alert sensors with active codes.""" + error_entity_id = entity_registry.async_get_entity_id( + "sensor", "fumis", f"{UNIQUE_ID}_error" + ) + assert error_entity_id is not None + assert (state := hass.states.get(error_entity_id)) + assert state == snapshot + assert state.state == "ignition_failed" + assert state.attributes["code"] == "E101" + + alert_entity_id = entity_registry.async_get_entity_id( + "sensor", "fumis", f"{UNIQUE_ID}_alert" + ) + assert alert_entity_id is not None + assert (state := hass.states.get(alert_entity_id)) + assert state == snapshot + assert state.state == "low_fuel" + assert state.attributes["code"] == "A001" + + @pytest.mark.parametrize("device_fixture", ["info_minimal"]) @pytest.mark.usefixtures("entity_registry_enabled_by_default", "init_integration") async def test_sensors_conditional_creation( @@ -93,7 +120,9 @@ async def test_sensors_conditional_creation( # These should still exist for key in ( + "alert", "detailed_stove_status", + "error", "power_output", "stove_status", "wifi_rssi",