diff --git a/README.md b/README.md index 3bb27b8..a40331d 100644 --- a/README.md +++ b/README.md @@ -50,12 +50,26 @@ Works with any remote integration that stores learnt commands using HA's `helper ## Configuration +### Initial setup + 1. [![Add integration](https://my.home-assistant.io/badges/config_flow_start.svg)](https://my.home-assistant.io/redirect/config_flow_start/?domain=remote_buttons) 2. Select the remote entities you want to watch — only remotes that support `learn_command` are shown. 3. Button entities are created automatically for all learnt commands on the selected remotes. +#### Setup parameters + +| Parameter | Description | +|---|---| +| **Remote entities** | One or more remote entities to watch. Only remotes on supported platforms (Broadlink, Tuya Local) that advertise the `learn_command` feature are listed. | + +### Options + You can update the selection at any time via **Settings > Devices & Services > Remote Buttons > Configure**. +| Parameter | Description | +|---|---| +| **Remote entities** | Add or remove remotes from the watch list. Removing a remote deletes all its button and number entities. Adding a remote triggers an immediate scan for learnt commands. | + ## Removal 1. Go to **Settings > Devices & Services > Remote Buttons**. diff --git a/custom_components/remote_buttons/button.py b/custom_components/remote_buttons/button.py index c6208ff..1618cb3 100644 --- a/custom_components/remote_buttons/button.py +++ b/custom_components/remote_buttons/button.py @@ -11,6 +11,8 @@ from .const import DOMAIN +PARALLEL_UPDATES = 0 + ATTR_COMMAND = "command" ATTR_DELAY_SECS = "delay_secs" ATTR_DEVICE = "device" diff --git a/custom_components/remote_buttons/number.py b/custom_components/remote_buttons/number.py index 184b457..7284744 100644 --- a/custom_components/remote_buttons/number.py +++ b/custom_components/remote_buttons/number.py @@ -13,6 +13,8 @@ from .const import DEFAULT_IR_DELAY, DEFAULT_IR_REPEATS, DOMAIN +PARALLEL_UPDATES = 0 + async def async_setup_entry( hass: HomeAssistant, entry, async_add_entities: AddEntitiesCallback diff --git a/tests/test_number.py b/tests/test_number.py index ef853a4..6e0d41e 100644 --- a/tests/test_number.py +++ b/tests/test_number.py @@ -2,6 +2,8 @@ from __future__ import annotations +from unittest.mock import AsyncMock, MagicMock, patch + from homeassistant.components.number import NumberMode from homeassistant.const import EntityCategory, UnitOfTime @@ -78,3 +80,37 @@ def test_number_attributes() -> None: assert repeats.native_step == 1.0 assert repeats.native_unit_of_measurement is None assert repeats.translation_key == "ir_repeat" + + +async def test_number_set_native_value() -> None: + """Test that setting a value updates the attribute and writes state.""" + delay, _ = create_ir_number_pair( + remote_entity_id="remote.living_room", + remote_device_id="abc123", + remote_domain="broadlink", + subdevice="TV", + ) + delay.async_write_ha_state = MagicMock() + + await delay.async_set_native_value(2.5) + assert delay.native_value == 2.5 + delay.async_write_ha_state.assert_called_once() + + +async def test_number_restores_last_state() -> None: + """Test that the number restores its value from the last known state.""" + delay, _ = create_ir_number_pair( + remote_entity_id="remote.living_room", + remote_device_id="abc123", + remote_domain="broadlink", + subdevice="TV", + ) + + last_state = MagicMock() + last_state.state = "3.0" + delay.async_get_last_state = AsyncMock(return_value=last_state) + + with patch.object(type(delay).__mro__[2], "async_added_to_hass", new_callable=AsyncMock): + await delay.async_added_to_hass() + + assert delay.native_value == 3.0 diff --git a/tests/test_storage.py b/tests/test_storage.py index a39ebfa..b1b1ada 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -59,3 +59,29 @@ async def test_tuya_local_reader_returns_commands(hass: HomeAssistant) -> None: assert "Fan" in result assert result["Fan"]["speed1"] == "code1" + + +async def test_tuya_local_reader_returns_empty_on_missing(hass: HomeAssistant) -> None: + """Test TuyaLocalStorageReader returns empty dict when no storage exists.""" + with patch( + "custom_components.remote_buttons.storage.Store.async_load", + new_callable=AsyncMock, + return_value=None, + ): + reader = TuyaLocalStorageReader() + result = await reader.async_read_commands(hass, "missing_uid") + + assert result == {} + + +async def test_tuya_local_reader_returns_empty_on_error(hass: HomeAssistant) -> None: + """Test TuyaLocalStorageReader returns empty dict on storage error.""" + with patch( + "custom_components.remote_buttons.storage.Store.async_load", + new_callable=AsyncMock, + side_effect=OSError("disk error"), + ): + reader = TuyaLocalStorageReader() + result = await reader.async_read_commands(hass, "broken_uid") + + assert result == {}