From ab945ee76eed9e79a25e3352b2d7ad5bd8fdedb3 Mon Sep 17 00:00:00 2001 From: Kevin Stillhammer Date: Sun, 14 Jul 2024 23:59:24 +0200 Subject: [PATCH] Add Broadlink select platform (#121797) * Add broadlink select platform * Apply strings.json feedback * Remove obsolete Service Exception * Use day names instead of IDs * Use list() --- homeassistant/components/broadlink/const.py | 1 + homeassistant/components/broadlink/select.py | 69 +++++++++++++++++++ .../components/broadlink/strings.json | 14 ++++ tests/components/broadlink/test_select.py | 67 ++++++++++++++++++ 4 files changed, 151 insertions(+) create mode 100644 homeassistant/components/broadlink/select.py create mode 100644 tests/components/broadlink/test_select.py diff --git a/homeassistant/components/broadlink/const.py b/homeassistant/components/broadlink/const.py index 041c2aba9f0..c9b17128b79 100644 --- a/homeassistant/components/broadlink/const.py +++ b/homeassistant/components/broadlink/const.py @@ -8,6 +8,7 @@ DOMAINS_AND_TYPES = { Platform.CLIMATE: {"HYS"}, Platform.LIGHT: {"LB1", "LB2"}, Platform.REMOTE: {"RM4MINI", "RM4PRO", "RMMINI", "RMMINIB", "RMPRO"}, + Platform.SELECT: {"HYS"}, Platform.SENSOR: { "A1", "MP1S", diff --git a/homeassistant/components/broadlink/select.py b/homeassistant/components/broadlink/select.py new file mode 100644 index 00000000000..6253adc308a --- /dev/null +++ b/homeassistant/components/broadlink/select.py @@ -0,0 +1,69 @@ +"""Support for Broadlink selects.""" + +from __future__ import annotations + +from typing import Any + +from homeassistant.components.select import SelectEntity +from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant +from homeassistant.helpers.entity_platform import AddEntitiesCallback + +from . import BroadlinkDevice +from .const import DOMAIN +from .entity import BroadlinkEntity + +DAY_ID_TO_NAME = { + 1: "monday", + 2: "tuesday", + 3: "wednesday", + 4: "thursday", + 5: "friday", + 6: "saturday", + 7: "sunday", +} +DAY_NAME_TO_ID = {v: k for k, v in DAY_ID_TO_NAME.items()} + + +async def async_setup_entry( + hass: HomeAssistant, + config_entry: ConfigEntry, + async_add_entities: AddEntitiesCallback, +) -> None: + """Set up the Broadlink select.""" + device = hass.data[DOMAIN].devices[config_entry.entry_id] + async_add_entities([BroadlinkDayOfWeek(device)]) + + +class BroadlinkDayOfWeek(BroadlinkEntity, SelectEntity): + """Representation of a Broadlink day of week.""" + + _attr_has_entity_name = True + _attr_current_option: str | None = None + _attr_options = list(DAY_NAME_TO_ID) + _attr_translation_key = "day_of_week" + + def __init__(self, device: BroadlinkDevice) -> None: + """Initialize the select.""" + super().__init__(device) + + self._attr_unique_id = f"{device.unique_id}-dayofweek" + + def _update_state(self, data: dict[str, Any]) -> None: + """Update the state of the entity.""" + if data is None or "dayofweek" not in data: + self._attr_current_option = None + else: + self._attr_current_option = DAY_ID_TO_NAME[data["dayofweek"]] + + async def async_select_option(self, option: str) -> None: + """Change the selected option.""" + await self._device.async_request( + self._device.api.set_time, + hour=self._coordinator.data["hour"], + minute=self._coordinator.data["min"], + second=self._coordinator.data["sec"], + day=DAY_NAME_TO_ID[option], + ) + self._attr_current_option = option + self.async_write_ha_state() diff --git a/homeassistant/components/broadlink/strings.json b/homeassistant/components/broadlink/strings.json index 335984d1ebe..5150a521363 100644 --- a/homeassistant/components/broadlink/strings.json +++ b/homeassistant/components/broadlink/strings.json @@ -61,6 +61,20 @@ "total_consumption": { "name": "Total consumption" } + }, + "select": { + "day_of_week": { + "name": "Day of week", + "state": { + "monday": "[%key:common::time::monday%]", + "tuesday": "[%key:common::time::tuesday%]", + "wednesday": "[%key:common::time::wednesday%]", + "thursday": "[%key:common::time::thursday%]", + "friday": "[%key:common::time::friday%]", + "saturday": "[%key:common::time::saturday%]", + "sunday": "[%key:common::time::sunday%]" + } + } } } } diff --git a/tests/components/broadlink/test_select.py b/tests/components/broadlink/test_select.py new file mode 100644 index 00000000000..42715c9a5ab --- /dev/null +++ b/tests/components/broadlink/test_select.py @@ -0,0 +1,67 @@ +"""Tests for Broadlink select.""" + +from homeassistant.components.broadlink.const import DOMAIN +from homeassistant.components.select import ( + ATTR_OPTION, + DOMAIN as SELECT_DOMAIN, + SERVICE_SELECT_OPTION, +) +from homeassistant.const import ATTR_ENTITY_ID, Platform +from homeassistant.core import HomeAssistant +from homeassistant.helpers import device_registry as dr, entity_registry as er +from homeassistant.helpers.entity_component import async_update_entity + +from . import get_device + + +async def test_select( + hass: HomeAssistant, + device_registry: dr.DeviceRegistry, + entity_registry: er.EntityRegistry, +) -> None: + """Test Broadlink select.""" + await hass.config.async_set_time_zone("UTC") + + device = get_device("Guest room") + mock_setup = await device.setup_entry(hass) + + device_entry = device_registry.async_get_device( + identifiers={(DOMAIN, mock_setup.entry.unique_id)} + ) + entries = er.async_entries_for_device(entity_registry, device_entry.id) + selects = [entry for entry in entries if entry.domain == Platform.SELECT] + assert len(selects) == 1 + + select = selects[0] + + mock_setup.api.get_full_status.return_value = { + "dayofweek": 3, + "hour": 2, + "min": 3, + "sec": 4, + } + await async_update_entity(hass, select.entity_id) + assert mock_setup.api.get_full_status.call_count == 2 + state = hass.states.get(select.entity_id) + assert state.state == "wednesday" + + # set value + await hass.services.async_call( + SELECT_DOMAIN, + SERVICE_SELECT_OPTION, + { + ATTR_ENTITY_ID: select.entity_id, + ATTR_OPTION: "tuesday", + }, + blocking=True, + ) + state = hass.states.get(select.entity_id) + assert state.state == "tuesday" + assert mock_setup.api.set_time.call_count == 1 + call_args = mock_setup.api.set_time.call_args.kwargs + assert call_args == { + "hour": 2, + "minute": 3, + "second": 4, + "day": 2, + }