Add sensors for drink stats per key to lamarzocco (#136582)
* Add sensors for drink stats per key to lamarzocco * Add icon * Use UOM translations * fix tests * remove translation key * Update sensor.py Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> --------- Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>pull/136998/head
parent
cde59613a5
commit
f21ab24b8b
|
@ -95,6 +95,9 @@
|
|||
"drink_stats_flushing": {
|
||||
"default": "mdi:chart-line"
|
||||
},
|
||||
"drink_stats_coffee_key": {
|
||||
"default": "mdi:chart-scatter-plot"
|
||||
},
|
||||
"shot_timer": {
|
||||
"default": "mdi:timer"
|
||||
},
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
|
||||
from pylamarzocco.const import BoilerType, MachineModel
|
||||
from pylamarzocco.const import KEYS_PER_MODEL, BoilerType, MachineModel, PhysicalKey
|
||||
from pylamarzocco.devices.machine import LaMarzoccoMachine
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
|
@ -21,7 +21,7 @@ from homeassistant.const import (
|
|||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .coordinator import LaMarzoccoConfigEntry
|
||||
from .coordinator import LaMarzoccoConfigEntry, LaMarzoccoUpdateCoordinator
|
||||
from .entity import LaMarzoccoEntity, LaMarzoccoEntityDescription, LaMarzoccScaleEntity
|
||||
|
||||
# Coordinator is used to centralize the data updates
|
||||
|
@ -37,6 +37,15 @@ class LaMarzoccoSensorEntityDescription(
|
|||
value_fn: Callable[[LaMarzoccoMachine], float | int]
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class LaMarzoccoKeySensorEntityDescription(
|
||||
LaMarzoccoEntityDescription, SensorEntityDescription
|
||||
):
|
||||
"""Description of a keyed La Marzocco sensor."""
|
||||
|
||||
value_fn: Callable[[LaMarzoccoMachine, PhysicalKey], int | None]
|
||||
|
||||
|
||||
ENTITIES: tuple[LaMarzoccoSensorEntityDescription, ...] = (
|
||||
LaMarzoccoSensorEntityDescription(
|
||||
key="shot_timer",
|
||||
|
@ -79,7 +88,6 @@ STATISTIC_ENTITIES: tuple[LaMarzoccoSensorEntityDescription, ...] = (
|
|||
LaMarzoccoSensorEntityDescription(
|
||||
key="drink_stats_coffee",
|
||||
translation_key="drink_stats_coffee",
|
||||
native_unit_of_measurement="drinks",
|
||||
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||
value_fn=lambda device: device.statistics.total_coffee,
|
||||
available_fn=lambda device: len(device.statistics.drink_stats) > 0,
|
||||
|
@ -88,7 +96,6 @@ STATISTIC_ENTITIES: tuple[LaMarzoccoSensorEntityDescription, ...] = (
|
|||
LaMarzoccoSensorEntityDescription(
|
||||
key="drink_stats_flushing",
|
||||
translation_key="drink_stats_flushing",
|
||||
native_unit_of_measurement="drinks",
|
||||
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||
value_fn=lambda device: device.statistics.total_flushes,
|
||||
available_fn=lambda device: len(device.statistics.drink_stats) > 0,
|
||||
|
@ -96,6 +103,18 @@ STATISTIC_ENTITIES: tuple[LaMarzoccoSensorEntityDescription, ...] = (
|
|||
),
|
||||
)
|
||||
|
||||
KEY_STATISTIC_ENTITIES: tuple[LaMarzoccoKeySensorEntityDescription, ...] = (
|
||||
LaMarzoccoKeySensorEntityDescription(
|
||||
key="drink_stats_coffee_key",
|
||||
translation_key="drink_stats_coffee_key",
|
||||
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||
value_fn=lambda device, key: device.statistics.drink_stats.get(key),
|
||||
available_fn=lambda device: len(device.statistics.drink_stats) > 0,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
)
|
||||
|
||||
SCALE_ENTITIES: tuple[LaMarzoccoSensorEntityDescription, ...] = (
|
||||
LaMarzoccoSensorEntityDescription(
|
||||
key="scale_battery",
|
||||
|
@ -120,6 +139,8 @@ async def async_setup_entry(
|
|||
"""Set up sensor entities."""
|
||||
config_coordinator = entry.runtime_data.config_coordinator
|
||||
|
||||
entities: list[LaMarzoccoSensorEntity | LaMarzoccoKeySensorEntity] = []
|
||||
|
||||
entities = [
|
||||
LaMarzoccoSensorEntity(config_coordinator, description)
|
||||
for description in ENTITIES
|
||||
|
@ -142,6 +163,14 @@ async def async_setup_entry(
|
|||
if description.supported_fn(statistics_coordinator)
|
||||
)
|
||||
|
||||
num_keys = KEYS_PER_MODEL[MachineModel(config_coordinator.device.model)]
|
||||
if num_keys > 0:
|
||||
entities.extend(
|
||||
LaMarzoccoKeySensorEntity(statistics_coordinator, description, key)
|
||||
for description in KEY_STATISTIC_ENTITIES
|
||||
for key in range(1, num_keys + 1)
|
||||
)
|
||||
|
||||
def _async_add_new_scale() -> None:
|
||||
async_add_entities(
|
||||
LaMarzoccoScaleSensorEntity(config_coordinator, description)
|
||||
|
@ -159,11 +188,36 @@ class LaMarzoccoSensorEntity(LaMarzoccoEntity, SensorEntity):
|
|||
entity_description: LaMarzoccoSensorEntityDescription
|
||||
|
||||
@property
|
||||
def native_value(self) -> int | float:
|
||||
def native_value(self) -> int | float | None:
|
||||
"""State of the sensor."""
|
||||
return self.entity_description.value_fn(self.coordinator.device)
|
||||
|
||||
|
||||
class LaMarzoccoKeySensorEntity(LaMarzoccoEntity, SensorEntity):
|
||||
"""Sensor for a La Marzocco key."""
|
||||
|
||||
entity_description: LaMarzoccoKeySensorEntityDescription
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: LaMarzoccoUpdateCoordinator,
|
||||
description: LaMarzoccoKeySensorEntityDescription,
|
||||
key: int,
|
||||
) -> None:
|
||||
"""Initialize the sensor."""
|
||||
super().__init__(coordinator, description)
|
||||
self.key = key
|
||||
self._attr_translation_placeholders = {"key": str(key)}
|
||||
self._attr_unique_id = f"{super()._attr_unique_id}_key{key}"
|
||||
|
||||
@property
|
||||
def native_value(self) -> int | None:
|
||||
"""State of the sensor."""
|
||||
return self.entity_description.value_fn(
|
||||
self.coordinator.device, PhysicalKey(self.key)
|
||||
)
|
||||
|
||||
|
||||
class LaMarzoccoScaleSensorEntity(LaMarzoccoSensorEntity, LaMarzoccScaleEntity):
|
||||
"""Sensor for a La Marzocco scale."""
|
||||
|
||||
|
|
|
@ -175,10 +175,16 @@
|
|||
"name": "Current steam temperature"
|
||||
},
|
||||
"drink_stats_coffee": {
|
||||
"name": "Total coffees made"
|
||||
"name": "Total coffees made",
|
||||
"unit_of_measurement": "coffees"
|
||||
},
|
||||
"drink_stats_coffee_key": {
|
||||
"name": "Coffees made Key {key}",
|
||||
"unit_of_measurement": "coffees"
|
||||
},
|
||||
"drink_stats_flushing": {
|
||||
"name": "Total flushes made"
|
||||
"name": "Total flushes made",
|
||||
"unit_of_measurement": "flushes"
|
||||
},
|
||||
"shot_timer": {
|
||||
"name": "Shot timer"
|
||||
|
|
|
@ -50,6 +50,206 @@
|
|||
'unit_of_measurement': '%',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.gs012345_coffees_made_key_1-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||
'entity_id': 'sensor.gs012345_coffees_made_key_1',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Coffees made Key 1',
|
||||
'platform': 'lamarzocco',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'drink_stats_coffee_key',
|
||||
'unique_id': 'GS012345_drink_stats_coffee_key_key1',
|
||||
'unit_of_measurement': 'coffees',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.gs012345_coffees_made_key_1-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'GS012345 Coffees made Key 1',
|
||||
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
|
||||
'unit_of_measurement': 'coffees',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.gs012345_coffees_made_key_1',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '1047',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.gs012345_coffees_made_key_2-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||
'entity_id': 'sensor.gs012345_coffees_made_key_2',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Coffees made Key 2',
|
||||
'platform': 'lamarzocco',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'drink_stats_coffee_key',
|
||||
'unique_id': 'GS012345_drink_stats_coffee_key_key2',
|
||||
'unit_of_measurement': 'coffees',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.gs012345_coffees_made_key_2-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'GS012345 Coffees made Key 2',
|
||||
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
|
||||
'unit_of_measurement': 'coffees',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.gs012345_coffees_made_key_2',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '560',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.gs012345_coffees_made_key_3-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||
'entity_id': 'sensor.gs012345_coffees_made_key_3',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Coffees made Key 3',
|
||||
'platform': 'lamarzocco',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'drink_stats_coffee_key',
|
||||
'unique_id': 'GS012345_drink_stats_coffee_key_key3',
|
||||
'unit_of_measurement': 'coffees',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.gs012345_coffees_made_key_3-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'GS012345 Coffees made Key 3',
|
||||
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
|
||||
'unit_of_measurement': 'coffees',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.gs012345_coffees_made_key_3',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '468',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.gs012345_coffees_made_key_4-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||
'entity_id': 'sensor.gs012345_coffees_made_key_4',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Coffees made Key 4',
|
||||
'platform': 'lamarzocco',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'drink_stats_coffee_key',
|
||||
'unique_id': 'GS012345_drink_stats_coffee_key_key4',
|
||||
'unit_of_measurement': 'coffees',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.gs012345_coffees_made_key_4-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'GS012345 Coffees made Key 4',
|
||||
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
|
||||
'unit_of_measurement': 'coffees',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.gs012345_coffees_made_key_4',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '312',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.gs012345_current_coffee_temperature-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
|
@ -241,7 +441,7 @@
|
|||
'supported_features': 0,
|
||||
'translation_key': 'drink_stats_coffee',
|
||||
'unique_id': 'GS012345_drink_stats_coffee',
|
||||
'unit_of_measurement': 'drinks',
|
||||
'unit_of_measurement': 'coffees',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.gs012345_total_coffees_made-state]
|
||||
|
@ -249,7 +449,7 @@
|
|||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'GS012345 Total coffees made',
|
||||
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
|
||||
'unit_of_measurement': 'drinks',
|
||||
'unit_of_measurement': 'coffees',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.gs012345_total_coffees_made',
|
||||
|
@ -291,7 +491,7 @@
|
|||
'supported_features': 0,
|
||||
'translation_key': 'drink_stats_flushing',
|
||||
'unique_id': 'GS012345_drink_stats_flushing',
|
||||
'unit_of_measurement': 'drinks',
|
||||
'unit_of_measurement': 'flushes',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.gs012345_total_flushes_made-state]
|
||||
|
@ -299,7 +499,7 @@
|
|||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'GS012345 Total flushes made',
|
||||
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
|
||||
'unit_of_measurement': 'drinks',
|
||||
'unit_of_measurement': 'flushes',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.gs012345_total_flushes_made',
|
||||
|
|
|
@ -18,6 +18,7 @@ from . import async_init_integration
|
|||
from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||
async def test_sensors(
|
||||
hass: HomeAssistant,
|
||||
mock_lamarzocco: MagicMock,
|
||||
|
|
Loading…
Reference in New Issue