Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clean up Danfoss TRV custom attributes definitions and commands #2150

Merged
merged 93 commits into from
Apr 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
93 commits
Select commit Hold shift + click to select a range
da24506
Danfoss thermostat: Fixup attributes access, types, names and remove …
Caius-Bonus Jan 29, 2023
7d914a7
Danfoss thermostat: remove dead import
Caius-Bonus Jan 29, 2023
b904108
formatted using black
Caius-Bonus Jan 29, 2023
3e745ad
danfoss thermostat: map System Mode (aka Operation Mode or HVAC mode)…
Caius-Bonus Jan 29, 2023
e9282b3
fix unused assignment
Caius-Bonus Jan 29, 2023
f63b21f
danfoss thermostat: fix flake8 issues
Caius-Bonus Jan 29, 2023
bf7d911
danfoss thermostat: use absolute import
Caius-Bonus Feb 1, 2023
4009564
Danfoss thermostat: add trv_operation_mode, occupied_heating_setpoint…
Caius-Bonus Feb 4, 2023
6ebf132
Merge branch 'dev' into dev
Caius-Bonus Feb 4, 2023
4b227d1
reverse automatic edit in file I didn't want to touch
Caius-Bonus Feb 4, 2023
297e0b9
Merge branch 'dev' into dev
Caius-Bonus Aug 11, 2023
78e9047
fix errors
Caius-Bonus Aug 11, 2023
28208e8
fix pre-commit
Caius-Bonus Aug 11, 2023
dcee9be
fix some accidental misuse of identifiers, remove magic strings and n…
Caius-Bonus Aug 11, 2023
14954c9
write tests
Caius-Bonus Aug 12, 2023
d54966c
Merge branch 'zigpy:dev' into dev
Caius-Bonus Sep 2, 2023
7c3017a
refactoring
Caius-Bonus Sep 2, 2023
bcf41d7
remove scheduled setpoint
Caius-Bonus Sep 2, 2023
f70c7de
comment for programming operation mode
Caius-Bonus Sep 2, 2023
a1dc598
remove read_fakeattr and get_result_index
Caius-Bonus Sep 2, 2023
7faa857
fix tests
Caius-Bonus Sep 2, 2023
160592a
comment fix
Caius-Bonus Sep 2, 2023
b2c73b2
increase coverage
Caius-Bonus Sep 2, 2023
279f218
Merge branch 'dev' into dev
Caius-Bonus Sep 13, 2023
a111a63
change cluster ids
Caius-Bonus Sep 13, 2023
0a1e32c
remove custom clusters
Caius-Bonus Sep 19, 2023
2378e60
Merge branch 'dev' into dev
Caius-Bonus Sep 23, 2023
e40da88
move constants out of init file
Caius-Bonus Sep 29, 2023
7dfccd8
fix code quality
Caius-Bonus Sep 29, 2023
bce3c3c
Merge pull request #1 from Caius-Bonus/RemoveCustomClusters
Caius-Bonus Sep 29, 2023
4442b2b
Merge branch 'dev' into dev
Caius-Bonus Sep 29, 2023
b138169
added time sync
Caius-Bonus Oct 2, 2023
aa9694a
move attrs into new datastructure
Caius-Bonus Oct 2, 2023
54a3ef5
refactor comments
Caius-Bonus Oct 2, 2023
69ce96d
fix non-working standard clusters
Caius-Bonus Oct 2, 2023
3089731
style
Caius-Bonus Oct 2, 2023
b81c8f8
add tests
Caius-Bonus Oct 2, 2023
f19e739
remove some lines
Caius-Bonus Oct 2, 2023
6186216
add tests
Caius-Bonus Oct 2, 2023
7e8c74f
styl
Caius-Bonus Oct 2, 2023
9470e40
disallow systemmode=off
Caius-Bonus Oct 2, 2023
188dc17
fix test
Caius-Bonus Oct 2, 2023
337ec1e
remove non-standard programing_oper_mode
Caius-Bonus Oct 19, 2023
c48cd08
align with better cluster documentation
Caius-Bonus Oct 19, 2023
b798074
deviate from documentation, because it works anyway
Caius-Bonus Oct 19, 2023
7a8f8e0
remove accidentally comitted change
Caius-Bonus Oct 19, 2023
e2d5aae
remove unused enum
Caius-Bonus Oct 19, 2023
0102f42
according to the documentation, this should be a new valid danfoss trv
Caius-Bonus Oct 21, 2023
2232b55
Revert "according to the documentation, this should be a new valid da…
Caius-Bonus Oct 24, 2023
bc5568c
add quirk_id
Caius-Bonus Oct 26, 2023
0ccc1d5
Merge branch 'dev' into dev
Caius-Bonus Oct 26, 2023
24edf21
move definition to quirk_ids.py
Caius-Bonus Oct 26, 2023
216527a
black
Caius-Bonus Oct 26, 2023
71cbea2
comment
Caius-Bonus Oct 26, 2023
fc79193
make combine_results more robust
Caius-Bonus Oct 27, 2023
73111fc
reduce code duplication and don't send unnecessary requests
Caius-Bonus Oct 27, 2023
2bdb1dd
code style
Caius-Bonus Oct 27, 2023
4c2a789
comment
Caius-Bonus Oct 27, 2023
cc35dab
change list to List type for compatibility reasons
Caius-Bonus Oct 27, 2023
663c135
remove variable arg Callable for compatibility reasons
Caius-Bonus Oct 27, 2023
23654e7
Merge branch 'dev' into FixDanfossThermostat
Caius-Bonus Oct 31, 2023
2d0862e
black
Caius-Bonus Oct 31, 2023
e8970b2
improve quirk id to ward against future products
Caius-Bonus Nov 2, 2023
169a562
fix variable name
Caius-Bonus Nov 2, 2023
c54626d
use more standard notation
Caius-Bonus Jan 18, 2024
b5e4922
but do use custom clusters
Caius-Bonus Jan 18, 2024
d70cf14
use zcl constants from shared library
Caius-Bonus Jan 25, 2024
e287e24
docstring
Caius-Bonus Jan 30, 2024
08abd4b
define enums in quirk and shorten AttributeDefs usage
Caius-Bonus Feb 4, 2024
5d04d09
capitals and dots in docstrings
Caius-Bonus Feb 4, 2024
e0180a1
documentation
Caius-Bonus Feb 11, 2024
6b43203
fix docstring
Caius-Bonus Feb 13, 2024
fc1646e
simnplify and add enum value to excersice day of the week
Caius-Bonus Feb 13, 2024
d0c640f
add bitmaps and reorder attributes
Caius-Bonus Feb 13, 2024
bd56e0c
change captica,
Caius-Bonus Feb 13, 2024
9bb3d04
Merge branch 'dev' into FixDanfossThermostat
Caius-Bonus Feb 13, 2024
49a4556
correct capitalization for enums and bitmaps
Caius-Bonus Feb 13, 2024
a78b102
comments
Caius-Bonus Feb 13, 2024
4c21b4a
Merge branch 'dev' into FixDanfossThermostat
Caius-Bonus Feb 21, 2024
7ab8a7f
test failure and success correctly
Caius-Bonus Feb 21, 2024
1fcc763
now correclty
Caius-Bonus Feb 21, 2024
77020d4
remove accidentally added line
Caius-Bonus Feb 23, 2024
6013713
Merge branch 'dev' into FixDanfossThermostat
Caius-Bonus Feb 23, 2024
f3b2f58
swap
Caius-Bonus Feb 23, 2024
72f3e77
Merge branch 'dev' into FixDanfossThermostat
Caius-Bonus Apr 9, 2024
c5cc05c
suggestions
Caius-Bonus Apr 9, 2024
2f84b33
ruffle
Caius-Bonus Apr 9, 2024
6d8f204
Update tests/test_danfoss.py
Caius-Bonus Apr 9, 2024
c29ae99
Update tests/test_danfoss.py
Caius-Bonus Apr 9, 2024
d37c214
suggestions
Caius-Bonus Apr 9, 2024
94b6112
fix test
Caius-Bonus Apr 9, 2024
2684a35
Remove empty lines
TheJulianJES Apr 9, 2024
0aa4acf
Merge branch 'dev' into FixDanfossThermostat
TheJulianJES Apr 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
239 changes: 239 additions & 0 deletions tests/test_danfoss.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
"""Tests the Danfoss quirk (all tests were written for the Popp eT093WRO)."""
from unittest import mock

from zigpy.quirks import CustomCluster
from zigpy.zcl import foundation
from zigpy.zcl.clusters.hvac import Thermostat
from zigpy.zcl.foundation import WriteAttributesStatusRecord, ZCLAttributeDef

import zhaquirks
from zhaquirks.danfoss.thermostat import CustomizedStandardCluster

zhaquirks.setup()


def test_popp_signature(assert_signature_matches_quirk):
"""Test the signature matching the Device Class."""
signature = {
"node_descriptor": "NodeDescriptor(logical_type=<LogicalType.EndDevice: 2>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress: 128>, manufacturer_code=4678, maximum_buffer_size=82, maximum_incoming_transfer_size=82, server_mask=11264, maximum_outgoing_transfer_size=82, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=True, *is_full_function_device=False, *is_mains_powered=False, *is_receiver_on_when_idle=False, *is_router=False, *is_security_capable=False)",
# SizePrefixedSimpleDescriptor(endpoint=1, profile=260, device_type=769, device_version=1, input_clusters=[0, 1, 3, 10, 32, 513, 516, 2821], output_clusters=[0, 25])
"endpoints": {
"1": {
"profile_id": 260,
"device_type": "0x0301",
"in_clusters": [
"0x0000",
"0x0001",
"0x0003",
"0x000a",
"0x0020",
"0x0201",
"0x0204",
"0x0b05",
],
"out_clusters": ["0x0000", "0x0019"],
}
},
"manufacturer": "D5X84YU",
"model": "eT093WRO",
"class": "danfoss.thermostat.DanfossThermostat",
}

assert_signature_matches_quirk(
zhaquirks.danfoss.thermostat.DanfossThermostat, signature
)


@mock.patch("zigpy.zcl.Cluster.bind", mock.AsyncMock())
async def test_danfoss_time_bind(zigpy_device_from_quirk):
"""Test the time being set when binding the Time cluster."""
device = zigpy_device_from_quirk(zhaquirks.danfoss.thermostat.DanfossThermostat)

danfoss_time_cluster = device.endpoints[1].time
danfoss_thermostat_cluster = device.endpoints[1].thermostat

def mock_write(attributes, manufacturer=None):
records = [
WriteAttributesStatusRecord(foundation.Status.SUCCESS)
for _ in attributes
]
return [records, []]

patch_danfoss_trv_write = mock.patch.object(
danfoss_time_cluster,
"_write_attributes",
mock.AsyncMock(side_effect=mock_write),
)

with patch_danfoss_trv_write:
await danfoss_thermostat_cluster.bind()

assert 0x0000 in danfoss_time_cluster._attr_cache
assert 0x0001 in danfoss_time_cluster._attr_cache
assert 0x0002 in danfoss_time_cluster._attr_cache


async def test_danfoss_thermostat_write_attributes(zigpy_device_from_quirk):
"""Test the Thermostat writes behaving correctly, in particular regarding setpoint."""
device = zigpy_device_from_quirk(zhaquirks.danfoss.thermostat.DanfossThermostat)

danfoss_thermostat_cluster = device.endpoints[1].thermostat

def mock_write(attributes, manufacturer=None):
records = [
WriteAttributesStatusRecord(foundation.Status.SUCCESS)
for _ in attributes
]
return [records, []]

setting = -100
operation = -0x01

def mock_setpoint(oper, sett, manufacturer=None):
nonlocal operation, setting
operation = oper
setting = sett

# data is written to trv
patch_danfoss_trv_write = mock.patch.object(
danfoss_thermostat_cluster,
"_write_attributes",
mock.AsyncMock(side_effect=mock_write),
)
patch_danfoss_setpoint = mock.patch.object(
danfoss_thermostat_cluster,
"setpoint_command",
mock.AsyncMock(side_effect=mock_setpoint),
)

with patch_danfoss_trv_write:
# data should be written to trv, but reach thermostat
success, fail = await danfoss_thermostat_cluster.write_attributes(
{"external_open_window_detected": False}
)
assert success
assert not fail
assert not danfoss_thermostat_cluster._attr_cache[0x4003]

with patch_danfoss_setpoint:
# data should be received from danfoss_trv
success, fail = await danfoss_thermostat_cluster.write_attributes(
{"occupied_heating_setpoint": 6}
)
assert success
assert not fail
assert danfoss_thermostat_cluster._attr_cache[0x0012] == 6
assert operation == 0x01
assert setting == 6

danfoss_thermostat_cluster._attr_cache[
0x0015
] = 5 # min_limit is present normally

success, fail = await danfoss_thermostat_cluster.write_attributes(
{"system_mode": 0x00}
)
assert success
assert not fail
assert danfoss_thermostat_cluster._attr_cache[0x001C] == 0x04

# setpoint to min_limit, when system_mode to off
assert danfoss_thermostat_cluster._attr_cache[0x0012] == 5

assert operation == 0x01
assert setting == 5


async def test_customized_standardcluster(zigpy_device_from_quirk):
"""Test customized standard cluster class correctly separating zigbee operations.

This is regarding manufacturer specific attributes.
"""
device = zigpy_device_from_quirk(zhaquirks.danfoss.thermostat.DanfossThermostat)

danfoss_thermostat_cluster = device.endpoints[1].in_clusters[Thermostat.cluster_id]

assert CustomizedStandardCluster.combine_results([[4545], [5433]], [[345]]) == [
[4545, 345],
[5433],
]
assert CustomizedStandardCluster.combine_results(
[[4545], [5433]], [[345], [45355]]
) == [[4545, 345], [5433, 45355]]

mock_attributes = {
656: ZCLAttributeDef(is_manufacturer_specific=True),
56454: ZCLAttributeDef(is_manufacturer_specific=False),
}

danfoss_thermostat_cluster.attributes = mock_attributes

reports = None

def mock_configure_reporting(reps, *args, **kwargs):
nonlocal reports
if mock_attributes[reps[0].attrid].is_manufacturer_specific:
reports = reps

return [[545], [4545]]

# data is written to trv
patch_danfoss_configure_reporting = mock.patch.object(
CustomCluster,
"_configure_reporting",
mock.AsyncMock(side_effect=mock_configure_reporting),
)

with patch_danfoss_configure_reporting:
one = foundation.AttributeReportingConfig()
one.direction = True
one.timeout = 4
one.attrid = 56454

two = foundation.AttributeReportingConfig()
two.direction = True
two.timeout = 4
two.attrid = 656
await danfoss_thermostat_cluster._configure_reporting([one, two])
assert reports == [two]

reports = None

def mock_read_attributes(attrs, *args, **kwargs):
nonlocal reports
if mock_attributes[attrs[0]].is_manufacturer_specific:
reports = attrs

return [[545]]

# data is written to trv
patch_danfoss_read_attributes = mock.patch.object(
CustomCluster,
"_read_attributes",
mock.AsyncMock(side_effect=mock_read_attributes),
)

with patch_danfoss_read_attributes:
result = await danfoss_thermostat_cluster._read_attributes([56454, 656])
assert result
assert reports == [656]

def mock_read_attributes_fail(attrs, *args, **kwargs):
nonlocal reports
if mock_attributes[attrs[0]].is_manufacturer_specific:
reports = attrs

return [[545], [4545]]

# data is written to trv
patch_danfoss_read_attributes_fail = mock.patch.object(
CustomCluster,
"_read_attributes",
mock.AsyncMock(side_effect=mock_read_attributes_fail),
)

with patch_danfoss_read_attributes_fail:
result, fail = await danfoss_thermostat_cluster._read_attributes([56454, 656])
assert result
assert fail
assert reports == [656]
2 changes: 0 additions & 2 deletions zhaquirks/danfoss/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
"""Module for Danfoss quirks implementations."""
DANFOSS = "Danfoss"
D5X84YU = "D5X84YU"
Loading
Loading