mirror of
https://github.com/home-assistant/core.git
synced 2025-07-09 22:37:11 +00:00
Add statistic entities to lamarzocco (#143415)
* Bump pylamarzocco to 2.0.0b2 * Add statistic entities to lamarzocco * add icons * Update coordinator.py * update uom * Update homeassistant/components/lamarzocco/sensor.py Co-authored-by: Simon Lamon <32477463+silamon@users.noreply.github.com> * revert cups * remove unnecessary call (for now) --------- Co-authored-by: Simon Lamon <32477463+silamon@users.noreply.github.com>
This commit is contained in:
parent
05f393560f
commit
d657298791
@ -32,6 +32,7 @@ from .coordinator import (
|
||||
LaMarzoccoRuntimeData,
|
||||
LaMarzoccoScheduleUpdateCoordinator,
|
||||
LaMarzoccoSettingsUpdateCoordinator,
|
||||
LaMarzoccoStatisticsUpdateCoordinator,
|
||||
)
|
||||
|
||||
PLATFORMS = [
|
||||
@ -140,12 +141,14 @@ async def async_setup_entry(hass: HomeAssistant, entry: LaMarzoccoConfigEntry) -
|
||||
LaMarzoccoConfigUpdateCoordinator(hass, entry, device),
|
||||
LaMarzoccoSettingsUpdateCoordinator(hass, entry, device),
|
||||
LaMarzoccoScheduleUpdateCoordinator(hass, entry, device),
|
||||
LaMarzoccoStatisticsUpdateCoordinator(hass, entry, device),
|
||||
)
|
||||
|
||||
await asyncio.gather(
|
||||
coordinators.config_coordinator.async_config_entry_first_refresh(),
|
||||
coordinators.settings_coordinator.async_config_entry_first_refresh(),
|
||||
coordinators.schedule_coordinator.async_config_entry_first_refresh(),
|
||||
coordinators.statistics_coordinator.async_config_entry_first_refresh(),
|
||||
)
|
||||
|
||||
entry.runtime_data = coordinators
|
||||
|
@ -22,6 +22,7 @@ from .const import DOMAIN
|
||||
SCAN_INTERVAL = timedelta(seconds=15)
|
||||
SETTINGS_UPDATE_INTERVAL = timedelta(hours=1)
|
||||
SCHEDULE_UPDATE_INTERVAL = timedelta(minutes=5)
|
||||
STATISTICS_UPDATE_INTERVAL = timedelta(minutes=15)
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -32,6 +33,7 @@ class LaMarzoccoRuntimeData:
|
||||
config_coordinator: LaMarzoccoConfigUpdateCoordinator
|
||||
settings_coordinator: LaMarzoccoSettingsUpdateCoordinator
|
||||
schedule_coordinator: LaMarzoccoScheduleUpdateCoordinator
|
||||
statistics_coordinator: LaMarzoccoStatisticsUpdateCoordinator
|
||||
|
||||
|
||||
type LaMarzoccoConfigEntry = ConfigEntry[LaMarzoccoRuntimeData]
|
||||
@ -130,3 +132,14 @@ class LaMarzoccoScheduleUpdateCoordinator(LaMarzoccoUpdateCoordinator):
|
||||
"""Fetch data from API endpoint."""
|
||||
await self.device.get_schedule()
|
||||
_LOGGER.debug("Current schedule: %s", self.device.schedule.to_dict())
|
||||
|
||||
|
||||
class LaMarzoccoStatisticsUpdateCoordinator(LaMarzoccoUpdateCoordinator):
|
||||
"""Coordinator for La Marzocco statistics."""
|
||||
|
||||
_default_update_interval = STATISTICS_UPDATE_INTERVAL
|
||||
|
||||
async def _internal_async_update_data(self) -> None:
|
||||
"""Fetch data from API endpoint."""
|
||||
await self.device.get_coffee_and_flush_counter()
|
||||
_LOGGER.debug("Current statistics: %s", self.device.statistics.to_dict())
|
||||
|
@ -81,6 +81,12 @@
|
||||
},
|
||||
"steam_boiler_ready_time": {
|
||||
"default": "mdi:av-timer"
|
||||
},
|
||||
"total_coffees_made": {
|
||||
"default": "mdi:coffee"
|
||||
},
|
||||
"total_flushes_done": {
|
||||
"default": "mdi:water-pump"
|
||||
}
|
||||
},
|
||||
"switch": {
|
||||
|
@ -9,6 +9,7 @@ from pylamarzocco.const import ModelName, WidgetType
|
||||
from pylamarzocco.models import (
|
||||
BackFlush,
|
||||
BaseWidgetOutput,
|
||||
CoffeeAndFlushCounter,
|
||||
CoffeeBoiler,
|
||||
SteamBoilerLevel,
|
||||
SteamBoilerTemperature,
|
||||
@ -18,6 +19,7 @@ from homeassistant.components.sensor import (
|
||||
SensorDeviceClass,
|
||||
SensorEntity,
|
||||
SensorEntityDescription,
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant
|
||||
@ -98,6 +100,31 @@ ENTITIES: tuple[LaMarzoccoSensorEntityDescription, ...] = (
|
||||
),
|
||||
)
|
||||
|
||||
STATISTIC_ENTITIES: tuple[LaMarzoccoSensorEntityDescription, ...] = (
|
||||
LaMarzoccoSensorEntityDescription(
|
||||
key="drink_stats_coffee",
|
||||
translation_key="total_coffees_made",
|
||||
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||
value_fn=(
|
||||
lambda statistics: cast(
|
||||
CoffeeAndFlushCounter, statistics[WidgetType.COFFEE_AND_FLUSH_COUNTER]
|
||||
).total_coffee
|
||||
),
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
LaMarzoccoSensorEntityDescription(
|
||||
key="drink_stats_flushing",
|
||||
translation_key="total_flushes_done",
|
||||
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||
value_fn=(
|
||||
lambda statistics: cast(
|
||||
CoffeeAndFlushCounter, statistics[WidgetType.COFFEE_AND_FLUSH_COUNTER]
|
||||
).total_flush
|
||||
),
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
@ -107,15 +134,21 @@ async def async_setup_entry(
|
||||
"""Set up sensor entities."""
|
||||
coordinator = entry.runtime_data.config_coordinator
|
||||
|
||||
async_add_entities(
|
||||
entities = [
|
||||
LaMarzoccoSensorEntity(coordinator, description)
|
||||
for description in ENTITIES
|
||||
if description.supported_fn(coordinator)
|
||||
]
|
||||
entities.extend(
|
||||
LaMarzoccoStatisticSensorEntity(coordinator, description)
|
||||
for description in STATISTIC_ENTITIES
|
||||
if description.supported_fn(coordinator)
|
||||
)
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
class LaMarzoccoSensorEntity(LaMarzoccoEntity, SensorEntity):
|
||||
"""Sensor representing espresso machine water reservoir status."""
|
||||
"""Sensor for La Marzocco."""
|
||||
|
||||
entity_description: LaMarzoccoSensorEntityDescription
|
||||
|
||||
@ -125,3 +158,14 @@ class LaMarzoccoSensorEntity(LaMarzoccoEntity, SensorEntity):
|
||||
return self.entity_description.value_fn(
|
||||
self.coordinator.device.dashboard.config
|
||||
)
|
||||
|
||||
|
||||
class LaMarzoccoStatisticSensorEntity(LaMarzoccoSensorEntity):
|
||||
"""Sensor for La Marzocco statistics."""
|
||||
|
||||
@property
|
||||
def native_value(self) -> StateType | datetime | None:
|
||||
"""Return the value of the sensor."""
|
||||
return self.entity_description.value_fn(
|
||||
self.coordinator.device.statistics.widgets
|
||||
)
|
||||
|
@ -147,6 +147,14 @@
|
||||
"steam_boiler_ready_time": {
|
||||
"name": "Steam boiler ready time"
|
||||
},
|
||||
"total_coffees_made": {
|
||||
"name": "Total coffees made",
|
||||
"unit_of_measurement": "coffees"
|
||||
},
|
||||
"total_flushes_done": {
|
||||
"name": "Total flushes done",
|
||||
"unit_of_measurement": "flushes"
|
||||
},
|
||||
"last_cleaning_time": {
|
||||
"name": "Last cleaning time"
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ from pylamarzocco.models import (
|
||||
ThingDashboardConfig,
|
||||
ThingSchedulingSettings,
|
||||
ThingSettings,
|
||||
ThingStatistics,
|
||||
)
|
||||
import pytest
|
||||
|
||||
@ -91,6 +92,7 @@ def mock_lamarzocco(device_fixture: ModelName) -> Generator[MagicMock]:
|
||||
config = load_json_object_fixture("config_gs3.json", DOMAIN)
|
||||
schedule = load_json_object_fixture("schedule.json", DOMAIN)
|
||||
settings = load_json_object_fixture("settings.json", DOMAIN)
|
||||
statistics = load_json_object_fixture("statistics.json", DOMAIN)
|
||||
|
||||
with (
|
||||
patch(
|
||||
@ -104,6 +106,7 @@ def mock_lamarzocco(device_fixture: ModelName) -> Generator[MagicMock]:
|
||||
machine_mock.dashboard = ThingDashboardConfig.from_dict(config)
|
||||
machine_mock.schedule = ThingSchedulingSettings.from_dict(schedule)
|
||||
machine_mock.settings = ThingSettings.from_dict(settings)
|
||||
machine_mock.statistics = ThingStatistics.from_dict(statistics)
|
||||
machine_mock.dashboard.model_name = device_fixture
|
||||
machine_mock.to_dict.return_value = {
|
||||
"serial_number": machine_mock.serial_number,
|
||||
|
183
tests/components/lamarzocco/fixtures/statistics.json
Normal file
183
tests/components/lamarzocco/fixtures/statistics.json
Normal file
@ -0,0 +1,183 @@
|
||||
{
|
||||
"serialNumber": "MR123456",
|
||||
"type": "CoffeeMachine",
|
||||
"name": "MR123456",
|
||||
"location": null,
|
||||
"modelCode": "LINEAMICRA",
|
||||
"modelName": "LINEA MICRA",
|
||||
"connected": true,
|
||||
"connectionDate": 1742526019892,
|
||||
"offlineMode": false,
|
||||
"requireFirmwareUpdate": false,
|
||||
"availableFirmwareUpdate": false,
|
||||
"coffeeStation": null,
|
||||
"imageUrl": "https://lion.lamarzocco.io/img/thing-model/detail/lineamicra/lineamicra-1-c-bianco.png",
|
||||
"bleAuthToken": null,
|
||||
"firmwares": null,
|
||||
"selectedWidgetCodes": ["COFFEE_AND_FLUSH_TREND", "LAST_COFFEE"],
|
||||
"allWidgetCodes": ["LAST_COFFEE", "COFFEE_AND_FLUSH_TREND"],
|
||||
"selectedWidgets": [
|
||||
{
|
||||
"code": "COFFEE_AND_FLUSH_TREND",
|
||||
"index": 1,
|
||||
"output": {
|
||||
"days": 7,
|
||||
"timezone": "Europe/Berlin",
|
||||
"coffees": [
|
||||
{ "timestamp": 1741993200000, "value": 2 },
|
||||
{ "timestamp": 1742079600000, "value": 2 },
|
||||
{ "timestamp": 1742166000000, "value": 2 },
|
||||
{ "timestamp": 1742252400000, "value": 2 },
|
||||
{ "timestamp": 1742338800000, "value": 4 },
|
||||
{ "timestamp": 1742425200000, "value": 3 },
|
||||
{ "timestamp": 1742511600000, "value": 1 }
|
||||
],
|
||||
"flushes": [
|
||||
{ "timestamp": 1741993200000, "value": 1 },
|
||||
{ "timestamp": 1742079600000, "value": 1 },
|
||||
{ "timestamp": 1742166000000, "value": 0 },
|
||||
{ "timestamp": 1742252400000, "value": 0 },
|
||||
{ "timestamp": 1742338800000, "value": 4 },
|
||||
{ "timestamp": 1742425200000, "value": 2 },
|
||||
{ "timestamp": 1742511600000, "value": 1 }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"code": "LAST_COFFEE",
|
||||
"index": 1,
|
||||
"output": {
|
||||
"lastCoffees": [
|
||||
{
|
||||
"time": 1742535679203,
|
||||
"extractionSeconds": 30.44,
|
||||
"doseMode": "Continuous",
|
||||
"doseIndex": "Continuous",
|
||||
"doseValue": null,
|
||||
"doseValueNumerator": null
|
||||
},
|
||||
{
|
||||
"time": 1742489827722,
|
||||
"extractionSeconds": 10.8,
|
||||
"doseMode": "Continuous",
|
||||
"doseIndex": "Continuous",
|
||||
"doseValue": null,
|
||||
"doseValueNumerator": null
|
||||
},
|
||||
{
|
||||
"time": 1742448826919,
|
||||
"extractionSeconds": 12.457,
|
||||
"doseMode": "Continuous",
|
||||
"doseIndex": "Continuous",
|
||||
"doseValue": null,
|
||||
"doseValueNumerator": null
|
||||
},
|
||||
{
|
||||
"time": 1742448702812,
|
||||
"extractionSeconds": 23.504,
|
||||
"doseMode": "Continuous",
|
||||
"doseIndex": "Continuous",
|
||||
"doseValue": null,
|
||||
"doseValueNumerator": null
|
||||
},
|
||||
{
|
||||
"time": 1742396255439,
|
||||
"extractionSeconds": 16.031,
|
||||
"doseMode": "Continuous",
|
||||
"doseIndex": "Continuous",
|
||||
"doseValue": null,
|
||||
"doseValueNumerator": null
|
||||
},
|
||||
{
|
||||
"time": 1742396142154,
|
||||
"extractionSeconds": 27.413,
|
||||
"doseMode": "Continuous",
|
||||
"doseIndex": "Continuous",
|
||||
"doseValue": null,
|
||||
"doseValueNumerator": null
|
||||
},
|
||||
{
|
||||
"time": 1742364379903,
|
||||
"extractionSeconds": 14.182,
|
||||
"doseMode": "Continuous",
|
||||
"doseIndex": "Continuous",
|
||||
"doseValue": null,
|
||||
"doseValueNumerator": null
|
||||
},
|
||||
{
|
||||
"time": 1742364235304,
|
||||
"extractionSeconds": 23.228,
|
||||
"doseMode": "Continuous",
|
||||
"doseIndex": "Continuous",
|
||||
"doseValue": null,
|
||||
"doseValueNumerator": null
|
||||
},
|
||||
{
|
||||
"time": 1742277098548,
|
||||
"extractionSeconds": 12.98,
|
||||
"doseMode": "PulsesType",
|
||||
"doseIndex": "DoseA",
|
||||
"doseValue": 0,
|
||||
"doseValueNumerator": null
|
||||
},
|
||||
{
|
||||
"time": 1742277006774,
|
||||
"extractionSeconds": 26.99,
|
||||
"doseMode": "PulsesType",
|
||||
"doseIndex": "DoseA",
|
||||
"doseValue": 0,
|
||||
"doseValueNumerator": null
|
||||
},
|
||||
{
|
||||
"time": 1742190219197,
|
||||
"extractionSeconds": 11.069,
|
||||
"doseMode": "PulsesType",
|
||||
"doseIndex": "DoseA",
|
||||
"doseValue": 0,
|
||||
"doseValueNumerator": null
|
||||
},
|
||||
{
|
||||
"time": 1742190123385,
|
||||
"extractionSeconds": 35.472,
|
||||
"doseMode": "PulsesType",
|
||||
"doseIndex": "DoseA",
|
||||
"doseValue": 0,
|
||||
"doseValueNumerator": null
|
||||
},
|
||||
{
|
||||
"time": 1742106228119,
|
||||
"extractionSeconds": 11.494,
|
||||
"doseMode": "PulsesType",
|
||||
"doseIndex": "DoseA",
|
||||
"doseValue": 0,
|
||||
"doseValueNumerator": null
|
||||
},
|
||||
{
|
||||
"time": 1742106147433,
|
||||
"extractionSeconds": 39.915,
|
||||
"doseMode": "PulsesType",
|
||||
"doseIndex": "DoseA",
|
||||
"doseValue": 0,
|
||||
"doseValueNumerator": null
|
||||
},
|
||||
{
|
||||
"time": 1742017890205,
|
||||
"extractionSeconds": 13.891,
|
||||
"doseMode": "PulsesType",
|
||||
"doseIndex": "DoseA",
|
||||
"doseValue": 0,
|
||||
"doseValueNumerator": null
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"code": "COFFEE_AND_FLUSH_COUNTER",
|
||||
"index": 1,
|
||||
"output": {
|
||||
"totalCoffee": 1620,
|
||||
"totalFlush": 1366
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -143,3 +143,105 @@
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.gs012345_total_coffees_made-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||
'entity_id': 'sensor.gs012345_total_coffees_made',
|
||||
'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': 'Total coffees made',
|
||||
'platform': 'lamarzocco',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'total_coffees_made',
|
||||
'unique_id': 'GS012345_drink_stats_coffee',
|
||||
'unit_of_measurement': 'coffees',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.gs012345_total_coffees_made-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'GS012345 Total coffees made',
|
||||
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
|
||||
'unit_of_measurement': 'coffees',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.gs012345_total_coffees_made',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '1620',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.gs012345_total_flushes_done-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||
'entity_id': 'sensor.gs012345_total_flushes_done',
|
||||
'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': 'Total flushes done',
|
||||
'platform': 'lamarzocco',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'total_flushes_done',
|
||||
'unique_id': 'GS012345_drink_stats_flushing',
|
||||
'unit_of_measurement': 'flushes',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.gs012345_total_flushes_done-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'GS012345 Total flushes done',
|
||||
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
|
||||
'unit_of_measurement': 'flushes',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.gs012345_total_flushes_done',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '1366',
|
||||
})
|
||||
# ---
|
||||
|
Loading…
x
Reference in New Issue
Block a user