Add LED mode select entities to opentherm_gw (#125702)
Add select entities for LED mode to opentherm_gwpull/125705/head
parent
1be455e0e0
commit
2611f72f5d
|
@ -5,7 +5,16 @@ from dataclasses import dataclass
|
|||
from enum import IntEnum, StrEnum
|
||||
from functools import partial
|
||||
|
||||
from pyotgw.vars import OTGW_GPIO_A, OTGW_GPIO_B
|
||||
from pyotgw.vars import (
|
||||
OTGW_GPIO_A,
|
||||
OTGW_GPIO_B,
|
||||
OTGW_LED_A,
|
||||
OTGW_LED_B,
|
||||
OTGW_LED_C,
|
||||
OTGW_LED_D,
|
||||
OTGW_LED_E,
|
||||
OTGW_LED_F,
|
||||
)
|
||||
|
||||
from homeassistant.components.select import SelectEntity, SelectEntityDescription
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
|
@ -37,6 +46,23 @@ class OpenThermSelectGPIOMode(StrEnum):
|
|||
DHW_BLOCK = "dhw_block"
|
||||
|
||||
|
||||
class OpenThermSelectLEDMode(StrEnum):
|
||||
"""OpenThermGateway LED modes."""
|
||||
|
||||
RX_ANY = "receive_any"
|
||||
TX_ANY = "transmit_any"
|
||||
THERMOSTAT_TRAFFIC = "thermostat_traffic"
|
||||
BOILER_TRAFFIC = "boiler_traffic"
|
||||
SETPOINT_OVERRIDE_ACTIVE = "setpoint_override_active"
|
||||
FLAME_ON = "flame_on"
|
||||
CENTRAL_HEATING_ON = "central_heating_on"
|
||||
HOT_WATER_ON = "hot_water_on"
|
||||
COMFORT_MODE_ON = "comfort_mode_on"
|
||||
TX_ERROR_DETECTED = "transmit_error_detected"
|
||||
BOILER_MAINTENANCE_REQUIRED = "boiler_maintenance_required"
|
||||
RAISED_POWER_MODE_ACTIVE = "raised_power_mode_active"
|
||||
|
||||
|
||||
class PyotgwGPIOMode(IntEnum):
|
||||
"""pyotgw GPIO modes."""
|
||||
|
||||
|
@ -51,6 +77,34 @@ class PyotgwGPIOMode(IntEnum):
|
|||
DHW_BLOCK = 8
|
||||
|
||||
|
||||
class PyotgwLEDMode(StrEnum):
|
||||
"""pyotgw LED modes."""
|
||||
|
||||
RX_ANY = "R"
|
||||
TX_ANY = "X"
|
||||
THERMOSTAT_TRAFFIC = "T"
|
||||
BOILER_TRAFFIC = "B"
|
||||
SETPOINT_OVERRIDE_ACTIVE = "O"
|
||||
FLAME_ON = "F"
|
||||
CENTRAL_HEATING_ON = "H"
|
||||
HOT_WATER_ON = "W"
|
||||
COMFORT_MODE_ON = "C"
|
||||
TX_ERROR_DETECTED = "E"
|
||||
BOILER_MAINTENANCE_REQUIRED = "M"
|
||||
RAISED_POWER_MODE_ACTIVE = "P"
|
||||
|
||||
|
||||
def pyotgw_led_mode_to_ha_led_mode(
|
||||
pyotgw_led_mode: PyotgwLEDMode,
|
||||
) -> OpenThermSelectLEDMode | None:
|
||||
"""Convert pyotgw LED mode to Home Assistant LED mode."""
|
||||
return (
|
||||
OpenThermSelectLEDMode[PyotgwLEDMode(pyotgw_led_mode).name]
|
||||
if pyotgw_led_mode in PyotgwLEDMode
|
||||
else None
|
||||
)
|
||||
|
||||
|
||||
async def set_gpio_mode(
|
||||
gpio_id: str, gw_hub: OpenThermGatewayHub, mode: str
|
||||
) -> OpenThermSelectGPIOMode | None:
|
||||
|
@ -65,6 +119,20 @@ async def set_gpio_mode(
|
|||
)
|
||||
|
||||
|
||||
async def set_led_mode(
|
||||
led_id: str, gw_hub: OpenThermGatewayHub, mode: str
|
||||
) -> OpenThermSelectLEDMode | None:
|
||||
"""Set gpio mode, return selected option or None."""
|
||||
value = await gw_hub.gateway.set_led_mode(
|
||||
led_id, PyotgwLEDMode[OpenThermSelectLEDMode(mode).name]
|
||||
)
|
||||
return (
|
||||
OpenThermSelectLEDMode[PyotgwLEDMode(value).name]
|
||||
if value in PyotgwLEDMode
|
||||
else None
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class OpenThermSelectEntityDescription(
|
||||
OpenThermEntityDescription, SelectEntityDescription
|
||||
|
@ -106,6 +174,60 @@ SELECT_DESCRIPTIONS: tuple[OpenThermSelectEntityDescription, ...] = (
|
|||
else None
|
||||
),
|
||||
),
|
||||
OpenThermSelectEntityDescription(
|
||||
key=OTGW_LED_A,
|
||||
translation_key="led_mode_n",
|
||||
translation_placeholders={"led_id": "A"},
|
||||
device_description=GATEWAY_DEVICE_DESCRIPTION,
|
||||
options=list(OpenThermSelectLEDMode),
|
||||
select_action=partial(set_led_mode, "A"),
|
||||
convert_pyotgw_state_to_ha_state=pyotgw_led_mode_to_ha_led_mode,
|
||||
),
|
||||
OpenThermSelectEntityDescription(
|
||||
key=OTGW_LED_B,
|
||||
translation_key="led_mode_n",
|
||||
translation_placeholders={"led_id": "B"},
|
||||
device_description=GATEWAY_DEVICE_DESCRIPTION,
|
||||
options=list(OpenThermSelectLEDMode),
|
||||
select_action=partial(set_led_mode, "B"),
|
||||
convert_pyotgw_state_to_ha_state=pyotgw_led_mode_to_ha_led_mode,
|
||||
),
|
||||
OpenThermSelectEntityDescription(
|
||||
key=OTGW_LED_C,
|
||||
translation_key="led_mode_n",
|
||||
translation_placeholders={"led_id": "C"},
|
||||
device_description=GATEWAY_DEVICE_DESCRIPTION,
|
||||
options=list(OpenThermSelectLEDMode),
|
||||
select_action=partial(set_led_mode, "C"),
|
||||
convert_pyotgw_state_to_ha_state=pyotgw_led_mode_to_ha_led_mode,
|
||||
),
|
||||
OpenThermSelectEntityDescription(
|
||||
key=OTGW_LED_D,
|
||||
translation_key="led_mode_n",
|
||||
translation_placeholders={"led_id": "D"},
|
||||
device_description=GATEWAY_DEVICE_DESCRIPTION,
|
||||
options=list(OpenThermSelectLEDMode),
|
||||
select_action=partial(set_led_mode, "D"),
|
||||
convert_pyotgw_state_to_ha_state=pyotgw_led_mode_to_ha_led_mode,
|
||||
),
|
||||
OpenThermSelectEntityDescription(
|
||||
key=OTGW_LED_E,
|
||||
translation_key="led_mode_n",
|
||||
translation_placeholders={"led_id": "E"},
|
||||
device_description=GATEWAY_DEVICE_DESCRIPTION,
|
||||
options=list(OpenThermSelectLEDMode),
|
||||
select_action=partial(set_led_mode, "E"),
|
||||
convert_pyotgw_state_to_ha_state=pyotgw_led_mode_to_ha_led_mode,
|
||||
),
|
||||
OpenThermSelectEntityDescription(
|
||||
key=OTGW_LED_F,
|
||||
translation_key="led_mode_n",
|
||||
translation_placeholders={"led_id": "F"},
|
||||
device_description=GATEWAY_DEVICE_DESCRIPTION,
|
||||
options=list(OpenThermSelectLEDMode),
|
||||
select_action=partial(set_led_mode, "F"),
|
||||
convert_pyotgw_state_to_ha_state=pyotgw_led_mode_to_ha_led_mode,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -172,6 +172,23 @@
|
|||
"ds1820": "DS1820",
|
||||
"dhw_block": "Block hot water"
|
||||
}
|
||||
},
|
||||
"led_mode_n": {
|
||||
"name": "LED {led_id} mode",
|
||||
"state": {
|
||||
"receive_any": "Receiving on any interface",
|
||||
"transmit_any": "Transmitting on any interface",
|
||||
"thermostat_traffic": "Traffic on the thermostat interface",
|
||||
"boiler_traffic": "Traffic on the boiler interface",
|
||||
"setpoint_override_active": "Setpoint override is active",
|
||||
"flame_on": "Boiler flame is on",
|
||||
"central_heating_on": "Central heating is on",
|
||||
"hot_water_on": "Hot water is on",
|
||||
"comfort_mode_on": "Comfort mode is on",
|
||||
"transmit_error_detected": "Transmit error detected",
|
||||
"boiler_maintenance_required": "Boiler maintenance required",
|
||||
"raised_power_mode_active": "Raised power mode active"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sensor": {
|
||||
|
|
|
@ -1,8 +1,18 @@
|
|||
"""Test opentherm_gw select entities."""
|
||||
|
||||
from typing import Any
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
|
||||
from pyotgw.vars import OTGW_GPIO_A, OTGW_GPIO_B
|
||||
from pyotgw.vars import (
|
||||
OTGW_GPIO_A,
|
||||
OTGW_GPIO_B,
|
||||
OTGW_LED_A,
|
||||
OTGW_LED_B,
|
||||
OTGW_LED_C,
|
||||
OTGW_LED_D,
|
||||
OTGW_LED_E,
|
||||
OTGW_LED_F,
|
||||
)
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.opentherm_gw import DOMAIN as OPENTHERM_DOMAIN
|
||||
|
@ -13,7 +23,9 @@ from homeassistant.components.opentherm_gw.const import (
|
|||
)
|
||||
from homeassistant.components.opentherm_gw.select import (
|
||||
OpenThermSelectGPIOMode,
|
||||
OpenThermSelectLEDMode,
|
||||
PyotgwGPIOMode,
|
||||
PyotgwLEDMode,
|
||||
)
|
||||
from homeassistant.components.select import (
|
||||
ATTR_OPTION,
|
||||
|
@ -29,23 +41,90 @@ from tests.common import MockConfigEntry
|
|||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("entity_key", "gpio_id"),
|
||||
(
|
||||
"entity_key",
|
||||
"target_func_name",
|
||||
"target_param_1",
|
||||
"target_param_2",
|
||||
"resulting_state",
|
||||
),
|
||||
[
|
||||
(OTGW_GPIO_A, "A"),
|
||||
(OTGW_GPIO_B, "B"),
|
||||
(
|
||||
OTGW_GPIO_A,
|
||||
"set_gpio_mode",
|
||||
"A",
|
||||
PyotgwGPIOMode.VCC,
|
||||
OpenThermSelectGPIOMode.VCC,
|
||||
),
|
||||
(
|
||||
OTGW_GPIO_B,
|
||||
"set_gpio_mode",
|
||||
"B",
|
||||
PyotgwGPIOMode.HOME,
|
||||
OpenThermSelectGPIOMode.HOME,
|
||||
),
|
||||
(
|
||||
OTGW_LED_A,
|
||||
"set_led_mode",
|
||||
"A",
|
||||
PyotgwLEDMode.TX_ANY,
|
||||
OpenThermSelectLEDMode.TX_ANY,
|
||||
),
|
||||
(
|
||||
OTGW_LED_B,
|
||||
"set_led_mode",
|
||||
"B",
|
||||
PyotgwLEDMode.RX_ANY,
|
||||
OpenThermSelectLEDMode.RX_ANY,
|
||||
),
|
||||
(
|
||||
OTGW_LED_C,
|
||||
"set_led_mode",
|
||||
"C",
|
||||
PyotgwLEDMode.BOILER_TRAFFIC,
|
||||
OpenThermSelectLEDMode.BOILER_TRAFFIC,
|
||||
),
|
||||
(
|
||||
OTGW_LED_D,
|
||||
"set_led_mode",
|
||||
"D",
|
||||
PyotgwLEDMode.THERMOSTAT_TRAFFIC,
|
||||
OpenThermSelectLEDMode.THERMOSTAT_TRAFFIC,
|
||||
),
|
||||
(
|
||||
OTGW_LED_E,
|
||||
"set_led_mode",
|
||||
"E",
|
||||
PyotgwLEDMode.FLAME_ON,
|
||||
OpenThermSelectLEDMode.FLAME_ON,
|
||||
),
|
||||
(
|
||||
OTGW_LED_F,
|
||||
"set_led_mode",
|
||||
"F",
|
||||
PyotgwLEDMode.BOILER_MAINTENANCE_REQUIRED,
|
||||
OpenThermSelectLEDMode.BOILER_MAINTENANCE_REQUIRED,
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_gpio_mode_select(
|
||||
async def test_select_change_value(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_pyotgw: MagicMock,
|
||||
entity_key: str,
|
||||
gpio_id: str,
|
||||
target_func_name: str,
|
||||
target_param_1: str,
|
||||
target_param_2: str | int,
|
||||
resulting_state: str,
|
||||
) -> None:
|
||||
"""Test GPIO mode selector."""
|
||||
|
||||
mock_pyotgw.return_value.set_gpio_mode = AsyncMock(return_value=PyotgwGPIOMode.VCC)
|
||||
setattr(
|
||||
mock_pyotgw.return_value,
|
||||
target_func_name,
|
||||
AsyncMock(return_value=target_param_2),
|
||||
)
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
|
||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
|
@ -63,29 +142,56 @@ async def test_gpio_mode_select(
|
|||
await hass.services.async_call(
|
||||
SELECT_DOMAIN,
|
||||
SERVICE_SELECT_OPTION,
|
||||
{ATTR_ENTITY_ID: select_entity_id, ATTR_OPTION: OpenThermSelectGPIOMode.VCC},
|
||||
{ATTR_ENTITY_ID: select_entity_id, ATTR_OPTION: resulting_state},
|
||||
blocking=True,
|
||||
)
|
||||
assert hass.states.get(select_entity_id).state == OpenThermSelectGPIOMode.VCC
|
||||
assert hass.states.get(select_entity_id).state == resulting_state
|
||||
|
||||
mock_pyotgw.return_value.set_gpio_mode.assert_awaited_once_with(
|
||||
gpio_id, PyotgwGPIOMode.VCC.value
|
||||
)
|
||||
target = getattr(mock_pyotgw.return_value, target_func_name)
|
||||
target.assert_awaited_once_with(target_param_1, target_param_2)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("entity_key"),
|
||||
("entity_key", "test_value", "resulting_state"),
|
||||
[
|
||||
(OTGW_GPIO_A),
|
||||
(OTGW_GPIO_B),
|
||||
(OTGW_GPIO_A, PyotgwGPIOMode.AWAY, OpenThermSelectGPIOMode.AWAY),
|
||||
(OTGW_GPIO_B, PyotgwGPIOMode.LED_F, OpenThermSelectGPIOMode.LED_F),
|
||||
(
|
||||
OTGW_LED_A,
|
||||
PyotgwLEDMode.SETPOINT_OVERRIDE_ACTIVE,
|
||||
OpenThermSelectLEDMode.SETPOINT_OVERRIDE_ACTIVE,
|
||||
),
|
||||
(
|
||||
OTGW_LED_B,
|
||||
PyotgwLEDMode.CENTRAL_HEATING_ON,
|
||||
OpenThermSelectLEDMode.CENTRAL_HEATING_ON,
|
||||
),
|
||||
(OTGW_LED_C, PyotgwLEDMode.HOT_WATER_ON, OpenThermSelectLEDMode.HOT_WATER_ON),
|
||||
(
|
||||
OTGW_LED_D,
|
||||
PyotgwLEDMode.COMFORT_MODE_ON,
|
||||
OpenThermSelectLEDMode.COMFORT_MODE_ON,
|
||||
),
|
||||
(
|
||||
OTGW_LED_E,
|
||||
PyotgwLEDMode.TX_ERROR_DETECTED,
|
||||
OpenThermSelectLEDMode.TX_ERROR_DETECTED,
|
||||
),
|
||||
(
|
||||
OTGW_LED_F,
|
||||
PyotgwLEDMode.RAISED_POWER_MODE_ACTIVE,
|
||||
OpenThermSelectLEDMode.RAISED_POWER_MODE_ACTIVE,
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_gpio_mode_state_update(
|
||||
async def test_select_state_update(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_pyotgw: MagicMock,
|
||||
entity_key: str,
|
||||
test_value: Any,
|
||||
resulting_state: str,
|
||||
) -> None:
|
||||
"""Test GPIO mode selector."""
|
||||
|
||||
|
@ -111,10 +217,10 @@ async def test_gpio_mode_state_update(
|
|||
gw_hub.update_signal,
|
||||
{
|
||||
OpenThermDeviceIdentifier.BOILER: {},
|
||||
OpenThermDeviceIdentifier.GATEWAY: {entity_key: 4},
|
||||
OpenThermDeviceIdentifier.GATEWAY: {entity_key: test_value},
|
||||
OpenThermDeviceIdentifier.THERMOSTAT: {},
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert hass.states.get(select_entity_id).state == OpenThermSelectGPIOMode.LED_F
|
||||
assert hass.states.get(select_entity_id).state == resulting_state
|
||||
|
|
Loading…
Reference in New Issue