core/homeassistant/components/lamarzocco/number.py

282 lines
9.4 KiB
Python
Raw Normal View History

"""Number platform for La Marzocco espresso machines."""
from collections.abc import Callable, Coroutine
from dataclasses import dataclass
from typing import Any
from lmcloud import LMCloud as LaMarzoccoClient
from lmcloud.const import KEYS_PER_MODEL, LaMarzoccoModel
from homeassistant.components.number import (
NumberDeviceClass,
NumberEntity,
NumberEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
PRECISION_TENTHS,
PRECISION_WHOLE,
EntityCategory,
UnitOfTemperature,
UnitOfTime,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DOMAIN
from .coordinator import LaMarzoccoUpdateCoordinator
from .entity import LaMarzoccoEntity, LaMarzoccoEntityDescription
@dataclass(frozen=True, kw_only=True)
class LaMarzoccoNumberEntityDescription(
LaMarzoccoEntityDescription,
NumberEntityDescription,
):
"""Description of a La Marzocco number entity."""
native_value_fn: Callable[[LaMarzoccoClient], float | int]
set_value_fn: Callable[
[LaMarzoccoUpdateCoordinator, float | int], Coroutine[Any, Any, bool]
]
@dataclass(frozen=True, kw_only=True)
class LaMarzoccoKeyNumberEntityDescription(
LaMarzoccoEntityDescription,
NumberEntityDescription,
):
"""Description of an La Marzocco number entity with keys."""
native_value_fn: Callable[[LaMarzoccoClient, int], float | int]
set_value_fn: Callable[
[LaMarzoccoClient, float | int, int], Coroutine[Any, Any, bool]
]
ENTITIES: tuple[LaMarzoccoNumberEntityDescription, ...] = (
LaMarzoccoNumberEntityDescription(
key="coffee_temp",
translation_key="coffee_temp",
device_class=NumberDeviceClass.TEMPERATURE,
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
native_step=PRECISION_TENTHS,
native_min_value=85,
native_max_value=104,
set_value_fn=lambda coordinator, temp: coordinator.lm.set_coffee_temp(temp),
native_value_fn=lambda lm: lm.current_status["coffee_set_temp"],
),
LaMarzoccoNumberEntityDescription(
key="steam_temp",
translation_key="steam_temp",
device_class=NumberDeviceClass.TEMPERATURE,
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
native_step=PRECISION_WHOLE,
native_min_value=126,
native_max_value=131,
set_value_fn=lambda coordinator, temp: coordinator.lm.set_steam_temp(int(temp)),
native_value_fn=lambda lm: lm.current_status["steam_set_temp"],
supported_fn=lambda coordinator: coordinator.lm.model_name
in (
LaMarzoccoModel.GS3_AV,
LaMarzoccoModel.GS3_MP,
),
),
LaMarzoccoNumberEntityDescription(
key="tea_water_duration",
translation_key="tea_water_duration",
device_class=NumberDeviceClass.DURATION,
native_unit_of_measurement=UnitOfTime.SECONDS,
native_step=PRECISION_WHOLE,
native_min_value=0,
native_max_value=30,
set_value_fn=lambda coordinator, value: coordinator.lm.set_dose_hot_water(
value=int(value)
),
2024-02-04 10:29:32 +00:00
native_value_fn=lambda lm: lm.current_status["dose_hot_water"],
supported_fn=lambda coordinator: coordinator.lm.model_name
in (
LaMarzoccoModel.GS3_AV,
LaMarzoccoModel.GS3_MP,
),
),
)
async def _set_prebrew_on(
lm: LaMarzoccoClient,
value: float,
key: int,
) -> bool:
return await lm.configure_prebrew(
on_time=int(value * 1000),
off_time=int(lm.current_status[f"prebrewing_toff_k{key}"] * 1000),
key=key,
)
async def _set_prebrew_off(
lm: LaMarzoccoClient,
value: float,
key: int,
) -> bool:
return await lm.configure_prebrew(
on_time=int(lm.current_status[f"prebrewing_ton_k{key}"] * 1000),
off_time=int(value * 1000),
key=key,
)
async def _set_preinfusion(
lm: LaMarzoccoClient,
value: float,
key: int,
) -> bool:
return await lm.configure_prebrew(
off_time=int(value * 1000),
key=key,
)
KEY_ENTITIES: tuple[LaMarzoccoKeyNumberEntityDescription, ...] = (
LaMarzoccoKeyNumberEntityDescription(
key="prebrew_off",
translation_key="prebrew_off",
device_class=NumberDeviceClass.DURATION,
native_unit_of_measurement=UnitOfTime.SECONDS,
native_step=PRECISION_TENTHS,
native_min_value=1,
native_max_value=10,
entity_category=EntityCategory.CONFIG,
set_value_fn=_set_prebrew_off,
native_value_fn=lambda lm, key: lm.current_status[f"prebrewing_ton_k{key}"],
available_fn=lambda lm: lm.current_status["enable_prebrewing"],
supported_fn=lambda coordinator: coordinator.lm.model_name
!= LaMarzoccoModel.GS3_MP,
),
LaMarzoccoKeyNumberEntityDescription(
key="prebrew_on",
translation_key="prebrew_on",
device_class=NumberDeviceClass.DURATION,
native_unit_of_measurement=UnitOfTime.SECONDS,
native_step=PRECISION_TENTHS,
native_min_value=2,
native_max_value=10,
entity_category=EntityCategory.CONFIG,
set_value_fn=_set_prebrew_on,
native_value_fn=lambda lm, key: lm.current_status[f"prebrewing_toff_k{key}"],
available_fn=lambda lm: lm.current_status["enable_prebrewing"],
supported_fn=lambda coordinator: coordinator.lm.model_name
!= LaMarzoccoModel.GS3_MP,
),
LaMarzoccoKeyNumberEntityDescription(
key="preinfusion_off",
translation_key="preinfusion_off",
device_class=NumberDeviceClass.DURATION,
native_unit_of_measurement=UnitOfTime.SECONDS,
native_step=PRECISION_TENTHS,
native_min_value=2,
native_max_value=29,
entity_category=EntityCategory.CONFIG,
set_value_fn=_set_preinfusion,
native_value_fn=lambda lm, key: lm.current_status[f"preinfusion_k{key}"],
available_fn=lambda lm: lm.current_status["enable_preinfusion"],
supported_fn=lambda coordinator: coordinator.lm.model_name
!= LaMarzoccoModel.GS3_MP,
),
LaMarzoccoKeyNumberEntityDescription(
key="dose",
translation_key="dose",
native_unit_of_measurement="ticks",
native_step=PRECISION_WHOLE,
native_min_value=0,
native_max_value=999,
entity_category=EntityCategory.CONFIG,
set_value_fn=lambda lm, ticks, key: lm.set_dose(key=key, value=int(ticks)),
native_value_fn=lambda lm, key: lm.current_status[f"dose_k{key}"],
supported_fn=lambda coordinator: coordinator.lm.model_name
== LaMarzoccoModel.GS3_AV,
),
)
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up number entities."""
coordinator = hass.data[DOMAIN][config_entry.entry_id]
async_add_entities(
LaMarzoccoNumberEntity(coordinator, description)
for description in ENTITIES
if description.supported_fn(coordinator)
)
entities: list[LaMarzoccoKeyNumberEntity] = []
for description in KEY_ENTITIES:
if description.supported_fn(coordinator):
num_keys = KEYS_PER_MODEL[coordinator.lm.model_name]
for key in range(min(num_keys, 1), num_keys + 1):
entities.append(
LaMarzoccoKeyNumberEntity(coordinator, description, key)
)
async_add_entities(entities)
class LaMarzoccoNumberEntity(LaMarzoccoEntity, NumberEntity):
"""La Marzocco number entity."""
entity_description: LaMarzoccoNumberEntityDescription
@property
def native_value(self) -> float:
"""Return the current value."""
return self.entity_description.native_value_fn(self.coordinator.lm)
async def async_set_native_value(self, value: float) -> None:
"""Set the value."""
await self.entity_description.set_value_fn(self.coordinator, value)
self.async_write_ha_state()
class LaMarzoccoKeyNumberEntity(LaMarzoccoEntity, NumberEntity):
"""Number representing espresso machine with key support."""
entity_description: LaMarzoccoKeyNumberEntityDescription
def __init__(
self,
coordinator: LaMarzoccoUpdateCoordinator,
description: LaMarzoccoKeyNumberEntityDescription,
pyhsical_key: int,
) -> None:
"""Initialize the entity."""
super().__init__(coordinator, description)
# Physical Key on the machine the entity represents.
if pyhsical_key == 0:
pyhsical_key = 1
else:
self._attr_translation_key = f"{description.translation_key}_key"
self._attr_translation_placeholders = {"key": str(pyhsical_key)}
self._attr_unique_id = f"{super()._attr_unique_id}_key{pyhsical_key}"
self._attr_entity_registry_enabled_default = False
self.pyhsical_key = pyhsical_key
@property
def native_value(self) -> float:
"""Return the current value."""
return self.entity_description.native_value_fn(
self.coordinator.lm, self.pyhsical_key
)
async def async_set_native_value(self, value: float) -> None:
"""Set the value."""
await self.entity_description.set_value_fn(
self.coordinator.lm, value, self.pyhsical_key
)
self.async_write_ha_state()