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 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.helpers.device_registry import (
@ -32,6 +34,7 @@ class LaMarzoccoBaseEntity(
"""Common elements for all entities."""
_attr_has_entity_name = True
_unavailable_when_machine_off = True
def __init__(
self,
@ -63,6 +66,21 @@ class LaMarzoccoBaseEntity(
if 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):
"""Common elements for all entities."""

View File

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

View File

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

View File

@ -2,11 +2,11 @@
from unittest.mock import MagicMock, patch
from pylamarzocco.const import ModelName
from pylamarzocco.const import MachineState, ModelName, WidgetType
import pytest
from syrupy.assertion import SnapshotAssertion
from homeassistant.const import Platform
from homeassistant.const import STATE_UNAVAILABLE, Platform
from homeassistant.core import HomeAssistant
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)
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 unittest.mock import MagicMock, patch
from pylamarzocco.const import SmartStandByType
from pylamarzocco.const import MachineState, SmartStandByType, WidgetType
from pylamarzocco.exceptions import RequestNotSuccessful
import pytest
from syrupy.assertion import SnapshotAssertion
@ -13,7 +13,7 @@ from homeassistant.components.switch import (
SERVICE_TURN_OFF,
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.exceptions import HomeAssistantError
from homeassistant.helpers import entity_registry as er
@ -197,3 +197,25 @@ async def test_switch_exceptions(
blocking=True,
)
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