Make entities unavailable when machine is physically off in lamarzocco (#147426)

This commit is contained in:
Josef Zweck 2025-06-27 10:03:14 +02:00 committed by Franck Nijhof
parent 6a7385590a
commit cb359da79e
No known key found for this signature in database
GPG Key ID: AB33ADACE7101952
5 changed files with 71 additions and 13 deletions

View File

@ -2,8 +2,10 @@
from collections.abc import Callable from collections.abc import Callable
from dataclasses import dataclass from dataclasses import dataclass
from typing import cast
from pylamarzocco.const import FirmwareType from pylamarzocco.const import FirmwareType, MachineState, WidgetType
from pylamarzocco.models import MachineStatus
from homeassistant.const import CONF_ADDRESS, CONF_MAC from homeassistant.const import CONF_ADDRESS, CONF_MAC
from homeassistant.helpers.device_registry import ( from homeassistant.helpers.device_registry import (
@ -32,6 +34,7 @@ class LaMarzoccoBaseEntity(
"""Common elements for all entities.""" """Common elements for all entities."""
_attr_has_entity_name = True _attr_has_entity_name = True
_unavailable_when_machine_off = True
def __init__( def __init__(
self, self,
@ -63,6 +66,21 @@ class LaMarzoccoBaseEntity(
if connections: if connections:
self._attr_device_info.update(DeviceInfo(connections=connections)) self._attr_device_info.update(DeviceInfo(connections=connections))
@property
def available(self) -> bool:
"""Return True if entity is available."""
machine_state = (
cast(
MachineStatus,
self.coordinator.device.dashboard.config[WidgetType.CM_MACHINE_STATUS],
).status
if WidgetType.CM_MACHINE_STATUS in self.coordinator.device.dashboard.config
else MachineState.OFF
)
return super().available and not (
self._unavailable_when_machine_off and machine_state is MachineState.OFF
)
class LaMarzoccoEntity(LaMarzoccoBaseEntity): class LaMarzoccoEntity(LaMarzoccoBaseEntity):
"""Common elements for all entities.""" """Common elements for all entities."""

View File

@ -58,10 +58,6 @@ ENTITIES: tuple[LaMarzoccoNumberEntityDescription, ...] = (
CoffeeBoiler, machine.dashboard.config[WidgetType.CM_COFFEE_BOILER] CoffeeBoiler, machine.dashboard.config[WidgetType.CM_COFFEE_BOILER]
).target_temperature ).target_temperature
), ),
available_fn=(
lambda coordinator: WidgetType.CM_COFFEE_BOILER
in coordinator.device.dashboard.config
),
), ),
LaMarzoccoNumberEntityDescription( LaMarzoccoNumberEntityDescription(
key="smart_standby_time", key="smart_standby_time",

View File

@ -57,10 +57,6 @@ ENTITIES: tuple[LaMarzoccoSensorEntityDescription, ...] = (
).ready_start_time ).ready_start_time
), ),
entity_category=EntityCategory.DIAGNOSTIC, entity_category=EntityCategory.DIAGNOSTIC,
available_fn=(
lambda coordinator: WidgetType.CM_COFFEE_BOILER
in coordinator.device.dashboard.config
),
), ),
LaMarzoccoSensorEntityDescription( LaMarzoccoSensorEntityDescription(
key="steam_boiler_ready_time", key="steam_boiler_ready_time",
@ -188,6 +184,8 @@ class LaMarzoccoSensorEntity(LaMarzoccoEntity, SensorEntity):
class LaMarzoccoStatisticSensorEntity(LaMarzoccoSensorEntity): class LaMarzoccoStatisticSensorEntity(LaMarzoccoSensorEntity):
"""Sensor for La Marzocco statistics.""" """Sensor for La Marzocco statistics."""
_unavailable_when_machine_off = False
@property @property
def native_value(self) -> StateType | datetime | None: def native_value(self) -> StateType | datetime | None:
"""Return the value of the sensor.""" """Return the value of the sensor."""

View File

@ -2,11 +2,11 @@
from unittest.mock import MagicMock, patch from unittest.mock import MagicMock, patch
from pylamarzocco.const import ModelName from pylamarzocco.const import MachineState, ModelName, WidgetType
import pytest import pytest
from syrupy.assertion import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
from homeassistant.const import Platform from homeassistant.const import STATE_UNAVAILABLE, Platform
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er from homeassistant.helpers import entity_registry as er
@ -52,3 +52,27 @@ async def test_steam_ready_entity_for_all_machines(
entry = entity_registry.async_get(state.entity_id) entry = entity_registry.async_get(state.entity_id)
assert entry assert entry
async def test_sensors_unavailable_if_machine_off(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
mock_lamarzocco: MagicMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test the La Marzocco switches are unavailable when the device is offline."""
SWITCHES_UNAVAILABLE = (
("sensor.gs012345_steam_boiler_ready_time", True),
("sensor.gs012345_coffee_boiler_ready_time", True),
("sensor.gs012345_total_coffees_made", False),
)
mock_lamarzocco.dashboard.config[
WidgetType.CM_MACHINE_STATUS
].status = MachineState.OFF
with patch("homeassistant.components.lamarzocco.PLATFORMS", [Platform.SENSOR]):
await async_init_integration(hass, mock_config_entry)
for sensor, available in SWITCHES_UNAVAILABLE:
state = hass.states.get(sensor)
assert state
assert (state.state == STATE_UNAVAILABLE) == available

View File

@ -3,7 +3,7 @@
from typing import Any from typing import Any
from unittest.mock import MagicMock, patch from unittest.mock import MagicMock, patch
from pylamarzocco.const import SmartStandByType from pylamarzocco.const import MachineState, SmartStandByType, WidgetType
from pylamarzocco.exceptions import RequestNotSuccessful from pylamarzocco.exceptions import RequestNotSuccessful
import pytest import pytest
from syrupy.assertion import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
@ -13,7 +13,7 @@ from homeassistant.components.switch import (
SERVICE_TURN_OFF, SERVICE_TURN_OFF,
SERVICE_TURN_ON, SERVICE_TURN_ON,
) )
from homeassistant.const import ATTR_ENTITY_ID, Platform from homeassistant.const import ATTR_ENTITY_ID, STATE_UNAVAILABLE, Platform
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import entity_registry as er from homeassistant.helpers import entity_registry as er
@ -197,3 +197,25 @@ async def test_switch_exceptions(
blocking=True, blocking=True,
) )
assert exc_info.value.translation_key == "auto_on_off_error" assert exc_info.value.translation_key == "auto_on_off_error"
async def test_switches_unavailable_if_machine_off(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
mock_lamarzocco: MagicMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test the La Marzocco switches are unavailable when the device is offline."""
mock_lamarzocco.dashboard.config[
WidgetType.CM_MACHINE_STATUS
].status = MachineState.OFF
with patch("homeassistant.components.lamarzocco.PLATFORMS", [Platform.SWITCH]):
await async_init_integration(hass, mock_config_entry)
switches = er.async_entries_for_config_entry(
entity_registry, mock_config_entry.entry_id
)
for switch in switches:
state = hass.states.get(switch.entity_id)
assert state
assert state.state == STATE_UNAVAILABLE