Skip to content
Snippets Groups Projects
Unverified Commit 2611f72f authored by mvn23's avatar mvn23 Committed by GitHub
Browse files

Add LED mode select entities to opentherm_gw (#125702)

Add select entities for LED mode to opentherm_gw
parent 1be455e0
No related branches found
No related tags found
No related merge requests found
...@@ -5,7 +5,16 @@ from dataclasses import dataclass ...@@ -5,7 +5,16 @@ from dataclasses import dataclass
from enum import IntEnum, StrEnum from enum import IntEnum, StrEnum
from functools import partial 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.components.select import SelectEntity, SelectEntityDescription
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
...@@ -37,6 +46,23 @@ class OpenThermSelectGPIOMode(StrEnum): ...@@ -37,6 +46,23 @@ class OpenThermSelectGPIOMode(StrEnum):
DHW_BLOCK = "dhw_block" 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): class PyotgwGPIOMode(IntEnum):
"""pyotgw GPIO modes.""" """pyotgw GPIO modes."""
...@@ -51,6 +77,34 @@ class PyotgwGPIOMode(IntEnum): ...@@ -51,6 +77,34 @@ class PyotgwGPIOMode(IntEnum):
DHW_BLOCK = 8 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( async def set_gpio_mode(
gpio_id: str, gw_hub: OpenThermGatewayHub, mode: str gpio_id: str, gw_hub: OpenThermGatewayHub, mode: str
) -> OpenThermSelectGPIOMode | None: ) -> OpenThermSelectGPIOMode | None:
...@@ -65,6 +119,20 @@ async def set_gpio_mode( ...@@ -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) @dataclass(frozen=True, kw_only=True)
class OpenThermSelectEntityDescription( class OpenThermSelectEntityDescription(
OpenThermEntityDescription, SelectEntityDescription OpenThermEntityDescription, SelectEntityDescription
...@@ -106,6 +174,60 @@ SELECT_DESCRIPTIONS: tuple[OpenThermSelectEntityDescription, ...] = ( ...@@ -106,6 +174,60 @@ SELECT_DESCRIPTIONS: tuple[OpenThermSelectEntityDescription, ...] = (
else None 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 @@ ...@@ -172,6 +172,23 @@
"ds1820": "DS1820", "ds1820": "DS1820",
"dhw_block": "Block hot water" "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": { "sensor": {
......
"""Test opentherm_gw select entities.""" """Test opentherm_gw select entities."""
from typing import Any
from unittest.mock import AsyncMock, MagicMock 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 import pytest
from homeassistant.components.opentherm_gw import DOMAIN as OPENTHERM_DOMAIN from homeassistant.components.opentherm_gw import DOMAIN as OPENTHERM_DOMAIN
...@@ -13,7 +23,9 @@ from homeassistant.components.opentherm_gw.const import ( ...@@ -13,7 +23,9 @@ from homeassistant.components.opentherm_gw.const import (
) )
from homeassistant.components.opentherm_gw.select import ( from homeassistant.components.opentherm_gw.select import (
OpenThermSelectGPIOMode, OpenThermSelectGPIOMode,
OpenThermSelectLEDMode,
PyotgwGPIOMode, PyotgwGPIOMode,
PyotgwLEDMode,
) )
from homeassistant.components.select import ( from homeassistant.components.select import (
ATTR_OPTION, ATTR_OPTION,
...@@ -29,23 +41,90 @@ from tests.common import MockConfigEntry ...@@ -29,23 +41,90 @@ from tests.common import MockConfigEntry
@pytest.mark.parametrize( @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, hass: HomeAssistant,
entity_registry: er.EntityRegistry, entity_registry: er.EntityRegistry,
mock_config_entry: MockConfigEntry, mock_config_entry: MockConfigEntry,
mock_pyotgw: MagicMock, mock_pyotgw: MagicMock,
entity_key: str, entity_key: str,
gpio_id: str, target_func_name: str,
target_param_1: str,
target_param_2: str | int,
resulting_state: str,
) -> None: ) -> None:
"""Test GPIO mode selector.""" """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) mock_config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(mock_config_entry.entry_id) await hass.config_entries.async_setup(mock_config_entry.entry_id)
...@@ -63,29 +142,56 @@ async def test_gpio_mode_select( ...@@ -63,29 +142,56 @@ async def test_gpio_mode_select(
await hass.services.async_call( await hass.services.async_call(
SELECT_DOMAIN, SELECT_DOMAIN,
SERVICE_SELECT_OPTION, 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, 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( target = getattr(mock_pyotgw.return_value, target_func_name)
gpio_id, PyotgwGPIOMode.VCC.value target.assert_awaited_once_with(target_param_1, target_param_2)
)
@pytest.mark.parametrize( @pytest.mark.parametrize(
("entity_key"), ("entity_key", "test_value", "resulting_state"),
[ [
(OTGW_GPIO_A), (OTGW_GPIO_A, PyotgwGPIOMode.AWAY, OpenThermSelectGPIOMode.AWAY),
(OTGW_GPIO_B), (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, hass: HomeAssistant,
entity_registry: er.EntityRegistry, entity_registry: er.EntityRegistry,
mock_config_entry: MockConfigEntry, mock_config_entry: MockConfigEntry,
mock_pyotgw: MagicMock, mock_pyotgw: MagicMock,
entity_key: str, entity_key: str,
test_value: Any,
resulting_state: str,
) -> None: ) -> None:
"""Test GPIO mode selector.""" """Test GPIO mode selector."""
...@@ -111,10 +217,10 @@ async def test_gpio_mode_state_update( ...@@ -111,10 +217,10 @@ async def test_gpio_mode_state_update(
gw_hub.update_signal, gw_hub.update_signal,
{ {
OpenThermDeviceIdentifier.BOILER: {}, OpenThermDeviceIdentifier.BOILER: {},
OpenThermDeviceIdentifier.GATEWAY: {entity_key: 4}, OpenThermDeviceIdentifier.GATEWAY: {entity_key: test_value},
OpenThermDeviceIdentifier.THERMOSTAT: {}, OpenThermDeviceIdentifier.THERMOSTAT: {},
}, },
) )
await hass.async_block_till_done() 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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment