Add Home Connect sensors for fridge door states and alarms (#125490)

* New sensors for Fridge door states and alarms

* Move 2 option entities to binary_sensor, tests

* Change state translations

* Fix stale docstring
This commit is contained in:
Robert Contreras 2024-09-13 10:31:35 -07:00 committed by GitHub
parent ba7ca84899
commit 85aa32338e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 478 additions and 6 deletions

View File

@ -1,14 +1,21 @@
"""Provides a binary sensor for Home Connect.""" """Provides a binary sensor for Home Connect."""
from dataclasses import dataclass, field
import logging import logging
from homeassistant.components.binary_sensor import BinarySensorEntity from homeassistant.components.binary_sensor import (
BinarySensorDeviceClass,
BinarySensorEntity,
BinarySensorEntityDescription,
)
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_ENTITIES from homeassistant.const import CONF_ENTITIES
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .api import HomeConnectDevice
from .const import ( from .const import (
ATTR_DEVICE,
ATTR_VALUE, ATTR_VALUE,
BSH_DOOR_STATE, BSH_DOOR_STATE,
BSH_DOOR_STATE_CLOSED, BSH_DOOR_STATE_CLOSED,
@ -17,12 +24,47 @@ from .const import (
BSH_REMOTE_CONTROL_ACTIVATION_STATE, BSH_REMOTE_CONTROL_ACTIVATION_STATE,
BSH_REMOTE_START_ALLOWANCE_STATE, BSH_REMOTE_START_ALLOWANCE_STATE,
DOMAIN, DOMAIN,
REFRIGERATION_STATUS_DOOR_CHILLER,
REFRIGERATION_STATUS_DOOR_CLOSED,
REFRIGERATION_STATUS_DOOR_FREEZER,
REFRIGERATION_STATUS_DOOR_OPEN,
REFRIGERATION_STATUS_DOOR_REFRIGERATOR,
) )
from .entity import HomeConnectEntity from .entity import HomeConnectEntity
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@dataclass(frozen=True, kw_only=True)
class HomeConnectBinarySensorEntityDescription(BinarySensorEntityDescription):
"""Entity Description class for binary sensors."""
state_key: str | None
device_class: BinarySensorDeviceClass | None = BinarySensorDeviceClass.DOOR
boolean_map: dict[str, bool] = field(
default_factory=lambda: {
REFRIGERATION_STATUS_DOOR_CLOSED: False,
REFRIGERATION_STATUS_DOOR_OPEN: True,
}
)
BINARY_SENSORS: tuple[HomeConnectBinarySensorEntityDescription, ...] = (
HomeConnectBinarySensorEntityDescription(
key="Chiller Door",
state_key=REFRIGERATION_STATUS_DOOR_CHILLER,
),
HomeConnectBinarySensorEntityDescription(
key="Freezer Door",
state_key=REFRIGERATION_STATUS_DOOR_FREEZER,
),
HomeConnectBinarySensorEntityDescription(
key="Refrigerator Door",
state_key=REFRIGERATION_STATUS_DOOR_REFRIGERATOR,
),
)
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
config_entry: ConfigEntry, config_entry: ConfigEntry,
@ -36,6 +78,15 @@ async def async_setup_entry(
for device_dict in hc_api.devices: for device_dict in hc_api.devices:
entity_dicts = device_dict.get(CONF_ENTITIES, {}).get("binary_sensor", []) entity_dicts = device_dict.get(CONF_ENTITIES, {}).get("binary_sensor", [])
entities += [HomeConnectBinarySensor(**d) for d in entity_dicts] entities += [HomeConnectBinarySensor(**d) for d in entity_dicts]
device: HomeConnectDevice = device_dict[ATTR_DEVICE]
# Auto-discover entities
entities.extend(
HomeConnectFridgeDoorBinarySensor(
device=device, entity_description=description
)
for description in BINARY_SENSORS
if description.state_key in device.appliance.status
)
return entities return entities
async_add_entities(await hass.async_add_executor_job(get_entities), True) async_add_entities(await hass.async_add_executor_job(get_entities), True)
@ -93,3 +144,37 @@ class HomeConnectBinarySensor(HomeConnectEntity, BinarySensorEntity):
def device_class(self): def device_class(self):
"""Return the device class.""" """Return the device class."""
return self._device_class return self._device_class
class HomeConnectFridgeDoorBinarySensor(HomeConnectEntity, BinarySensorEntity):
"""Binary sensor for Home Connect Fridge Doors."""
entity_description: HomeConnectBinarySensorEntityDescription
def __init__(
self,
device: HomeConnectDevice,
entity_description: HomeConnectBinarySensorEntityDescription,
) -> None:
"""Initialize the entity."""
self.entity_description = entity_description
super().__init__(device, entity_description.key)
async def async_update(self) -> None:
"""Update the binary sensor's status."""
_LOGGER.debug(
"Updating: %s, cur state: %s",
self._attr_unique_id,
self.state,
)
self._attr_is_on = self.entity_description.boolean_map.get(
self.device.appliance.status.get(self.entity_description.state_key, {}).get(
ATTR_VALUE
)
)
self._attr_available = self._attr_is_on is not None
_LOGGER.debug(
"Updated: %s, new state: %s",
self._attr_unique_id,
self.state,
)

View File

@ -14,6 +14,9 @@ BSH_REMOTE_CONTROL_ACTIVATION_STATE = "BSH.Common.Status.RemoteControlActive"
BSH_REMOTE_START_ALLOWANCE_STATE = "BSH.Common.Status.RemoteControlStartAllowed" BSH_REMOTE_START_ALLOWANCE_STATE = "BSH.Common.Status.RemoteControlStartAllowed"
BSH_CHILD_LOCK_STATE = "BSH.Common.Setting.ChildLock" BSH_CHILD_LOCK_STATE = "BSH.Common.Setting.ChildLock"
BSH_EVENT_PRESENT_STATE_PRESENT = "BSH.Common.EnumType.EventPresentState.Present"
BSH_EVENT_PRESENT_STATE_CONFIRMED = "BSH.Common.EnumType.EventPresentState.Confirmed"
BSH_EVENT_PRESENT_STATE_OFF = "BSH.Common.EnumType.EventPresentState.Off"
BSH_OPERATION_STATE = "BSH.Common.Status.OperationState" BSH_OPERATION_STATE = "BSH.Common.Status.OperationState"
BSH_OPERATION_STATE_RUN = "BSH.Common.EnumType.OperationState.Run" BSH_OPERATION_STATE_RUN = "BSH.Common.EnumType.OperationState.Run"
@ -23,6 +26,11 @@ BSH_OPERATION_STATE_FINISHED = "BSH.Common.EnumType.OperationState.Finished"
COOKING_LIGHTING = "Cooking.Common.Setting.Lighting" COOKING_LIGHTING = "Cooking.Common.Setting.Lighting"
COOKING_LIGHTING_BRIGHTNESS = "Cooking.Common.Setting.LightingBrightness" COOKING_LIGHTING_BRIGHTNESS = "Cooking.Common.Setting.LightingBrightness"
COFFEE_EVENT_BEAN_CONTAINER_EMPTY = (
"ConsumerProducts.CoffeeMaker.Event.BeanContainerEmpty"
)
COFFEE_EVENT_WATER_TANK_EMPTY = "ConsumerProducts.CoffeeMaker.Event.WaterTankEmpty"
COFFEE_EVENT_DRIP_TRAY_FULL = "ConsumerProducts.CoffeeMaker.Event.DripTrayFull"
REFRIGERATION_SUPERMODEFREEZER = "Refrigeration.FridgeFreezer.Setting.SuperModeFreezer" REFRIGERATION_SUPERMODEFREEZER = "Refrigeration.FridgeFreezer.Setting.SuperModeFreezer"
REFRIGERATION_SUPERMODEREFRIGERATOR = ( REFRIGERATION_SUPERMODEREFRIGERATOR = (
@ -30,6 +38,24 @@ REFRIGERATION_SUPERMODEREFRIGERATOR = (
) )
REFRIGERATION_DISPENSER = "Refrigeration.Common.Setting.Dispenser.Enabled" REFRIGERATION_DISPENSER = "Refrigeration.Common.Setting.Dispenser.Enabled"
REFRIGERATION_STATUS_DOOR_CHILLER = "Refrigeration.Common.Status.Door.ChillerCommon"
REFRIGERATION_STATUS_DOOR_FREEZER = "Refrigeration.Common.Status.Door.Freezer"
REFRIGERATION_STATUS_DOOR_REFRIGERATOR = "Refrigeration.Common.Status.Door.Refrigerator"
REFRIGERATION_STATUS_DOOR_CLOSED = "Refrigeration.Common.EnumType.Door.States.Closed"
REFRIGERATION_STATUS_DOOR_OPEN = "Refrigeration.Common.EnumType.Door.States.Open"
REFRIGERATION_EVENT_DOOR_ALARM_REFRIGERATOR = (
"Refrigeration.FridgeFreezer.Event.DoorAlarmRefrigerator"
)
REFRIGERATION_EVENT_DOOR_ALARM_FREEZER = (
"Refrigeration.FridgeFreezer.Event.DoorAlarmFreezer"
)
REFRIGERATION_EVENT_TEMP_ALARM_FREEZER = (
"Refrigeration.FridgeFreezer.Event.TemperatureAlarmFreezer"
)
BSH_AMBIENT_LIGHT_ENABLED = "BSH.Common.Setting.AmbientLightEnabled" BSH_AMBIENT_LIGHT_ENABLED = "BSH.Common.Setting.AmbientLightEnabled"
BSH_AMBIENT_LIGHT_BRIGHTNESS = "BSH.Common.Setting.AmbientLightBrightness" BSH_AMBIENT_LIGHT_BRIGHTNESS = "BSH.Common.Setting.AmbientLightBrightness"
BSH_AMBIENT_LIGHT_COLOR = "BSH.Common.Setting.AmbientLightColor" BSH_AMBIENT_LIGHT_COLOR = "BSH.Common.Setting.AmbientLightColor"

View File

@ -23,6 +23,50 @@
} }
}, },
"entity": { "entity": {
"sensor": {
"alarm_sensor_fridge": {
"default": "mdi:fridge",
"state": {
"confirmed": "mdi:fridge-alert-outline",
"present": "mdi:fridge-alert"
}
},
"alarm_sensor_freezer": {
"default": "mdi:snowflake",
"state": {
"confirmed": "mdi:snowflake-check",
"present": "mdi:snowflake-alert"
}
},
"alarm_sensor_temp": {
"default": "mdi:thermometer",
"state": {
"confirmed": "mdi:thermometer-check",
"present": "mdi:thermometer-alert"
}
},
"alarm_sensor_coffee_bean_container": {
"default": "mdi:coffee-maker",
"state": {
"confirmed": "mdi:coffee-maker-check",
"present": "mdi:coffee-maker-outline"
}
},
"alarm_sensor_coffee_water_tank": {
"default": "mdi:water",
"state": {
"confirmed": "mdi:water-check",
"present": "mdi:water-alert"
}
},
"alarm_sensor_coffee_drip_tray": {
"default": "mdi:tray",
"state": {
"confirmed": "mdi:tray-full",
"present": "mdi:tray-alert"
}
}
},
"switch": { "switch": {
"refrigeration_dispenser": { "refrigeration_dispenser": {
"default": "mdi:snowflake", "default": "mdi:snowflake",

View File

@ -1,29 +1,95 @@
"""Provides a sensor for Home Connect.""" """Provides a sensor for Home Connect."""
from dataclasses import dataclass, field
from datetime import datetime, timedelta from datetime import datetime, timedelta
import logging import logging
from typing import cast from typing import cast
from homeassistant.components.sensor import SensorDeviceClass, SensorEntity from homeassistant.components.sensor import (
SensorDeviceClass,
SensorEntity,
SensorEntityDescription,
)
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_ENTITIES from homeassistant.const import CONF_ENTITIES
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
from .api import ConfigEntryAuth, HomeConnectDevice
from .const import ( from .const import (
ATTR_DEVICE,
ATTR_VALUE, ATTR_VALUE,
BSH_EVENT_PRESENT_STATE_OFF,
BSH_OPERATION_STATE, BSH_OPERATION_STATE,
BSH_OPERATION_STATE_FINISHED, BSH_OPERATION_STATE_FINISHED,
BSH_OPERATION_STATE_PAUSE, BSH_OPERATION_STATE_PAUSE,
BSH_OPERATION_STATE_RUN, BSH_OPERATION_STATE_RUN,
COFFEE_EVENT_BEAN_CONTAINER_EMPTY,
COFFEE_EVENT_DRIP_TRAY_FULL,
COFFEE_EVENT_WATER_TANK_EMPTY,
DOMAIN, DOMAIN,
REFRIGERATION_EVENT_DOOR_ALARM_FREEZER,
REFRIGERATION_EVENT_DOOR_ALARM_REFRIGERATOR,
REFRIGERATION_EVENT_TEMP_ALARM_FREEZER,
) )
from .entity import HomeConnectEntity from .entity import HomeConnectEntity
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@dataclass(frozen=True, kw_only=True)
class HomeConnectSensorEntityDescription(SensorEntityDescription):
"""Entity Description class for sensors."""
device_class: SensorDeviceClass | None = SensorDeviceClass.ENUM
options: list[str] | None = field(
default_factory=lambda: ["confirmed", "off", "present"]
)
state_key: str
appliance_types: tuple[str, ...]
SENSORS: tuple[HomeConnectSensorEntityDescription, ...] = (
HomeConnectSensorEntityDescription(
key="Door Alarm Freezer",
translation_key="alarm_sensor_freezer",
state_key=REFRIGERATION_EVENT_DOOR_ALARM_FREEZER,
appliance_types=("FridgeFreezer", "Freezer"),
),
HomeConnectSensorEntityDescription(
key="Door Alarm Refrigerator",
translation_key="alarm_sensor_fridge",
state_key=REFRIGERATION_EVENT_DOOR_ALARM_REFRIGERATOR,
appliance_types=("FridgeFreezer", "Refrigerator"),
),
HomeConnectSensorEntityDescription(
key="Temperature Alarm Freezer",
translation_key="alarm_sensor_temp",
state_key=REFRIGERATION_EVENT_TEMP_ALARM_FREEZER,
appliance_types=("FridgeFreezer", "Freezer"),
),
HomeConnectSensorEntityDescription(
key="Bean Container Empty",
translation_key="alarm_sensor_coffee_bean_container",
state_key=COFFEE_EVENT_BEAN_CONTAINER_EMPTY,
appliance_types=("CoffeeMaker",),
),
HomeConnectSensorEntityDescription(
key="Water Tank Empty",
translation_key="alarm_sensor_coffee_water_tank",
state_key=COFFEE_EVENT_WATER_TANK_EMPTY,
appliance_types=("CoffeeMaker",),
),
HomeConnectSensorEntityDescription(
key="Drip Tray Full",
translation_key="alarm_sensor_coffee_drip_tray",
state_key=COFFEE_EVENT_DRIP_TRAY_FULL,
appliance_types=("CoffeeMaker",),
),
)
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
config_entry: ConfigEntry, config_entry: ConfigEntry,
@ -34,10 +100,20 @@ async def async_setup_entry(
def get_entities(): def get_entities():
"""Get a list of entities.""" """Get a list of entities."""
entities = [] entities = []
hc_api = hass.data[DOMAIN][config_entry.entry_id] hc_api: ConfigEntryAuth = hass.data[DOMAIN][config_entry.entry_id]
for device_dict in hc_api.devices: for device_dict in hc_api.devices:
entity_dicts = device_dict.get(CONF_ENTITIES, {}).get("sensor", []) entity_dicts = device_dict.get(CONF_ENTITIES, {}).get("sensor", [])
entities += [HomeConnectSensor(**d) for d in entity_dicts] entities += [HomeConnectSensor(**d) for d in entity_dicts]
device: HomeConnectDevice = device_dict[ATTR_DEVICE]
# Auto-discover entities
entities.extend(
HomeConnectAlarmSensor(
device,
entity_description=description,
)
for description in SENSORS
if device.appliance.type in description.appliance_types
)
return entities return entities
async_add_entities(await hass.async_add_executor_job(get_entities), True) async_add_entities(await hass.async_add_executor_job(get_entities), True)
@ -101,3 +177,37 @@ class HomeConnectSensor(HomeConnectEntity, SensorEntity):
-1 -1
] ]
_LOGGER.debug("Updated, new state: %s", self._attr_native_value) _LOGGER.debug("Updated, new state: %s", self._attr_native_value)
class HomeConnectAlarmSensor(HomeConnectEntity, SensorEntity):
"""Sensor entity setup using SensorEntityDescription."""
entity_description: HomeConnectSensorEntityDescription
def __init__(
self,
device: HomeConnectDevice,
entity_description: HomeConnectSensorEntityDescription,
) -> None:
"""Initialize the entity."""
self.entity_description = entity_description
super().__init__(device, self.entity_description.key)
@property
def available(self) -> bool:
"""Return true if the sensor is available."""
return self._attr_native_value is not None
async def async_update(self) -> None:
"""Update the sensor's status."""
self._attr_native_value = (
self.device.appliance.status.get(self.entity_description.state_key, {})
.get(ATTR_VALUE, BSH_EVENT_PRESENT_STATE_OFF)
.rsplit(".", maxsplit=1)[-1]
.lower()
)
_LOGGER.debug(
"Updated: %s, new state: %s",
self._attr_unique_id,
self._attr_native_value,
)

View File

@ -1,4 +1,8 @@
{ {
"common": {
"confirmed": "Confirmed",
"present": "Present"
},
"config": { "config": {
"step": { "step": {
"pick_implementation": { "pick_implementation": {
@ -129,5 +133,45 @@
"value": { "name": "Value", "description": "Value of the setting." } "value": { "name": "Value", "description": "Value of the setting." }
} }
} }
},
"entity": {
"sensor": {
"alarm_sensor_fridge": {
"state": {
"confirmed": "[%key:component::home_connect::common::confirmed%]",
"present": "[%key:component::home_connect::common::present%]"
}
},
"alarm_sensor_freezer": {
"state": {
"confirmed": "[%key:component::home_connect::common::confirmed%]",
"present": "[%key:component::home_connect::common::present%]"
}
},
"alarm_sensor_temp": {
"state": {
"confirmed": "[%key:component::home_connect::common::confirmed%]",
"present": "[%key:component::home_connect::common::present%]"
}
},
"alarm_sensor_coffee_bean_container": {
"state": {
"confirmed": "[%key:component::home_connect::common::confirmed%]",
"present": "[%key:component::home_connect::common::present%]"
}
},
"alarm_sensor_coffee_water_tank": {
"state": {
"confirmed": "[%key:component::home_connect::common::confirmed%]",
"present": "[%key:component::home_connect::common::present%]"
}
},
"alarm_sensor_coffee_drip_tray": {
"state": {
"confirmed": "[%key:component::home_connect::common::confirmed%]",
"present": "[%key:component::home_connect::common::present%]"
}
}
}
} }
} }

View File

@ -10,6 +10,10 @@
{ {
"key": "BSH.Common.Status.DoorState", "key": "BSH.Common.Status.DoorState",
"value": "BSH.Common.EnumType.DoorState.Closed" "value": "BSH.Common.EnumType.DoorState.Closed"
},
{
"key": "Refrigeration.Common.Status.Door.Refrigerator",
"value": "BSH.Common.EnumType.DoorState.Open"
} }
] ]
} }

View File

@ -3,6 +3,7 @@
from collections.abc import Awaitable, Callable from collections.abc import Awaitable, Callable
from unittest.mock import MagicMock, Mock from unittest.mock import MagicMock, Mock
from homeconnect.api import HomeConnectAPI
import pytest import pytest
from homeassistant.components.home_connect.const import ( from homeassistant.components.home_connect.const import (
@ -10,13 +11,16 @@ from homeassistant.components.home_connect.const import (
BSH_DOOR_STATE_CLOSED, BSH_DOOR_STATE_CLOSED,
BSH_DOOR_STATE_LOCKED, BSH_DOOR_STATE_LOCKED,
BSH_DOOR_STATE_OPEN, BSH_DOOR_STATE_OPEN,
REFRIGERATION_STATUS_DOOR_CLOSED,
REFRIGERATION_STATUS_DOOR_OPEN,
REFRIGERATION_STATUS_DOOR_REFRIGERATOR,
) )
from homeassistant.config_entries import ConfigEntryState from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import Platform from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNAVAILABLE, Platform
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_component import async_update_entity from homeassistant.helpers.entity_component import async_update_entity
from tests.common import MockConfigEntry from tests.common import MockConfigEntry, load_json_object_fixture
@pytest.fixture @pytest.fixture
@ -70,3 +74,59 @@ async def test_binary_sensors_door_states(
await async_update_entity(hass, entity_id) await async_update_entity(hass, entity_id)
await hass.async_block_till_done() await hass.async_block_till_done()
assert hass.states.is_state(entity_id, expected) assert hass.states.is_state(entity_id, expected)
@pytest.mark.parametrize(
("entity_id", "status_key", "event_value_update", "expected", "appliance"),
[
(
"binary_sensor.fridgefreezer_refrigerator_door",
REFRIGERATION_STATUS_DOOR_REFRIGERATOR,
REFRIGERATION_STATUS_DOOR_CLOSED,
STATE_OFF,
"FridgeFreezer",
),
(
"binary_sensor.fridgefreezer_refrigerator_door",
REFRIGERATION_STATUS_DOOR_REFRIGERATOR,
REFRIGERATION_STATUS_DOOR_OPEN,
STATE_ON,
"FridgeFreezer",
),
(
"binary_sensor.fridgefreezer_refrigerator_door",
REFRIGERATION_STATUS_DOOR_REFRIGERATOR,
"",
STATE_UNAVAILABLE,
"FridgeFreezer",
),
],
indirect=["appliance"],
)
@pytest.mark.usefixtures("bypass_throttle")
async def test_bianry_sensors_fridge_door_states(
entity_id: str,
status_key: str,
event_value_update: str,
appliance: Mock,
expected: str,
hass: HomeAssistant,
config_entry: MockConfigEntry,
integration_setup: Callable[[], Awaitable[bool]],
setup_credentials: None,
get_appliances: MagicMock,
) -> None:
"""Tests for Home Connect Fridge appliance door states."""
appliance.status.update(
HomeConnectAPI.json2dict(
load_json_object_fixture("home_connect/status.json")["data"]["status"]
)
)
get_appliances.return_value = [appliance]
assert config_entry.state == ConfigEntryState.NOT_LOADED
assert await integration_setup()
assert config_entry.state == ConfigEntryState.LOADED
appliance.status.update({status_key: {"value": event_value_update}})
await async_update_entity(hass, entity_id)
await hass.async_block_till_done()
assert hass.states.is_state(entity_id, expected)

View File

@ -4,14 +4,22 @@ from collections.abc import Awaitable, Callable
from unittest.mock import MagicMock, Mock from unittest.mock import MagicMock, Mock
from freezegun.api import FrozenDateTimeFactory from freezegun.api import FrozenDateTimeFactory
from homeconnect.api import HomeConnectAPI
import pytest import pytest
from homeassistant.components.home_connect.const import (
BSH_EVENT_PRESENT_STATE_CONFIRMED,
BSH_EVENT_PRESENT_STATE_OFF,
BSH_EVENT_PRESENT_STATE_PRESENT,
COFFEE_EVENT_BEAN_CONTAINER_EMPTY,
REFRIGERATION_EVENT_DOOR_ALARM_FREEZER,
)
from homeassistant.config_entries import ConfigEntryState from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import Platform from homeassistant.const import Platform
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_component import async_update_entity from homeassistant.helpers.entity_component import async_update_entity
from tests.common import MockConfigEntry from tests.common import MockConfigEntry, load_json_object_fixture
TEST_HC_APP = "Dishwasher" TEST_HC_APP = "Dishwasher"
@ -207,3 +215,94 @@ async def test_remaining_prog_time_edge_cases(
await hass.async_block_till_done() await hass.async_block_till_done()
freezer.tick() freezer.tick()
assert hass.states.is_state(entity_id, expected_state) assert hass.states.is_state(entity_id, expected_state)
@pytest.mark.parametrize(
("entity_id", "status_key", "event_value_update", "expected", "appliance"),
[
(
"sensor.fridgefreezer_door_alarm_freezer",
"EVENT_NOT_IN_STATUS_YET_SO_SET_TO_OFF",
"",
"off",
"FridgeFreezer",
),
(
"sensor.fridgefreezer_door_alarm_freezer",
REFRIGERATION_EVENT_DOOR_ALARM_FREEZER,
BSH_EVENT_PRESENT_STATE_OFF,
"off",
"FridgeFreezer",
),
(
"sensor.fridgefreezer_door_alarm_freezer",
REFRIGERATION_EVENT_DOOR_ALARM_FREEZER,
BSH_EVENT_PRESENT_STATE_PRESENT,
"present",
"FridgeFreezer",
),
(
"sensor.fridgefreezer_door_alarm_freezer",
REFRIGERATION_EVENT_DOOR_ALARM_FREEZER,
BSH_EVENT_PRESENT_STATE_CONFIRMED,
"confirmed",
"FridgeFreezer",
),
(
"sensor.coffeemaker_bean_container_empty",
"EVENT_NOT_IN_STATUS_YET_SO_SET_TO_OFF",
"",
"off",
"CoffeeMaker",
),
(
"sensor.coffeemaker_bean_container_empty",
COFFEE_EVENT_BEAN_CONTAINER_EMPTY,
BSH_EVENT_PRESENT_STATE_OFF,
"off",
"CoffeeMaker",
),
(
"sensor.coffeemaker_bean_container_empty",
COFFEE_EVENT_BEAN_CONTAINER_EMPTY,
BSH_EVENT_PRESENT_STATE_PRESENT,
"present",
"CoffeeMaker",
),
(
"sensor.coffeemaker_bean_container_empty",
COFFEE_EVENT_BEAN_CONTAINER_EMPTY,
BSH_EVENT_PRESENT_STATE_CONFIRMED,
"confirmed",
"CoffeeMaker",
),
],
indirect=["appliance"],
)
@pytest.mark.usefixtures("bypass_throttle")
async def test_sensors_states(
entity_id: str,
status_key: str,
event_value_update: str,
appliance: Mock,
expected: str,
hass: HomeAssistant,
config_entry: MockConfigEntry,
integration_setup: Callable[[], Awaitable[bool]],
setup_credentials: None,
get_appliances: MagicMock,
) -> None:
"""Tests for Appliance alarm sensors."""
appliance.status.update(
HomeConnectAPI.json2dict(
load_json_object_fixture("home_connect/status.json")["data"]["status"]
)
)
get_appliances.return_value = [appliance]
assert config_entry.state == ConfigEntryState.NOT_LOADED
assert await integration_setup()
assert config_entry.state == ConfigEntryState.LOADED
appliance.status.update({status_key: {"value": event_value_update}})
await async_update_entity(hass, entity_id)
await hass.async_block_till_done()
assert hass.states.is_state(entity_id, expected)