-
-
Notifications
You must be signed in to change notification settings - Fork 28.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add time component to Melnor Bluetooth integration (#93652)
* Add time component to Melnor Bluetooth integration * Apply suggestions from code review --------- Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
- Loading branch information
1 parent
c3a3ddc
commit 4bade86
Showing
6 changed files
with
145 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ | |
Platform.NUMBER, | ||
Platform.SENSOR, | ||
Platform.SWITCH, | ||
Platform.TIME, | ||
] | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
"""Number support for Melnor Bluetooth water timer.""" | ||
|
||
from __future__ import annotations | ||
|
||
from collections.abc import Callable, Coroutine | ||
from dataclasses import dataclass | ||
from datetime import time | ||
from typing import Any | ||
|
||
from melnor_bluetooth.device import Valve | ||
|
||
from homeassistant.components.time import TimeEntity, TimeEntityDescription | ||
from homeassistant.config_entries import ConfigEntry | ||
from homeassistant.const import EntityCategory | ||
from homeassistant.core import HomeAssistant | ||
from homeassistant.helpers.entity_platform import AddEntitiesCallback | ||
|
||
from .const import DOMAIN | ||
from .models import ( | ||
MelnorDataUpdateCoordinator, | ||
MelnorZoneEntity, | ||
get_entities_for_valves, | ||
) | ||
|
||
|
||
@dataclass | ||
class MelnorZoneTimeEntityDescriptionMixin: | ||
"""Mixin for required keys.""" | ||
|
||
set_time_fn: Callable[[Valve, time], Coroutine[Any, Any, None]] | ||
state_fn: Callable[[Valve], Any] | ||
|
||
|
||
@dataclass | ||
class MelnorZoneTimeEntityDescription( | ||
TimeEntityDescription, MelnorZoneTimeEntityDescriptionMixin | ||
): | ||
"""Describes Melnor number entity.""" | ||
|
||
|
||
ZONE_ENTITY_DESCRIPTIONS: list[MelnorZoneTimeEntityDescription] = [ | ||
MelnorZoneTimeEntityDescription( | ||
entity_category=EntityCategory.CONFIG, | ||
key="frequency_start_time", | ||
name="Schedule Start Time", | ||
set_time_fn=lambda valve, value: valve.set_frequency_start_time(value), | ||
state_fn=lambda valve: valve.frequency.start_time, | ||
), | ||
] | ||
|
||
|
||
async def async_setup_entry( | ||
hass: HomeAssistant, | ||
config_entry: ConfigEntry, | ||
async_add_entities: AddEntitiesCallback, | ||
) -> None: | ||
"""Set up the number platform.""" | ||
|
||
coordinator: MelnorDataUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id] | ||
|
||
async_add_entities( | ||
get_entities_for_valves( | ||
coordinator, | ||
ZONE_ENTITY_DESCRIPTIONS, | ||
lambda valve, description: MelnorZoneTime(coordinator, description, valve), | ||
) | ||
) | ||
|
||
|
||
class MelnorZoneTime(MelnorZoneEntity, TimeEntity): | ||
"""A time implementation for a melnor device.""" | ||
|
||
entity_description: MelnorZoneTimeEntityDescription | ||
|
||
def __init__( | ||
self, | ||
coordinator: MelnorDataUpdateCoordinator, | ||
entity_description: MelnorZoneTimeEntityDescription, | ||
valve: Valve, | ||
) -> None: | ||
"""Initialize a number for a melnor device.""" | ||
super().__init__(coordinator, entity_description, valve) | ||
|
||
@property | ||
def native_value(self) -> time | None: | ||
"""Return the current value.""" | ||
return self.entity_description.state_fn(self._valve) | ||
|
||
async def async_set_value(self, value: time) -> None: | ||
"""Update the current value.""" | ||
await self.entity_description.set_time_fn(self._valve, value) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
"""Test the Melnor time platform.""" | ||
from __future__ import annotations | ||
|
||
from datetime import time | ||
|
||
from homeassistant.core import HomeAssistant | ||
import homeassistant.util.dt as dt_util | ||
|
||
from .conftest import ( | ||
mock_config_entry, | ||
patch_async_ble_device_from_address, | ||
patch_async_register_callback, | ||
patch_melnor_device, | ||
) | ||
|
||
from tests.common import async_fire_time_changed | ||
|
||
|
||
async def test_schedule_start_time(hass: HomeAssistant) -> None: | ||
"""Test the frequency schedule start time.""" | ||
|
||
now = dt_util.now() | ||
|
||
entry = mock_config_entry(hass) | ||
|
||
with patch_async_ble_device_from_address(), patch_melnor_device() as device_patch, patch_async_register_callback(): | ||
device = device_patch.return_value | ||
|
||
assert await hass.config_entries.async_setup(entry.entry_id) | ||
await hass.async_block_till_done() | ||
|
||
time_entity = hass.states.get("time.zone_1_schedule_start_time") | ||
|
||
assert time_entity is not None | ||
assert time_entity.state == device.zone1.frequency.start_time.isoformat() | ||
|
||
await hass.services.async_call( | ||
"time", | ||
"set_value", | ||
{"entity_id": "time.zone_1_schedule_start_time", "time": time(1, 0)}, | ||
blocking=True, | ||
) | ||
|
||
async_fire_time_changed(hass, now + dt_util.dt.timedelta(seconds=10)) | ||
await hass.async_block_till_done() | ||
|
||
time_entity = hass.states.get("time.zone_1_schedule_start_time") | ||
|
||
assert time_entity is not None | ||
assert time_entity.state == time(1, 0).isoformat() |