mirror of
https://github.com/home-assistant/core.git
synced 2025-07-03 11:27:05 +00:00

* 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>
285 lines
9.4 KiB
Python
285 lines
9.4 KiB
Python
"""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, 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,
|
|
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)
|
|
),
|
|
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()
|