Add per-address invert toggles

This commit is contained in:
2026-02-13 13:44:06 +01:00
parent d6ec48e2e6
commit d91d3edc5a
7 changed files with 353 additions and 13 deletions

View File

@@ -13,6 +13,8 @@ from .const import (
CONF_ANGLE_ADDRESS,
CONF_ANGLE_STATE_ADDRESS,
CONF_COMMAND_ADDRESS,
CONF_INVERT_INCOMING,
CONF_INVERT_OUTGOING,
CONF_KNX_ENTRY_ID,
CONF_MOVE_LONG_ADDRESS,
CONF_MOVE_SHORT_ADDRESS,
@@ -94,7 +96,10 @@ class BinarySensorPortSubentryFlow(config_entries.ConfigSubentryFlow):
async def async_step_user(self, user_input: dict | None = None):
if user_input is not None:
user_input, errors = _validate_knx_addresses(
user_input, [CONF_STATE_ADDRESS]
user_input,
[
CONF_STATE_ADDRESS,
],
)
if errors:
return self.async_show_form(
@@ -167,6 +172,12 @@ def _binary_sensor_schema() -> vol.Schema:
vol.Optional(CONF_STATE_ADDRESS): selector.TextSelector(
selector.TextSelectorConfig(type="text")
),
vol.Optional(_invert_in_key(CONF_STATE_ADDRESS), default=False): (
selector.BooleanSelector()
),
vol.Optional(_invert_out_key(CONF_STATE_ADDRESS), default=False): (
selector.BooleanSelector()
),
}
)
@@ -180,24 +191,66 @@ def _cover_schema() -> vol.Schema:
vol.Optional(CONF_MOVE_LONG_ADDRESS): selector.TextSelector(
selector.TextSelectorConfig(type="text")
),
vol.Optional(_invert_in_key(CONF_MOVE_LONG_ADDRESS), default=False): (
selector.BooleanSelector()
),
vol.Optional(_invert_out_key(CONF_MOVE_LONG_ADDRESS), default=False): (
selector.BooleanSelector()
),
vol.Optional(CONF_MOVE_SHORT_ADDRESS): selector.TextSelector(
selector.TextSelectorConfig(type="text")
),
vol.Optional(_invert_in_key(CONF_MOVE_SHORT_ADDRESS), default=False): (
selector.BooleanSelector()
),
vol.Optional(_invert_out_key(CONF_MOVE_SHORT_ADDRESS), default=False): (
selector.BooleanSelector()
),
vol.Optional(CONF_STOP_ADDRESS): selector.TextSelector(
selector.TextSelectorConfig(type="text")
),
vol.Optional(_invert_in_key(CONF_STOP_ADDRESS), default=False): (
selector.BooleanSelector()
),
vol.Optional(_invert_out_key(CONF_STOP_ADDRESS), default=False): (
selector.BooleanSelector()
),
vol.Optional(CONF_POSITION_ADDRESS): selector.TextSelector(
selector.TextSelectorConfig(type="text")
),
vol.Optional(_invert_in_key(CONF_POSITION_ADDRESS), default=False): (
selector.BooleanSelector()
),
vol.Optional(_invert_out_key(CONF_POSITION_ADDRESS), default=False): (
selector.BooleanSelector()
),
vol.Optional(CONF_POSITION_STATE_ADDRESS): selector.TextSelector(
selector.TextSelectorConfig(type="text")
),
vol.Optional(_invert_in_key(CONF_POSITION_STATE_ADDRESS), default=False): (
selector.BooleanSelector()
),
vol.Optional(_invert_out_key(CONF_POSITION_STATE_ADDRESS), default=False): (
selector.BooleanSelector()
),
vol.Optional(CONF_ANGLE_ADDRESS): selector.TextSelector(
selector.TextSelectorConfig(type="text")
),
vol.Optional(_invert_in_key(CONF_ANGLE_ADDRESS), default=False): (
selector.BooleanSelector()
),
vol.Optional(_invert_out_key(CONF_ANGLE_ADDRESS), default=False): (
selector.BooleanSelector()
),
vol.Optional(CONF_ANGLE_STATE_ADDRESS): selector.TextSelector(
selector.TextSelectorConfig(type="text")
),
vol.Optional(_invert_in_key(CONF_ANGLE_STATE_ADDRESS), default=False): (
selector.BooleanSelector()
),
vol.Optional(_invert_out_key(CONF_ANGLE_STATE_ADDRESS), default=False): (
selector.BooleanSelector()
),
}
)
@@ -211,9 +264,21 @@ def _switch_schema() -> vol.Schema:
vol.Optional(CONF_COMMAND_ADDRESS): selector.TextSelector(
selector.TextSelectorConfig(type="text")
),
vol.Optional(_invert_in_key(CONF_COMMAND_ADDRESS), default=False): (
selector.BooleanSelector()
),
vol.Optional(_invert_out_key(CONF_COMMAND_ADDRESS), default=False): (
selector.BooleanSelector()
),
vol.Optional(CONF_STATE_ADDRESS): selector.TextSelector(
selector.TextSelectorConfig(type="text")
),
vol.Optional(_invert_in_key(CONF_STATE_ADDRESS), default=False): (
selector.BooleanSelector()
),
vol.Optional(_invert_out_key(CONF_STATE_ADDRESS), default=False): (
selector.BooleanSelector()
),
}
)
@@ -229,6 +294,8 @@ def _validate_knx_addresses(
value = cleaned.get(key)
if value is None:
cleaned.pop(key, None)
cleaned.pop(_invert_in_key(key), None)
cleaned.pop(_invert_out_key(key), None)
continue
try:
normalized = _normalize_group_address(str(value))
@@ -237,6 +304,8 @@ def _validate_knx_addresses(
continue
if normalized == "":
cleaned.pop(key, None)
cleaned.pop(_invert_in_key(key), None)
cleaned.pop(_invert_out_key(key), None)
else:
cleaned[key] = normalized
return cleaned, errors
@@ -269,3 +338,11 @@ def _parse_int(value: str) -> int:
if text == "":
raise ValueError("empty group address part")
return int(text)
def _invert_in_key(address_key: str) -> str:
return f"{address_key}_{CONF_INVERT_INCOMING}"
def _invert_out_key(address_key: str) -> str:
return f"{address_key}_{CONF_INVERT_OUTGOING}"