Skip to content

Commit

Permalink
Enable button lock for hm devices (#1621)
Browse files Browse the repository at this point in the history
  • Loading branch information
SukramJ authored Jul 27, 2024
1 parent a5b3867 commit 9bd74c7
Show file tree
Hide file tree
Showing 10 changed files with 80 additions and 54 deletions.
4 changes: 4 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# Version 2024.7.1 (2024-07-27)

- Enable button lock for hm devices

# Version 2024.7.0 (2024-07-26)

- Rename last_updated -> modified_at
Expand Down
38 changes: 25 additions & 13 deletions hahomematic/caches/visibility.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
# and not for general display.
# {device_type: (channel_no, parameter)}
_RELEVANT_MASTER_PARAMSETS_BY_DEVICE: Final[
Mapping[str, tuple[tuple[int, ...], tuple[Parameter, ...]]]
Mapping[str, tuple[tuple[int | None, ...], tuple[Parameter, ...]]]
] = {
"ALPHA-IP-RBG": (
(0, 1),
Expand All @@ -35,8 +35,16 @@
Parameter.GLOBAL_BUTTON_LOCK,
),
),
"HM-CC-RT-DN": ((1,), (Parameter.TEMPERATURE_MAXIMUM, Parameter.TEMPERATURE_MINIMUM)),
"HM-CC-RT-DN": (
(None, 1),
(
Parameter.TEMPERATURE_MAXIMUM,
Parameter.TEMPERATURE_MINIMUM,
Parameter.GLOBAL_BUTTON_LOCK,
),
),
"HM-CC-VG-1": ((1,), (Parameter.TEMPERATURE_MAXIMUM, Parameter.TEMPERATURE_MINIMUM)),
"HM-TC-IT-WM-W-EU": ((None,), (Parameter.GLOBAL_BUTTON_LOCK,)),
"HmIP-BWTH": (
(0, 1),
(
Expand Down Expand Up @@ -328,20 +336,24 @@ def _init(self) -> None:
self._relevant_master_paramsets_by_device[device_type_l] = set()
if device_type_l not in self._un_ignore_parameters_by_device_paramset_key:
self._un_ignore_parameters_by_device_paramset_key[device_type_l] = {}
for channel_no in channel_nos:
self._relevant_master_paramsets_by_device[device_type_l].add(channel_no)
if (
channel_no
not in self._un_ignore_parameters_by_device_paramset_key[device_type_l]
):
self._un_ignore_parameters_by_device_paramset_key[device_type_l][
channel_no
] = {ParamsetKey.MASTER: set()}
for parameter in parameters:
self._un_ignore_parameters_by_device_paramset_key[device_type_l][channel_no][

def _add_channel(dt_l: str, params: tuple[Parameter, ...], ch_no: int | None) -> None:
self._relevant_master_paramsets_by_device[dt_l].add(ch_no)
if ch_no not in self._un_ignore_parameters_by_device_paramset_key[dt_l]:
self._un_ignore_parameters_by_device_paramset_key[dt_l][ch_no] = {
ParamsetKey.MASTER: set()
}
for parameter in params:
self._un_ignore_parameters_by_device_paramset_key[dt_l][ch_no][
ParamsetKey.MASTER
].add(parameter)

if channel_nos:
for channel_no in channel_nos:
_add_channel(dt_l=device_type_l, params=parameters, ch_no=channel_no)
else:
_add_channel(dt_l=device_type_l, params=parameters, ch_no=None)

@lru_cache(maxsize=128)
def device_type_is_ignored(self, device_type: str) -> bool:
"""Check if a device type should be ignored for custom entities."""
Expand Down
3 changes: 2 additions & 1 deletion hahomematic/platforms/custom/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
class DeviceProfile(StrEnum):
"""Enum for device profiles."""

BUTTON_LOCK = "ButtonLock"
IP_BUTTON_LOCK = "IPButtonLock"
IP_COVER = "IPCover"
IP_DIMMER = "IPDimmer"
IP_DRG_DALI = "IPDRGDALI"
Expand All @@ -24,6 +24,7 @@ class DeviceProfile(StrEnum):
IP_SWITCH = "IPSwitch"
IP_THERMOSTAT = "IPThermostat"
IP_THERMOSTAT_GROUP = "IPThermostatGroup"
RF_BUTTON_LOCK = "RFButtonLock"
RF_COVER = "RfCover"
RF_DIMMER = "RfDimmer"
RF_DIMMER_COLOR = "RfDimmer_Color"
Expand Down
20 changes: 15 additions & 5 deletions hahomematic/platforms/custom/definition.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

SCHEMA_ED_DEVICE_GROUP = vol.Schema(
{
vol.Required(ED.PRIMARY_CHANNEL.value): int,
vol.Required(ED.PRIMARY_CHANNEL.value): vol.Any(int, None),
vol.Optional(ED.SECONDARY_CHANNELS.value): (int,),
vol.Optional(ED.REPEATABLE_FIELDS.value): SCHEMA_ED_FIELD_DETAILS,
vol.Optional(ED.VISIBLE_REPEATABLE_FIELDS.value): SCHEMA_ED_FIELD_DETAILS,
Expand Down Expand Up @@ -279,14 +279,22 @@
},
},
},
DeviceProfile.BUTTON_LOCK: {
DeviceProfile.IP_BUTTON_LOCK: {
ED.DEVICE_GROUP: {
ED.PRIMARY_CHANNEL: 0,
ED.REPEATABLE_FIELDS: {
Field.BUTTON_LOCK: Parameter.GLOBAL_BUTTON_LOCK,
},
},
},
DeviceProfile.RF_BUTTON_LOCK: {
ED.DEVICE_GROUP: {
ED.PRIMARY_CHANNEL: None,
ED.REPEATABLE_FIELDS: {
Field.BUTTON_LOCK: Parameter.GLOBAL_BUTTON_LOCK,
},
},
},
DeviceProfile.IP_SIREN: {
ED.DEVICE_GROUP: {
ED.PRIMARY_CHANNEL: 3,
Expand Down Expand Up @@ -640,11 +648,13 @@ def _get_device_definition(device_profile: DeviceProfile) -> Mapping[ED, Any]:
return cast(Mapping[ED, Any], ENTITY_DEFINITION[ED.DEVICE_DEFINITIONS][device_profile])


def _get_device_group(device_profile: DeviceProfile, base_channel_no: int) -> Mapping[ED, Any]:
def _get_device_group(
device_profile: DeviceProfile, base_channel_no: int | None
) -> Mapping[ED, Any]:
"""Return the device group."""
device = _get_device_definition(device_profile)
group = cast(dict[ED, Any], device[ED.DEVICE_GROUP])
if group and base_channel_no == 0:
if not base_channel_no:
return group

# Create a deep copy of the group due to channel rebase
Expand Down Expand Up @@ -737,7 +747,7 @@ def _get_entity_config_by_platform(

def is_multi_channel_device(device_type: str, platform: HmPlatform) -> bool:
"""Return true, if device has multiple channels."""
channels: list[int] = []
channels: list[int | None] = []
for entity_configs in get_entity_configs(device_type=device_type, platform=platform):
if isinstance(entity_configs, CustomConfig):
channels.extend(entity_configs.channels)
Expand Down
39 changes: 29 additions & 10 deletions hahomematic/platforms/custom/lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,16 +273,31 @@ def make_ip_lock(
)


def make_button_lock(
def make_ip_button_lock(
device: hmd.HmDevice,
group_base_channels: tuple[int, ...],
extended: ExtendedConfig | None = None,
) -> tuple[CustomEntity, ...]:
"""Create HomematicIP lock entities."""
"""Create HomematicIP ip button lock entities."""
return hmed.make_custom_entity(
device=device,
entity_class=CeButtonLock,
device_profile=DeviceProfile.IP_BUTTON_LOCK,
group_base_channels=group_base_channels,
extended=extended,
)


def make_rf_button_lock(
device: hmd.HmDevice,
group_base_channels: tuple[int, ...],
extended: ExtendedConfig | None = None,
) -> tuple[CustomEntity, ...]:
"""Create HomematicIP rf button lock entities."""
return hmed.make_custom_entity(
device=device,
entity_class=CeButtonLock,
device_profile=DeviceProfile.BUTTON_LOCK,
device_profile=DeviceProfile.RF_BUTTON_LOCK,
group_base_channels=group_base_channels,
extended=extended,
)
Expand Down Expand Up @@ -327,32 +342,36 @@ def make_rf_lock(
}
),
),
"HM-TC-IT-WM-W-EU": CustomConfig(
make_ce_func=make_rf_button_lock,
channels=(None,),
),
"ALPHA-IP-RBG": CustomConfig(
make_ce_func=make_button_lock,
make_ce_func=make_ip_button_lock,
channels=(0,),
),
"HmIP-BWTH": CustomConfig(
make_ce_func=make_button_lock,
make_ce_func=make_ip_button_lock,
channels=(0,),
),
"HmIP-FAL": CustomConfig(
make_ce_func=make_button_lock,
make_ce_func=make_ip_button_lock,
channels=(0,),
),
"HmIP-WTH": CustomConfig(
make_ce_func=make_button_lock,
make_ce_func=make_ip_button_lock,
channels=(0,),
),
"HmIP-eTRV": CustomConfig(
make_ce_func=make_button_lock,
make_ce_func=make_ip_button_lock,
channels=(0,),
),
"HmIPW-FAL": CustomConfig(
make_ce_func=make_button_lock,
make_ce_func=make_ip_button_lock,
channels=(0,),
),
"HmIPW-WTH": CustomConfig(
make_ce_func=make_button_lock,
make_ce_func=make_ip_button_lock,
channels=(0,),
),
}
Expand Down
2 changes: 1 addition & 1 deletion hahomematic/platforms/custom/support.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class CustomConfig:
"""Data for custom entity creation."""

make_ce_func: Callable
channels: tuple[int, ...]
channels: tuple[int | None, ...]
extended: ExtendedConfig | None = None


Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "hahomematic"
version = "2024.7.0"
version = "2024.7.1"
license = {text = "MIT License"}
description = "Homematic interface for Home Assistant running on Python 3."
readme = "README.md"
Expand Down
21 changes: 0 additions & 21 deletions tests/test_central.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,34 +231,13 @@ async def test_device_unignore_broll(
@pytest.mark.parametrize(
("line", "parameter", "channel_no", "paramset_key", "expected_result"),
[
(
"GLOBAL_BUTTON_LOCK@HM-TC-IT-WM-W-EU:MASTER",
"GLOBAL_BUTTON_LOCK",
None,
"MASTER",
False,
),
(
"GLOBAL_BUTTON_LOCK:MASTER@HM-TC-IT-WM-W-EU:",
"GLOBAL_BUTTON_LOCK",
None,
"MASTER",
True,
),
(
"GLOBAL_BUTTON_LOCK:MASTER@all:",
"GLOBAL_BUTTON_LOCK",
None,
"MASTER",
False,
),
(
"GLOBAL_BUTTON_LOCK:MASTER@HM-TC-IT-WM-W-EU:all",
"GLOBAL_BUTTON_LOCK",
None,
"MASTER",
False,
),
],
)
@pytest.mark.asyncio()
Expand Down
4 changes: 2 additions & 2 deletions tests/test_central_pydevccu.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,8 @@ async def test_central_full(central_unit_full) -> None:
) as fptr:
fptr.write(orjson.dumps(addresses, option=orjson.OPT_INDENT_2 | orjson.OPT_NON_STR_KEYS))

assert usage_types[EntityUsage.NO_CREATE] == 3213
assert usage_types[EntityUsage.CE_PRIMARY] == 207
assert usage_types[EntityUsage.NO_CREATE] == 3220
assert usage_types[EntityUsage.CE_PRIMARY] == 208
assert usage_types[EntityUsage.ENTITY] == 3707
assert usage_types[EntityUsage.CE_VISIBLE] == 114
assert usage_types[EntityUsage.CE_SECONDARY] == 146
Expand Down
1 change: 1 addition & 0 deletions tests/test_lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"VCU9724704": "HmIP-DLD.json",
"VCU0000146": "HM-Sec-Key.json",
"VCU3609622": "HmIP-eTRV-2.json",
"VCU0000341": "HM-TC-IT-WM-W-EU.json",
}

# pylint: disable=protected-access
Expand Down

0 comments on commit 9bd74c7

Please sign in to comment.