mirror of
https://github.com/home-assistant/core.git
synced 2025-07-27 23:27:37 +00:00
Add date sensors to Rehlko (#145314)
* feat: add datetime sensors * fix: constants * fix: constants * fix: move tz conversion to api * fix: update typing
This commit is contained in:
parent
8ec5472b79
commit
3ff3cb975b
@ -10,6 +10,7 @@ from homeassistant.const import CONF_EMAIL, CONF_PASSWORD, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from .const import (
|
||||
CONF_REFRESH_TOKEN,
|
||||
@ -28,7 +29,7 @@ _LOGGER = logging.getLogger(__name__)
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: RehlkoConfigEntry) -> bool:
|
||||
"""Set up Rehlko from a config entry."""
|
||||
websession = async_get_clientsession(hass)
|
||||
rehlko = AioKem(session=websession)
|
||||
rehlko = AioKem(session=websession, home_timezone=dt_util.get_default_time_zone())
|
||||
# If requests take more than 20 seconds; timeout and let the setup retry.
|
||||
rehlko.set_timeout(20)
|
||||
|
||||
|
@ -18,6 +18,7 @@ DEVICE_DATA_IS_CONNECTED = "isConnected"
|
||||
KOHLER = "Kohler"
|
||||
|
||||
GENERATOR_DATA_DEVICE = "device"
|
||||
GENERATOR_DATA_EXERCISE = "exercise"
|
||||
|
||||
CONNECTION_EXCEPTIONS = (
|
||||
TimeoutError,
|
||||
|
@ -43,7 +43,7 @@ class RehlkoEntity(CoordinatorEntity[RehlkoUpdateCoordinator]):
|
||||
device_id: int,
|
||||
device_data: dict,
|
||||
description: EntityDescription,
|
||||
use_device_key: bool = False,
|
||||
document_key: str | None = None,
|
||||
) -> None:
|
||||
"""Initialize the sensor."""
|
||||
super().__init__(coordinator)
|
||||
@ -61,7 +61,7 @@ class RehlkoEntity(CoordinatorEntity[RehlkoUpdateCoordinator]):
|
||||
manufacturer=KOHLER,
|
||||
connections=_get_device_connections(device_data[DEVICE_DATA_MAC_ADDRESS]),
|
||||
)
|
||||
self._use_device_key = use_device_key
|
||||
self._document_key = document_key
|
||||
|
||||
@property
|
||||
def _device_data(self) -> dict[str, Any]:
|
||||
@ -71,8 +71,10 @@ class RehlkoEntity(CoordinatorEntity[RehlkoUpdateCoordinator]):
|
||||
@property
|
||||
def _rehlko_value(self) -> str:
|
||||
"""Return the sensor value."""
|
||||
if self._use_device_key:
|
||||
return self._device_data[self.entity_description.key]
|
||||
if self._document_key:
|
||||
return self.coordinator.data[self._document_key][
|
||||
self.entity_description.key
|
||||
]
|
||||
return self.coordinator.data[self.entity_description.key]
|
||||
|
||||
@property
|
||||
|
@ -2,7 +2,9 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
SensorDeviceClass,
|
||||
@ -25,7 +27,12 @@ from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.helpers.typing import StateType
|
||||
|
||||
from .const import DEVICE_DATA_DEVICES, DEVICE_DATA_ID
|
||||
from .const import (
|
||||
DEVICE_DATA_DEVICES,
|
||||
DEVICE_DATA_ID,
|
||||
GENERATOR_DATA_DEVICE,
|
||||
GENERATOR_DATA_EXERCISE,
|
||||
)
|
||||
from .coordinator import RehlkoConfigEntry
|
||||
from .entity import RehlkoEntity
|
||||
|
||||
@ -37,7 +44,8 @@ PARALLEL_UPDATES = 0
|
||||
class RehlkoSensorEntityDescription(SensorEntityDescription):
|
||||
"""Class describing Rehlko sensor entities."""
|
||||
|
||||
use_device_key: bool = False
|
||||
document_key: str | None = None
|
||||
value_fn: Callable[[str], datetime | None] | None = None
|
||||
|
||||
|
||||
SENSORS: tuple[RehlkoSensorEntityDescription, ...] = (
|
||||
@ -116,7 +124,7 @@ SENSORS: tuple[RehlkoSensorEntityDescription, ...] = (
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
entity_registry_enabled_default=False,
|
||||
use_device_key=True,
|
||||
document_key=GENERATOR_DATA_DEVICE,
|
||||
),
|
||||
RehlkoSensorEntityDescription(
|
||||
key="runtimeSinceLastMaintenanceHours",
|
||||
@ -132,7 +140,7 @@ SENSORS: tuple[RehlkoSensorEntityDescription, ...] = (
|
||||
translation_key="device_ip_address",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
entity_registry_enabled_default=False,
|
||||
use_device_key=True,
|
||||
document_key=GENERATOR_DATA_DEVICE,
|
||||
),
|
||||
RehlkoSensorEntityDescription(
|
||||
key="serverIpAddress",
|
||||
@ -171,7 +179,7 @@ SENSORS: tuple[RehlkoSensorEntityDescription, ...] = (
|
||||
RehlkoSensorEntityDescription(
|
||||
key="status",
|
||||
translation_key="generator_status",
|
||||
use_device_key=True,
|
||||
document_key=GENERATOR_DATA_DEVICE,
|
||||
),
|
||||
RehlkoSensorEntityDescription(
|
||||
key="engineState",
|
||||
@ -181,6 +189,44 @@ SENSORS: tuple[RehlkoSensorEntityDescription, ...] = (
|
||||
key="powerSource",
|
||||
translation_key="power_source",
|
||||
),
|
||||
RehlkoSensorEntityDescription(
|
||||
key="lastRanTimestamp",
|
||||
translation_key="last_run",
|
||||
device_class=SensorDeviceClass.TIMESTAMP,
|
||||
value_fn=datetime.fromisoformat,
|
||||
),
|
||||
RehlkoSensorEntityDescription(
|
||||
key="lastMaintenanceTimestamp",
|
||||
translation_key="last_maintainance",
|
||||
device_class=SensorDeviceClass.TIMESTAMP,
|
||||
document_key=GENERATOR_DATA_DEVICE,
|
||||
value_fn=datetime.fromisoformat,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
RehlkoSensorEntityDescription(
|
||||
key="nextMaintenanceTimestamp",
|
||||
translation_key="next_maintainance",
|
||||
device_class=SensorDeviceClass.TIMESTAMP,
|
||||
document_key=GENERATOR_DATA_DEVICE,
|
||||
value_fn=datetime.fromisoformat,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
RehlkoSensorEntityDescription(
|
||||
key="lastStartTimestamp",
|
||||
translation_key="last_exercise",
|
||||
device_class=SensorDeviceClass.TIMESTAMP,
|
||||
document_key=GENERATOR_DATA_EXERCISE,
|
||||
value_fn=datetime.fromisoformat,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
RehlkoSensorEntityDescription(
|
||||
key="nextStartTimestamp",
|
||||
translation_key="next_exercise",
|
||||
device_class=SensorDeviceClass.TIMESTAMP,
|
||||
document_key=GENERATOR_DATA_EXERCISE,
|
||||
value_fn=datetime.fromisoformat,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@ -199,7 +245,7 @@ async def async_setup_entry(
|
||||
device_data[DEVICE_DATA_ID],
|
||||
device_data,
|
||||
sensor_description,
|
||||
sensor_description.use_device_key,
|
||||
sensor_description.document_key,
|
||||
)
|
||||
for home_data in homes
|
||||
for device_data in home_data[DEVICE_DATA_DEVICES]
|
||||
@ -210,7 +256,11 @@ async def async_setup_entry(
|
||||
class RehlkoSensorEntity(RehlkoEntity, SensorEntity):
|
||||
"""Representation of a Rehlko sensor."""
|
||||
|
||||
entity_description: RehlkoSensorEntityDescription
|
||||
|
||||
@property
|
||||
def native_value(self) -> StateType:
|
||||
def native_value(self) -> StateType | datetime:
|
||||
"""Return the sensor state."""
|
||||
if self.entity_description.value_fn:
|
||||
return self.entity_description.value_fn(self._rehlko_value)
|
||||
return self._rehlko_value
|
||||
|
@ -91,6 +91,21 @@
|
||||
},
|
||||
"generator_status": {
|
||||
"name": "Generator status"
|
||||
},
|
||||
"last_run": {
|
||||
"name": "Last run"
|
||||
},
|
||||
"last_maintainance": {
|
||||
"name": "Last maintainance"
|
||||
},
|
||||
"next_maintainance": {
|
||||
"name": "Next maintainance"
|
||||
},
|
||||
"next_exercise": {
|
||||
"name": "Next exercise"
|
||||
},
|
||||
"last_exercise": {
|
||||
"name": "Last exercise"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -54,8 +54,8 @@
|
||||
"alertCount": 0,
|
||||
"model": "Model20KW",
|
||||
"modelDisplayName": "20 KW",
|
||||
"lastMaintenanceTimestamp": "2025-04-10T09:12:59",
|
||||
"nextMaintenanceTimestamp": "2026-04-10T09:12:59",
|
||||
"lastMaintenanceTimestamp": "2025-04-10T09:12:59-04:00",
|
||||
"nextMaintenanceTimestamp": "2026-04-10T09:12:59-04:00",
|
||||
"maintenancePeriodDays": 365,
|
||||
"hasServiceAgreement": null,
|
||||
"totalRuntimeHours": 120.2
|
||||
@ -74,7 +74,7 @@
|
||||
},
|
||||
"exercise": {
|
||||
"frequency": "Weekly",
|
||||
"nextStartTimestamp": "2025-04-19T10:00:00",
|
||||
"nextStartTimestamp": "2025-04-19T10:00:00-04:00",
|
||||
"mode": "Unloaded",
|
||||
"runningMode": null,
|
||||
"durationMinutes": 20,
|
||||
|
@ -609,6 +609,150 @@
|
||||
'state': 'ReadyToRun',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.generator_1_last_exercise-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'sensor.generator_1_last_exercise',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Last exercise',
|
||||
'platform': 'rehlko',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'last_exercise',
|
||||
'unique_id': 'myemail@email.com_12345_lastStartTimestamp',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.generator_1_last_exercise-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'timestamp',
|
||||
'friendly_name': 'Generator 1 Last exercise',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.generator_1_last_exercise',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '2025-04-12T14:00:00+00:00',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.generator_1_last_maintainance-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'sensor.generator_1_last_maintainance',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Last maintainance',
|
||||
'platform': 'rehlko',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'last_maintainance',
|
||||
'unique_id': 'myemail@email.com_12345_lastMaintenanceTimestamp',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.generator_1_last_maintainance-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'timestamp',
|
||||
'friendly_name': 'Generator 1 Last maintainance',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.generator_1_last_maintainance',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '2025-04-10T13:12:59+00:00',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.generator_1_last_run-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'sensor.generator_1_last_run',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Last run',
|
||||
'platform': 'rehlko',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'last_run',
|
||||
'unique_id': 'myemail@email.com_12345_lastRanTimestamp',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.generator_1_last_run-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'timestamp',
|
||||
'friendly_name': 'Generator 1 Last run',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.generator_1_last_run',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '2025-04-12T14:00:00+00:00',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.generator_1_lube_oil_temperature-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
@ -661,6 +805,102 @@
|
||||
'state': '6.0',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.generator_1_next_exercise-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'sensor.generator_1_next_exercise',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Next exercise',
|
||||
'platform': 'rehlko',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'next_exercise',
|
||||
'unique_id': 'myemail@email.com_12345_nextStartTimestamp',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.generator_1_next_exercise-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'timestamp',
|
||||
'friendly_name': 'Generator 1 Next exercise',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.generator_1_next_exercise',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '2025-04-19T14:00:00+00:00',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.generator_1_next_maintainance-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'sensor.generator_1_next_maintainance',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Next maintainance',
|
||||
'platform': 'rehlko',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'next_maintainance',
|
||||
'unique_id': 'myemail@email.com_12345_nextMaintenanceTimestamp',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.generator_1_next_maintainance-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'timestamp',
|
||||
'friendly_name': 'Generator 1 Next maintainance',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.generator_1_next_maintainance',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '2026-04-10T13:12:59+00:00',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.generator_1_power_source-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
|
Loading…
x
Reference in New Issue
Block a user