core/homeassistant/components/lamarzocco/number.py

285 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,
Add Bluetooth support to La Marzocco integration (#108287) * init * init tests * linting * checks * tests, linting * pylint * add tests * switch tests * add water heater tests * change icons * extra args cleanup * moar tests * services tests * remove extra platforms * test for unique id * back to single instance * add diagnostics * remove extra platforms * test for unique id * back to single instance * Add better connection management for Idasen Desk (#102135) * Return 'None' for light attributes when off instead of removing them (#101946) * Bump home-assistant-bluetooth to 1.10.4 (#102268) * Bump orjson to 3.9.9 (#102267) * Bump opower to 0.0.37 (#102265) * Bump Python-Roborock to 0.35.0 (#102275) * Add CodeQL CI Job (#102273) * Remove unused dsmr sensors (#102223) * rebase messed up conftest * more tests for init * add client to coveragerc * add client to coveragerc * next lmcloud version * strict typing * more typing * allow multiple machines * remove unneeded var * Update homeassistant/components/lamarzocco/coordinator.py Co-authored-by: Robert Resch <robert@resch.dev> * Update homeassistant/components/lamarzocco/diagnostics.py Co-authored-by: Robert Resch <robert@resch.dev> * Update homeassistant/components/lamarzocco/__init__.py Co-authored-by: Robert Resch <robert@resch.dev> * PR suggestions * remove base exception * Update manifest.json * update lmcloud * update lmcloud * remove ignore * selection bugfix for machines with space in name * bugfix temps * add options flow * send out full user input * remove options flow * split the tests to avoid timeouts * use selectoptionsdict for selection * removing rccoleman * improve test coverage to 100% * Update config_flow.py Co-authored-by: Robert Resch <robert@resch.dev> * Update config_flow.py Co-authored-by: Robert Resch <robert@resch.dev> * Update config_flow.py Co-authored-by: Robert Resch <robert@resch.dev> * autoselect cloud machine for discovered machine * move default values to 3rd party lib * bring property changes from lmcloud * moving things to lmcloud * move validation to method * move more things to lmcloud * remove unused const * Update homeassistant/components/lamarzocco/coordinator.py Co-authored-by: Robert Resch <robert@resch.dev> * Update homeassistant/components/lamarzocco/coordinator.py Co-authored-by: Robert Resch <robert@resch.dev> * Update homeassistant/components/lamarzocco/__init__.py Co-authored-by: Robert Resch <robert@resch.dev> * Update homeassistant/components/lamarzocco/__init__.py Co-authored-by: Robert Resch <robert@resch.dev> * remove callback from coordinator * remove waterheater, add switch * improvement to background task * next lmcloud * adapt to lib changes * Update homeassistant/components/lamarzocco/strings.json Co-authored-by: Robert Resch <robert@resch.dev> * Update homeassistant/components/lamarzocco/entity.py Co-authored-by: Robert Resch <robert@resch.dev> * Update homeassistant/components/lamarzocco/entity.py Co-authored-by: Robert Resch <robert@resch.dev> * Update homeassistant/components/lamarzocco/switch.py Co-authored-by: Robert Resch <robert@resch.dev> * Update homeassistant/components/lamarzocco/switch.py Co-authored-by: Robert Resch <robert@resch.dev> * Update homeassistant/components/lamarzocco/entity.py Co-authored-by: Robert Resch <robert@resch.dev> * Update homeassistant/components/lamarzocco/strings.json Co-authored-by: Robert Resch <robert@resch.dev> * requested changes * Update homeassistant/components/lamarzocco/switch.py Co-authored-by: Robert Resch <robert@resch.dev> * Update homeassistant/components/lamarzocco/entity.py Co-authored-by: Robert Resch <robert@resch.dev> * Update tests/components/lamarzocco/test_config_flow.py Co-authored-by: Robert Resch <robert@resch.dev> * Update tests/components/lamarzocco/test_config_flow.py Co-authored-by: Robert Resch <robert@resch.dev> * some requested changes * changes * requested changes * move steam boiler to controls * fix: remove entities from GS3MP model + tests * remove dataclass decorator * next lmcloud version * improvements * move reauth to user step * improve config flow * remove asserts in favor of runtimeerrors * undo conftest comment * make duc return none * Update homeassistant/components/lamarzocco/switch.py Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * Update homeassistant/components/lamarzocco/entity.py Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * Update homeassistant/components/lamarzocco/config_flow.py Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * remove diagnostics, changes * refine config flow * remove runtimeerrors in favor of asserts * move initialization of lm_client to coordinator * remove things from lmclient * remove lm_client * remove lm_client * bump lm version * correctly set initialized for tests * move exception handling inside init + tests * add test for switch without bluetooth on * bump lmcloud * pass httpx client to LMLocalAPI * add call function to reduce code * switch to snapshot testing * remove bluetooth * bump version * cleanup import * remove unused const * set correct integration_type * correct default selection in CF * reduce unnecessary tests by fixture change * use other json loads helpers * move prebrew/infusion to select entity * bump lmcloud * Update coordinator.py Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * Update coordinator.py Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * Update coordinator.py Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * Update entity.py Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * Update entity.py Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * requested feedback * step description, bump lmcloud * create init integration functino * revert * ruff * remove leftover BT test * make main switch main entity * bump lmcloud * re-add bluetooth * improve * bump firmware (again) * correct test * Update homeassistant/components/lamarzocco/coordinator.py Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * Update homeassistant/components/lamarzocco/entity.py Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * Update homeassistant/components/lamarzocco/strings.json Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * separate device test * add BT to entites * fix import * docstring * minor * fix rebase * get device from discovered devices * tweak * change tests * switch to dict * switch to options * fix * fix --------- Co-authored-by: Abílio Costa <abmantis@users.noreply.github.com> Co-authored-by: Paul Bottein <paul.bottein@gmail.com> Co-authored-by: J. Nick Koston <nick@koston.org> Co-authored-by: tronikos <tronikos@users.noreply.github.com> Co-authored-by: Luke Lashley <conway220@gmail.com> Co-authored-by: Franck Nijhof <git@frenck.dev> Co-authored-by: dupondje <jean-louis@dupond.be> Co-authored-by: Robert Resch <robert@resch.dev> Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2024-03-21 12:08:11 +00:00
set_value_fn=lambda coordinator, temp: coordinator.lm.set_coffee_temp(
temp, coordinator.async_get_ble_device()
),
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,
Add Bluetooth support to La Marzocco integration (#108287) * init * init tests * linting * checks * tests, linting * pylint * add tests * switch tests * add water heater tests * change icons * extra args cleanup * moar tests * services tests * remove extra platforms * test for unique id * back to single instance * add diagnostics * remove extra platforms * test for unique id * back to single instance * Add better connection management for Idasen Desk (#102135) * Return 'None' for light attributes when off instead of removing them (#101946) * Bump home-assistant-bluetooth to 1.10.4 (#102268) * Bump orjson to 3.9.9 (#102267) * Bump opower to 0.0.37 (#102265) * Bump Python-Roborock to 0.35.0 (#102275) * Add CodeQL CI Job (#102273) * Remove unused dsmr sensors (#102223) * rebase messed up conftest * more tests for init * add client to coveragerc * add client to coveragerc * next lmcloud version * strict typing * more typing * allow multiple machines * remove unneeded var * Update homeassistant/components/lamarzocco/coordinator.py Co-authored-by: Robert Resch <robert@resch.dev> * Update homeassistant/components/lamarzocco/diagnostics.py Co-authored-by: Robert Resch <robert@resch.dev> * Update homeassistant/components/lamarzocco/__init__.py Co-authored-by: Robert Resch <robert@resch.dev> * PR suggestions * remove base exception * Update manifest.json * update lmcloud * update lmcloud * remove ignore * selection bugfix for machines with space in name * bugfix temps * add options flow * send out full user input * remove options flow * split the tests to avoid timeouts * use selectoptionsdict for selection * removing rccoleman * improve test coverage to 100% * Update config_flow.py Co-authored-by: Robert Resch <robert@resch.dev> * Update config_flow.py Co-authored-by: Robert Resch <robert@resch.dev> * Update config_flow.py Co-authored-by: Robert Resch <robert@resch.dev> * autoselect cloud machine for discovered machine * move default values to 3rd party lib * bring property changes from lmcloud * moving things to lmcloud * move validation to method * move more things to lmcloud * remove unused const * Update homeassistant/components/lamarzocco/coordinator.py Co-authored-by: Robert Resch <robert@resch.dev> * Update homeassistant/components/lamarzocco/coordinator.py Co-authored-by: Robert Resch <robert@resch.dev> * Update homeassistant/components/lamarzocco/__init__.py Co-authored-by: Robert Resch <robert@resch.dev> * Update homeassistant/components/lamarzocco/__init__.py Co-authored-by: Robert Resch <robert@resch.dev> * remove callback from coordinator * remove waterheater, add switch * improvement to background task * next lmcloud * adapt to lib changes * Update homeassistant/components/lamarzocco/strings.json Co-authored-by: Robert Resch <robert@resch.dev> * Update homeassistant/components/lamarzocco/entity.py Co-authored-by: Robert Resch <robert@resch.dev> * Update homeassistant/components/lamarzocco/entity.py Co-authored-by: Robert Resch <robert@resch.dev> * Update homeassistant/components/lamarzocco/switch.py Co-authored-by: Robert Resch <robert@resch.dev> * Update homeassistant/components/lamarzocco/switch.py Co-authored-by: Robert Resch <robert@resch.dev> * Update homeassistant/components/lamarzocco/entity.py Co-authored-by: Robert Resch <robert@resch.dev> * Update homeassistant/components/lamarzocco/strings.json Co-authored-by: Robert Resch <robert@resch.dev> * requested changes * Update homeassistant/components/lamarzocco/switch.py Co-authored-by: Robert Resch <robert@resch.dev> * Update homeassistant/components/lamarzocco/entity.py Co-authored-by: Robert Resch <robert@resch.dev> * Update tests/components/lamarzocco/test_config_flow.py Co-authored-by: Robert Resch <robert@resch.dev> * Update tests/components/lamarzocco/test_config_flow.py Co-authored-by: Robert Resch <robert@resch.dev> * some requested changes * changes * requested changes * move steam boiler to controls * fix: remove entities from GS3MP model + tests * remove dataclass decorator * next lmcloud version * improvements * move reauth to user step * improve config flow * remove asserts in favor of runtimeerrors * undo conftest comment * make duc return none * Update homeassistant/components/lamarzocco/switch.py Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * Update homeassistant/components/lamarzocco/entity.py Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * Update homeassistant/components/lamarzocco/config_flow.py Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * remove diagnostics, changes * refine config flow * remove runtimeerrors in favor of asserts * move initialization of lm_client to coordinator * remove things from lmclient * remove lm_client * remove lm_client * bump lm version * correctly set initialized for tests * move exception handling inside init + tests * add test for switch without bluetooth on * bump lmcloud * pass httpx client to LMLocalAPI * add call function to reduce code * switch to snapshot testing * remove bluetooth * bump version * cleanup import * remove unused const * set correct integration_type * correct default selection in CF * reduce unnecessary tests by fixture change * use other json loads helpers * move prebrew/infusion to select entity * bump lmcloud * Update coordinator.py Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * Update coordinator.py Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * Update coordinator.py Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * Update entity.py Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * Update entity.py Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * requested feedback * step description, bump lmcloud * create init integration functino * revert * ruff * remove leftover BT test * make main switch main entity * bump lmcloud * re-add bluetooth * improve * bump firmware (again) * correct test * Update homeassistant/components/lamarzocco/coordinator.py Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * Update homeassistant/components/lamarzocco/entity.py Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * Update homeassistant/components/lamarzocco/strings.json Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * separate device test * add BT to entites * fix import * docstring * minor * fix rebase * get device from discovered devices * tweak * change tests * switch to dict * switch to options * fix * fix --------- Co-authored-by: Abílio Costa <abmantis@users.noreply.github.com> Co-authored-by: Paul Bottein <paul.bottein@gmail.com> Co-authored-by: J. Nick Koston <nick@koston.org> Co-authored-by: tronikos <tronikos@users.noreply.github.com> Co-authored-by: Luke Lashley <conway220@gmail.com> Co-authored-by: Franck Nijhof <git@frenck.dev> Co-authored-by: dupondje <jean-louis@dupond.be> Co-authored-by: Robert Resch <robert@resch.dev> Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2024-03-21 12:08:11 +00:00
set_value_fn=lambda coordinator, temp: coordinator.lm.set_steam_temp(
int(temp), coordinator.async_get_ble_device()
),
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]
entities: list[NumberEntity] = [
LaMarzoccoNumberEntity(coordinator, description)
for description in ENTITIES
if description.supported_fn(coordinator)
]
for description in KEY_ENTITIES:
if description.supported_fn(coordinator):
num_keys = KEYS_PER_MODEL[coordinator.lm.model_name]
entities.extend(
LaMarzoccoKeyNumberEntity(coordinator, description, key)
for key in range(min(num_keys, 1), num_keys + 1)
)
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()