mirror of
https://github.com/home-assistant/core.git
synced 2026-05-28 03:06:30 +01:00
Update rf-protocols to 4.0.0 (#172131)
This commit is contained in:
@@ -1,7 +0,0 @@
|
||||
"""Command names for the Novy Cooker Hood RF codes."""
|
||||
|
||||
from typing import Final
|
||||
|
||||
COMMAND_LIGHT: Final = "light"
|
||||
COMMAND_PLUS: Final = "plus"
|
||||
COMMAND_MINUS: Final = "minus"
|
||||
@@ -3,7 +3,7 @@
|
||||
import asyncio
|
||||
from typing import Any
|
||||
|
||||
from rf_protocols.codes.novy.cooker_hood import get_codes_for_code
|
||||
from rf_protocols.codes.novy.cooker_hood import NovyCookerHoodButton
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.radio_frequency import (
|
||||
@@ -19,7 +19,6 @@ from homeassistant.const import CONF_CODE
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import entity_registry as er, selector
|
||||
|
||||
from .commands import COMMAND_LIGHT
|
||||
from .const import (
|
||||
CODE_MAX,
|
||||
CODE_MIN,
|
||||
@@ -128,10 +127,8 @@ class NovyCookerHoodConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
) -> ConfigFlowResult:
|
||||
"""Toggle the hood light on then off so it ends in its starting state."""
|
||||
assert self._transmitter_entity_id is not None
|
||||
command = NovyCookerHoodButton.LIGHT.to_command(channel=self._code)
|
||||
try:
|
||||
command = await get_codes_for_code(self._code).async_load_command(
|
||||
COMMAND_LIGHT
|
||||
)
|
||||
await async_send_command(self.hass, self._transmitter_entity_id, command)
|
||||
await asyncio.sleep(_TOGGLE_GAP)
|
||||
await async_send_command(self.hass, self._transmitter_entity_id, command)
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
import math
|
||||
from typing import Any
|
||||
|
||||
from rf_protocols.codes.novy.cooker_hood import get_codes_for_code
|
||||
from rf_protocols.codes.novy.cooker_hood import NovyCookerHoodButton
|
||||
from rf_protocols.commands.novy import NovyCookerHoodCommand
|
||||
|
||||
from homeassistant.components.fan import ATTR_PERCENTAGE, FanEntity, FanEntityFeature
|
||||
from homeassistant.components.radio_frequency import async_send_command
|
||||
@@ -17,7 +18,6 @@ from homeassistant.util.percentage import (
|
||||
ranged_value_to_percentage,
|
||||
)
|
||||
|
||||
from .commands import COMMAND_MINUS, COMMAND_PLUS
|
||||
from .const import SPEED_COUNT
|
||||
from .entity import NovyCookerHoodEntity
|
||||
|
||||
@@ -49,7 +49,7 @@ class NovyCookerHoodFan(NovyCookerHoodEntity, FanEntity, RestoreEntity):
|
||||
def __init__(self, entry: ConfigEntry) -> None:
|
||||
"""Initialize the fan."""
|
||||
super().__init__(entry)
|
||||
self._codes = get_codes_for_code(entry.data[CONF_CODE])
|
||||
self._code: int = entry.data[CONF_CODE]
|
||||
self._level = 0
|
||||
self._attr_unique_id = entry.entry_id
|
||||
|
||||
@@ -103,7 +103,7 @@ class NovyCookerHoodFan(NovyCookerHoodEntity, FanEntity, RestoreEntity):
|
||||
async def async_increase_speed(self, percentage_step: int | None = None) -> None:
|
||||
"""Bump speed up by N hardware levels (no recalibration)."""
|
||||
steps = self._steps_from_percentage(percentage_step)
|
||||
plus = await self._codes.async_load_command(COMMAND_PLUS)
|
||||
plus = NovyCookerHoodButton.PLUS.to_command(channel=self._code)
|
||||
for _ in range(steps):
|
||||
await self._async_send(plus)
|
||||
self._level = min(SPEED_COUNT, self._level + steps)
|
||||
@@ -112,7 +112,7 @@ class NovyCookerHoodFan(NovyCookerHoodEntity, FanEntity, RestoreEntity):
|
||||
async def async_decrease_speed(self, percentage_step: int | None = None) -> None:
|
||||
"""Bump speed down by N hardware levels (no recalibration)."""
|
||||
steps = self._steps_from_percentage(percentage_step)
|
||||
minus = await self._codes.async_load_command(COMMAND_MINUS)
|
||||
minus = NovyCookerHoodButton.MINUS.to_command(channel=self._code)
|
||||
for _ in range(steps):
|
||||
await self._async_send(minus)
|
||||
self._level = max(0, self._level - steps)
|
||||
@@ -127,17 +127,17 @@ class NovyCookerHoodFan(NovyCookerHoodEntity, FanEntity, RestoreEntity):
|
||||
|
||||
async def _async_set_level(self, level: int) -> None:
|
||||
"""Reset to off with `SPEED_COUNT` minus presses, then climb to level."""
|
||||
minus = await self._codes.async_load_command(COMMAND_MINUS)
|
||||
minus = NovyCookerHoodButton.MINUS.to_command(channel=self._code)
|
||||
for _ in range(SPEED_COUNT):
|
||||
await self._async_send(minus)
|
||||
if level > 0:
|
||||
plus = await self._codes.async_load_command(COMMAND_PLUS)
|
||||
plus = NovyCookerHoodButton.PLUS.to_command(channel=self._code)
|
||||
for _ in range(level):
|
||||
await self._async_send(plus)
|
||||
self._level = level
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def _async_send(self, command: Any) -> None:
|
||||
async def _async_send(self, command: NovyCookerHoodCommand) -> None:
|
||||
"""Send a single RF command via the configured transmitter."""
|
||||
await async_send_command(
|
||||
self.hass, self._transmitter, command, context=self._context
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
from typing import Any
|
||||
|
||||
from rf_protocols.codes.novy.cooker_hood import get_codes_for_code
|
||||
from rf_protocols.codes.novy.cooker_hood import NovyCookerHoodButton
|
||||
|
||||
from homeassistant.components.light import ColorMode, LightEntity
|
||||
from homeassistant.components.radio_frequency import async_send_command
|
||||
@@ -12,7 +12,6 @@ from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.helpers.restore_state import RestoreEntity
|
||||
|
||||
from .commands import COMMAND_LIGHT
|
||||
from .entity import NovyCookerHoodEntity
|
||||
|
||||
PARALLEL_UPDATES = 1
|
||||
@@ -37,7 +36,7 @@ class NovyCookerHoodLight(NovyCookerHoodEntity, LightEntity, RestoreEntity):
|
||||
def __init__(self, entry: ConfigEntry) -> None:
|
||||
"""Initialize the light."""
|
||||
super().__init__(entry)
|
||||
self._codes = get_codes_for_code(entry.data[CONF_CODE])
|
||||
self._code = entry.data[CONF_CODE]
|
||||
self._attr_unique_id = entry.entry_id
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
@@ -48,19 +47,19 @@ class NovyCookerHoodLight(NovyCookerHoodEntity, LightEntity, RestoreEntity):
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the light on by sending the toggle command."""
|
||||
await self._async_send_command(COMMAND_LIGHT)
|
||||
await self._async_send_light()
|
||||
self._attr_is_on = True
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the light off by sending the toggle command."""
|
||||
await self._async_send_command(COMMAND_LIGHT)
|
||||
await self._async_send_light()
|
||||
self._attr_is_on = False
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def _async_send_command(self, name: str) -> None:
|
||||
"""Load the named command and send it via the configured transmitter."""
|
||||
command = await self._codes.async_load_command(name)
|
||||
async def _async_send_light(self) -> None:
|
||||
"""Send the light toggle command via the configured transmitter."""
|
||||
command = NovyCookerHoodButton.LIGHT.to_command(channel=self._code)
|
||||
await async_send_command(
|
||||
self.hass, self._transmitter, command, context=self._context
|
||||
)
|
||||
|
||||
@@ -5,5 +5,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/radio_frequency",
|
||||
"integration_type": "entity",
|
||||
"quality_scale": "internal",
|
||||
"requirements": ["rf-protocols==3.2.0"]
|
||||
"requirements": ["rf-protocols==4.0.0"]
|
||||
}
|
||||
|
||||
Generated
+1
-1
@@ -47,7 +47,7 @@ python-slugify==8.0.4
|
||||
PyTurboJPEG==1.8.3
|
||||
PyYAML==6.0.3
|
||||
requests==2.34.2
|
||||
rf-protocols==3.2.0
|
||||
rf-protocols==4.0.0
|
||||
securetar==2026.4.1
|
||||
SQLAlchemy==2.0.49
|
||||
standard-aifc==3.13.0
|
||||
|
||||
Generated
+1
-1
@@ -2874,7 +2874,7 @@ renson-endura-delta==1.7.2
|
||||
reolink-aio==0.20.0
|
||||
|
||||
# homeassistant.components.radio_frequency
|
||||
rf-protocols==3.2.0
|
||||
rf-protocols==4.0.0
|
||||
|
||||
# homeassistant.components.idteck_prox
|
||||
rfk101py==0.0.1
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
"""Common fixtures for the Novy Cooker Hood tests."""
|
||||
|
||||
from collections.abc import Iterator
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
import pytest
|
||||
from rf_protocols.loader import CodeCollection
|
||||
|
||||
from homeassistant.components.novy_cooker_hood.const import CONF_TRANSMITTER, DOMAIN
|
||||
from homeassistant.const import CONF_CODE
|
||||
@@ -12,38 +8,11 @@ from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.components.radio_frequency.common import (
|
||||
MockRadioFrequencyCommand,
|
||||
MockRadioFrequencyEntity,
|
||||
)
|
||||
from tests.components.radio_frequency.common import MockRadioFrequencyEntity
|
||||
|
||||
TRANSMITTER_ENTITY_ID = "radio_frequency.test_rf_transmitter"
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def mock_get_codes() -> Iterator[MagicMock]:
|
||||
"""Patch the bundled-codes loader so tests don't hit the filesystem."""
|
||||
fake_collection = MagicMock(spec=CodeCollection)
|
||||
fake_collection.async_load_command = AsyncMock(
|
||||
side_effect=lambda name: MockRadioFrequencyCommand()
|
||||
)
|
||||
with (
|
||||
patch(
|
||||
"homeassistant.components.novy_cooker_hood.light.get_codes_for_code",
|
||||
return_value=fake_collection,
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.novy_cooker_hood.fan.get_codes_for_code",
|
||||
return_value=fake_collection,
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.novy_cooker_hood.config_flow.get_codes_for_code",
|
||||
return_value=fake_collection,
|
||||
),
|
||||
):
|
||||
yield fake_collection
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_config_entry(
|
||||
mock_rf_entity: MockRadioFrequencyEntity,
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
"""Test the Novy Hood config flow."""
|
||||
|
||||
from collections.abc import Iterator
|
||||
from unittest.mock import MagicMock, patch
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
from rf_protocols.codes.novy.cooker_hood import NovyCookerHoodButton
|
||||
|
||||
from homeassistant.components.novy_cooker_hood.commands import COMMAND_LIGHT
|
||||
from homeassistant.components.novy_cooker_hood.const import CONF_TRANSMITTER, DOMAIN
|
||||
from homeassistant.components.radio_frequency import DATA_COMPONENT, DOMAIN as RF_DOMAIN
|
||||
from homeassistant.config_entries import SOURCE_USER
|
||||
@@ -49,7 +49,6 @@ async def _start_user_flow(hass: HomeAssistant, code: str = "1") -> dict:
|
||||
|
||||
async def test_user_flow_test_then_finish(
|
||||
hass: HomeAssistant,
|
||||
mock_get_codes: MagicMock,
|
||||
mock_rf_entity: MockRadioFrequencyEntity,
|
||||
entity_registry: er.EntityRegistry,
|
||||
) -> None:
|
||||
@@ -58,8 +57,10 @@ async def test_user_flow_test_then_finish(
|
||||
|
||||
assert result["type"] is FlowResultType.MENU
|
||||
assert result["step_id"] == "test_light"
|
||||
mock_get_codes.async_load_command.assert_awaited_with(COMMAND_LIGHT)
|
||||
assert len(mock_rf_entity.send_command_calls) == 2
|
||||
sent = mock_rf_entity.send_command_calls[0].command
|
||||
assert sent.key == NovyCookerHoodButton.LIGHT.code
|
||||
assert sent.channel == 3
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], user_input={"next_step_id": "finish"}
|
||||
@@ -77,7 +78,6 @@ async def test_user_flow_test_then_finish(
|
||||
|
||||
async def test_user_flow_retry_picks_different_code(
|
||||
hass: HomeAssistant,
|
||||
mock_get_codes: MagicMock,
|
||||
mock_rf_entity: MockRadioFrequencyEntity,
|
||||
entity_registry: er.EntityRegistry,
|
||||
) -> None:
|
||||
@@ -99,9 +99,13 @@ async def test_user_flow_retry_picks_different_code(
|
||||
},
|
||||
)
|
||||
assert result["type"] is FlowResultType.MENU
|
||||
# One load per test x two tests; two sends per test x two tests.
|
||||
assert mock_get_codes.async_load_command.await_count == 2
|
||||
assert len(mock_rf_entity.send_command_calls) == 4
|
||||
assert [c.command.channel for c in mock_rf_entity.send_command_calls] == [
|
||||
1,
|
||||
1,
|
||||
7,
|
||||
7,
|
||||
]
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], user_input={"next_step_id": "finish"}
|
||||
@@ -127,7 +131,6 @@ async def test_user_flow_test_transmit_failure(
|
||||
|
||||
async def test_recover_after_transmit_failure(
|
||||
hass: HomeAssistant,
|
||||
mock_get_codes: MagicMock,
|
||||
mock_rf_entity: MockRadioFrequencyEntity,
|
||||
) -> None:
|
||||
"""The user can Retry from test_failed and complete the flow."""
|
||||
@@ -183,7 +186,6 @@ async def test_unique_id_already_configured(
|
||||
|
||||
async def test_same_transmitter_different_code_is_allowed(
|
||||
hass: HomeAssistant,
|
||||
mock_get_codes: MagicMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_rf_entity: MockRadioFrequencyEntity,
|
||||
entity_registry: er.EntityRegistry,
|
||||
@@ -205,7 +207,6 @@ async def test_same_transmitter_different_code_is_allowed(
|
||||
|
||||
async def test_reconfigure_updates_entry(
|
||||
hass: HomeAssistant,
|
||||
mock_get_codes: MagicMock,
|
||||
init_novy_cooker_hood: MockConfigEntry,
|
||||
mock_rf_entity: MockRadioFrequencyEntity,
|
||||
entity_registry: er.EntityRegistry,
|
||||
@@ -224,7 +225,9 @@ async def test_reconfigure_updates_entry(
|
||||
)
|
||||
assert result["type"] is FlowResultType.MENU
|
||||
assert result["step_id"] == "test_light"
|
||||
mock_get_codes.async_load_command.assert_awaited_with(COMMAND_LIGHT)
|
||||
sent = mock_rf_entity.send_command_calls[-1].command
|
||||
assert sent.key == NovyCookerHoodButton.LIGHT.code
|
||||
assert sent.channel == 4
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], user_input={"next_step_id": "finish"}
|
||||
@@ -239,7 +242,6 @@ async def test_reconfigure_updates_entry(
|
||||
|
||||
async def test_reconfigure_frees_old_unique_id(
|
||||
hass: HomeAssistant,
|
||||
mock_get_codes: MagicMock,
|
||||
init_novy_cooker_hood: MockConfigEntry,
|
||||
mock_rf_entity: MockRadioFrequencyEntity,
|
||||
) -> None:
|
||||
@@ -295,7 +297,6 @@ async def test_reconfigure_aborts_on_collision(
|
||||
|
||||
async def test_reconfigure_retry_returns_to_picker(
|
||||
hass: HomeAssistant,
|
||||
mock_get_codes: MagicMock,
|
||||
init_novy_cooker_hood: MockConfigEntry,
|
||||
mock_rf_entity: MockRadioFrequencyEntity,
|
||||
) -> None:
|
||||
@@ -326,7 +327,6 @@ async def test_no_transmitters(hass: HomeAssistant) -> None:
|
||||
|
||||
async def test_recover_after_no_transmitters(
|
||||
hass: HomeAssistant,
|
||||
mock_get_codes: MagicMock,
|
||||
) -> None:
|
||||
"""User can re-init the flow after the radio_frequency integration loads."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
"""Tests for the Novy Hood light platform."""
|
||||
|
||||
from unittest.mock import MagicMock, call
|
||||
from rf_protocols.codes.novy.cooker_hood import NovyCookerHoodButton
|
||||
|
||||
from homeassistant.components.light import (
|
||||
DOMAIN as LIGHT_DOMAIN,
|
||||
SERVICE_TURN_OFF,
|
||||
SERVICE_TURN_ON,
|
||||
)
|
||||
from homeassistant.components.novy_cooker_hood.commands import COMMAND_LIGHT
|
||||
from homeassistant.const import (
|
||||
ATTR_ASSUMED_STATE,
|
||||
ATTR_ENTITY_ID,
|
||||
@@ -28,7 +27,6 @@ ENTITY_ID = "light.novy_cooker_hood_light"
|
||||
|
||||
async def test_turn_on_and_off_send_light_once_each(
|
||||
hass: HomeAssistant,
|
||||
mock_get_codes: MagicMock,
|
||||
mock_rf_entity: MockRadioFrequencyEntity,
|
||||
init_novy_cooker_hood: MockConfigEntry,
|
||||
) -> None:
|
||||
@@ -66,11 +64,11 @@ async def test_turn_on_and_off_send_light_once_each(
|
||||
state = hass.states.get(ENTITY_ID)
|
||||
assert state is not None
|
||||
assert state.state == STATE_OFF
|
||||
assert mock_get_codes.async_load_command.await_args_list == [
|
||||
call(COMMAND_LIGHT),
|
||||
call(COMMAND_LIGHT),
|
||||
]
|
||||
assert len(mock_rf_entity.send_command_calls) == 2
|
||||
assert [c.command.key for c in mock_rf_entity.send_command_calls] == [
|
||||
NovyCookerHoodButton.LIGHT.code,
|
||||
NovyCookerHoodButton.LIGHT.code,
|
||||
]
|
||||
|
||||
|
||||
async def test_restore_state(
|
||||
|
||||
Reference in New Issue
Block a user