Add time platform to ohme (#136289)

This commit is contained in:
Dan Raper 2025-01-23 07:20:03 +00:00 committed by GitHub
parent 90bd783fff
commit 95b49fd2bc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 200 additions and 4 deletions

View File

@ -3,4 +3,10 @@
from homeassistant.const import Platform
DOMAIN = "ohme"
PLATFORMS = [Platform.BUTTON, Platform.NUMBER, Platform.SENSOR, Platform.SWITCH]
PLATFORMS = [
Platform.BUTTON,
Platform.NUMBER,
Platform.SENSOR,
Platform.SWITCH,
Platform.TIME,
]

View File

@ -41,6 +41,11 @@
"off": "mdi:sleep-off"
}
}
},
"time": {
"target_time": {
"default": "mdi:clock-end"
}
}
},
"services": {

View File

@ -7,5 +7,5 @@
"integration_type": "device",
"iot_class": "cloud_polling",
"quality_scale": "silver",
"requirements": ["ohme==1.2.4"]
"requirements": ["ohme==1.2.5"]
}

View File

@ -83,6 +83,11 @@
"sleep_when_inactive": {
"name": "Sleep when inactive"
}
},
"time": {
"target_time": {
"name": "Target time"
}
}
},
"exceptions": {

View File

@ -0,0 +1,77 @@
"""Platform for time."""
from collections.abc import Awaitable, Callable
from dataclasses import dataclass
from datetime import time
from ohme import ApiException, OhmeApiClient
from homeassistant.components.time import TimeEntity, TimeEntityDescription
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import OhmeConfigEntry
from .const import DOMAIN
from .entity import OhmeEntity, OhmeEntityDescription
PARALLEL_UPDATES = 1
@dataclass(frozen=True, kw_only=True)
class OhmeTimeDescription(OhmeEntityDescription, TimeEntityDescription):
"""Class describing Ohme time entities."""
set_fn: Callable[[OhmeApiClient, time], Awaitable[None]]
value_fn: Callable[[OhmeApiClient], time]
TIME_DESCRIPTION = [
OhmeTimeDescription(
key="target_time",
translation_key="target_time",
value_fn=lambda client: time(
hour=client.target_time[0], minute=client.target_time[1]
),
set_fn=lambda client, value: client.async_set_target(
target_time=(value.hour, value.minute)
),
),
]
async def async_setup_entry(
hass: HomeAssistant,
config_entry: OhmeConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up time entities."""
coordinators = config_entry.runtime_data
coordinator = coordinators.charge_session_coordinator
async_add_entities(
OhmeTime(coordinator, description)
for description in TIME_DESCRIPTION
if description.is_supported_fn(coordinator.client)
)
class OhmeTime(OhmeEntity, TimeEntity):
"""Generic time entity for Ohme."""
entity_description: OhmeTimeDescription
@property
def native_value(self) -> time:
"""Return the current value of the time."""
return self.entity_description.value_fn(self.coordinator.client)
async def async_set_value(self, value: time) -> None:
"""Set the time value."""
try:
await self.entity_description.set_fn(self.coordinator.client, value)
except ApiException as e:
raise HomeAssistantError(
translation_key="api_failed", translation_domain=DOMAIN
) from e
await self.coordinator.async_request_refresh()

2
requirements_all.txt generated
View File

@ -1540,7 +1540,7 @@ odp-amsterdam==6.0.2
oemthermostat==1.1.1
# homeassistant.components.ohme
ohme==1.2.4
ohme==1.2.5
# homeassistant.components.ollama
ollama==0.4.7

View File

@ -1288,7 +1288,7 @@ objgraph==3.5.0
odp-amsterdam==6.0.2
# homeassistant.components.ohme
ohme==1.2.4
ohme==1.2.5
# homeassistant.components.ollama
ollama==0.4.7

View File

@ -55,6 +55,7 @@ def mock_client():
client.power = ChargerPower(0, 0, 0, 0)
client.target_soc = 50
client.target_time = (8, 0)
client.battery = 80
client.serial = "chargerid"
client.ct_connected = True

View File

@ -0,0 +1,47 @@
# serializer version: 1
# name: test_time[time.ohme_home_pro_target_time-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'time',
'entity_category': None,
'entity_id': 'time.ohme_home_pro_target_time',
'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': 'Target time',
'platform': 'ohme',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'target_time',
'unique_id': 'chargerid_target_time',
'unit_of_measurement': None,
})
# ---
# name: test_time[time.ohme_home_pro_target_time-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Ohme Home Pro Target time',
}),
'context': <ANY>,
'entity_id': 'time.ohme_home_pro_target_time',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '08:00:00',
})
# ---

View File

@ -0,0 +1,55 @@
"""Tests for time."""
from unittest.mock import MagicMock, patch
from syrupy import SnapshotAssertion
from homeassistant.components.time import (
ATTR_TIME,
DOMAIN as TIME_DOMAIN,
SERVICE_SET_VALUE,
)
from homeassistant.const import ATTR_ENTITY_ID, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from . import setup_integration
from tests.common import MockConfigEntry, snapshot_platform
async def test_time(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
snapshot: SnapshotAssertion,
mock_config_entry: MockConfigEntry,
mock_client: MagicMock,
) -> None:
"""Test the Ohme sensors."""
with patch("homeassistant.components.ohme.PLATFORMS", [Platform.TIME]):
await setup_integration(hass, mock_config_entry)
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
async def test_set_time(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_client: MagicMock,
) -> None:
"""Test the time set."""
await setup_integration(hass, mock_config_entry)
await hass.services.async_call(
TIME_DOMAIN,
SERVICE_SET_VALUE,
service_data={
ATTR_TIME: "00:00:00",
},
target={
ATTR_ENTITY_ID: "time.ohme_home_pro_target_time",
},
blocking=True,
)
assert len(mock_client.async_set_target.mock_calls) == 1