zigpy-deconz 0.25.2__tar.gz → 0.25.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. {zigpy_deconz-0.25.2/zigpy_deconz.egg-info → zigpy_deconz-0.25.3}/PKG-INFO +1 -1
  2. {zigpy_deconz-0.25.2 → zigpy_deconz-0.25.3}/tests/test_application.py +1 -1
  3. {zigpy_deconz-0.25.2 → zigpy_deconz-0.25.3}/tests/test_network_state.py +103 -6
  4. {zigpy_deconz-0.25.2 → zigpy_deconz-0.25.3}/zigpy_deconz/zigbee/application.py +14 -7
  5. {zigpy_deconz-0.25.2 → zigpy_deconz-0.25.3/zigpy_deconz.egg-info}/PKG-INFO +1 -1
  6. {zigpy_deconz-0.25.2 → zigpy_deconz-0.25.3}/COPYING +0 -0
  7. {zigpy_deconz-0.25.2 → zigpy_deconz-0.25.3}/LICENSE +0 -0
  8. {zigpy_deconz-0.25.2 → zigpy_deconz-0.25.3}/README.md +0 -0
  9. {zigpy_deconz-0.25.2 → zigpy_deconz-0.25.3}/pyproject.toml +0 -0
  10. {zigpy_deconz-0.25.2 → zigpy_deconz-0.25.3}/setup.cfg +0 -0
  11. {zigpy_deconz-0.25.2 → zigpy_deconz-0.25.3}/setup.py +0 -0
  12. {zigpy_deconz-0.25.2 → zigpy_deconz-0.25.3}/tests/test_api.py +0 -0
  13. {zigpy_deconz-0.25.2 → zigpy_deconz-0.25.3}/tests/test_exception.py +0 -0
  14. {zigpy_deconz-0.25.2 → zigpy_deconz-0.25.3}/tests/test_send_receive.py +0 -0
  15. {zigpy_deconz-0.25.2 → zigpy_deconz-0.25.3}/tests/test_types.py +0 -0
  16. {zigpy_deconz-0.25.2 → zigpy_deconz-0.25.3}/tests/test_uart.py +0 -0
  17. {zigpy_deconz-0.25.2 → zigpy_deconz-0.25.3}/tests/test_utils.py +0 -0
  18. {zigpy_deconz-0.25.2 → zigpy_deconz-0.25.3}/zigpy_deconz/__init__.py +0 -0
  19. {zigpy_deconz-0.25.2 → zigpy_deconz-0.25.3}/zigpy_deconz/api.py +0 -0
  20. {zigpy_deconz-0.25.2 → zigpy_deconz-0.25.3}/zigpy_deconz/config.py +0 -0
  21. {zigpy_deconz-0.25.2 → zigpy_deconz-0.25.3}/zigpy_deconz/exception.py +0 -0
  22. {zigpy_deconz-0.25.2 → zigpy_deconz-0.25.3}/zigpy_deconz/types.py +0 -0
  23. {zigpy_deconz-0.25.2 → zigpy_deconz-0.25.3}/zigpy_deconz/uart.py +0 -0
  24. {zigpy_deconz-0.25.2 → zigpy_deconz-0.25.3}/zigpy_deconz/utils.py +0 -0
  25. {zigpy_deconz-0.25.2 → zigpy_deconz-0.25.3}/zigpy_deconz/zigbee/__init__.py +0 -0
  26. {zigpy_deconz-0.25.2 → zigpy_deconz-0.25.3}/zigpy_deconz.egg-info/SOURCES.txt +0 -0
  27. {zigpy_deconz-0.25.2 → zigpy_deconz-0.25.3}/zigpy_deconz.egg-info/dependency_links.txt +0 -0
  28. {zigpy_deconz-0.25.2 → zigpy_deconz-0.25.3}/zigpy_deconz.egg-info/requires.txt +0 -0
  29. {zigpy_deconz-0.25.2 → zigpy_deconz-0.25.3}/zigpy_deconz.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zigpy-deconz
3
- Version: 0.25.2
3
+ Version: 0.25.3
4
4
  Summary: A library which communicates with Deconz radios for zigpy
5
5
  Author-email: Daniel Schmidt <schmidt.d@aon.at>
6
6
  License: GPL-3.0
@@ -556,7 +556,7 @@ async def test_reset_network_info(app):
556
556
  app.form_network = AsyncMock()
557
557
  await app.reset_network_info()
558
558
 
559
- app.form_network.assert_called_once()
559
+ app.form_network.assert_called_once_with(fast=True)
560
560
 
561
561
 
562
562
  async def test_energy_scan_conbee_2(app):
@@ -1,9 +1,10 @@
1
1
  """Test `load_network_info` and `write_network_info` methods."""
2
2
 
3
3
  import importlib.metadata
4
+ from unittest.mock import ANY, call
4
5
 
5
6
  import pytest
6
- from zigpy.exceptions import ControllerException, NetworkNotFormed
7
+ from zigpy.exceptions import CannotWriteNetworkSettings, NetworkNotFormed
7
8
  import zigpy.state as app_state
8
9
  import zigpy.types as t
9
10
  import zigpy.zdo.types as zdo_t
@@ -70,28 +71,55 @@ def network_info(node_info):
70
71
  @patch.object(application, "CHANGE_NETWORK_POLL_TIME", 0.001)
71
72
  @patch.object(application, "CHANGE_NETWORK_STATE_DELAY", 0.001)
72
73
  @pytest.mark.parametrize(
73
- "channel_mask, channel, security_level, fw_supports_fc, logical_type",
74
+ (
75
+ "channel_mask",
76
+ "channel",
77
+ "security_level",
78
+ "fw_supports_fc",
79
+ "logical_type",
80
+ "tx_counter",
81
+ "should_error",
82
+ ),
74
83
  [
84
+ # FW supports frame counter
75
85
  (
76
86
  t.Channels.from_channel_list([15]),
77
87
  15,
78
88
  0,
79
89
  True,
80
90
  zdo_t.LogicalType.Coordinator,
91
+ 39009277,
92
+ False,
93
+ ),
94
+ # FW doesn't support but we're writing blank settings (tx_counter == 0)
95
+ (
96
+ t.Channels.from_channel_list([15]),
97
+ 15,
98
+ 5,
99
+ False,
100
+ zdo_t.LogicalType.Coordinator,
101
+ 0,
102
+ False,
81
103
  ),
104
+ # FW doesn't support and we're writing real settings (should error)
82
105
  (
83
106
  t.Channels.from_channel_list([15]),
84
107
  15,
85
108
  0,
86
109
  False,
87
110
  zdo_t.LogicalType.Coordinator,
111
+ 39009277,
112
+ True,
88
113
  ),
114
+ # Additional test cases with FW support
89
115
  (
90
116
  t.Channels.from_channel_list([15, 20]),
91
117
  15,
92
118
  5,
93
119
  True,
94
120
  zdo_t.LogicalType.Coordinator,
121
+ 39009277,
122
+ False,
95
123
  ),
96
124
  (
97
125
  t.Channels.from_channel_list([15, 20, 25]),
@@ -99,8 +127,18 @@ def network_info(node_info):
99
127
  5,
100
128
  True,
101
129
  zdo_t.LogicalType.Router,
130
+ 39009277,
131
+ False,
132
+ ),
133
+ (
134
+ None,
135
+ 15,
136
+ 5,
137
+ True,
138
+ zdo_t.LogicalType.Coordinator,
139
+ 39009277,
140
+ False,
102
141
  ),
103
- (None, 15, 5, True, zdo_t.LogicalType.Coordinator),
104
142
  ],
105
143
  )
106
144
  async def test_write_network_info(
@@ -112,6 +150,8 @@ async def test_write_network_info(
112
150
  security_level,
113
151
  fw_supports_fc,
114
152
  logical_type,
153
+ tx_counter,
154
+ should_error,
115
155
  ):
116
156
  """Test that network info is correctly written."""
117
157
 
@@ -137,13 +177,14 @@ async def test_write_network_info(
137
177
  channel=channel,
138
178
  channel_mask=channel_mask,
139
179
  security_level=security_level,
180
+ network_key=network_info.network_key.replace(tx_counter=tx_counter),
140
181
  )
141
182
 
142
183
  node_info = node_info.replace(logical_type=logical_type)
143
184
 
144
- if not fw_supports_fc:
185
+ if should_error:
145
186
  with pytest.raises(
146
- ControllerException,
187
+ CannotWriteNetworkSettings,
147
188
  match=(
148
189
  "Please upgrade your adapter firmware. Firmware version 0x26580700 does"
149
190
  " not support writing the network key frame counter, which is required"
@@ -166,7 +207,9 @@ async def test_write_network_info(
166
207
  for call in app._api.write_parameter.await_args_list
167
208
  }
168
209
 
169
- assert params["nwk_frame_counter"] == (network_info.network_key.tx_counter,)
210
+ # Only check frame counter if firmware supports it
211
+ if fw_supports_fc:
212
+ assert params["nwk_frame_counter"] == (network_info.network_key.tx_counter,)
170
213
 
171
214
  if node_info.logical_type == zdo_t.LogicalType.Coordinator:
172
215
  assert params["aps_designed_coordinator"] == (1,)
@@ -328,3 +371,57 @@ async def test_load_network_info(
328
371
  assert app.state.network_info == network_info
329
372
 
330
373
  assert app.state.node_info == node_info.replace(**node_state_changes)
374
+
375
+
376
+ @patch.object(application, "CHANGE_NETWORK_POLL_TIME", 0.001)
377
+ @patch.object(application, "CHANGE_NETWORK_STATE_DELAY", 0.001)
378
+ async def test_form_network_fast_without_frame_counter_support(app): # noqa: F811
379
+ """Test that form_network(fast=True) works when FW doesn't support frame counter."""
380
+
381
+ async def write_parameter(param, *args):
382
+ if param == zigpy_deconz.api.NetworkParameter.nwk_frame_counter:
383
+ raise zigpy_deconz.exception.CommandError(
384
+ "Command is unsupported",
385
+ status=zigpy_deconz.api.Status.UNSUPPORTED,
386
+ command=None,
387
+ )
388
+
389
+ app._change_network_state = AsyncMock()
390
+ app._api.write_parameter = AsyncMock(side_effect=write_parameter)
391
+ app.backups = AsyncMock()
392
+ app.backups.restore_backup = AsyncMock()
393
+
394
+ # This should not raise an error because fast=True sets form_quickly
395
+ await app.form_network(fast=True)
396
+
397
+ # Verify that restore_backup was called with create_new=False (due to fast=True)
398
+ assert app.backups.restore_backup.mock_calls == [
399
+ call(backup=ANY, counter_increment=0, allow_incomplete=True, create_new=False)
400
+ ]
401
+
402
+
403
+ @patch.object(application, "CHANGE_NETWORK_POLL_TIME", 0.001)
404
+ @patch.object(application, "CHANGE_NETWORK_STATE_DELAY", 0.001)
405
+ async def test_reset_network_info_without_frame_counter_support(app): # noqa: F811
406
+ """Test that reset_network_info works even when FW doesn't support frame counter."""
407
+
408
+ async def write_parameter(param, *args):
409
+ if param == zigpy_deconz.api.NetworkParameter.nwk_frame_counter:
410
+ raise zigpy_deconz.exception.CommandError(
411
+ "Command is unsupported",
412
+ status=zigpy_deconz.api.Status.UNSUPPORTED,
413
+ command=None,
414
+ )
415
+
416
+ app._change_network_state = AsyncMock()
417
+ app._api.write_parameter = AsyncMock(side_effect=write_parameter)
418
+ app.backups = AsyncMock()
419
+ app.backups.restore_backup = AsyncMock()
420
+
421
+ # Should not raise an error because reset_network_info calls form_network(fast=True)
422
+ await app.reset_network_info()
423
+
424
+ # Verify that restore_backup was called once (via form_network)
425
+ assert app.backups.restore_backup.mock_calls == [
426
+ call(backup=ANY, counter_increment=0, allow_incomplete=True, create_new=False)
427
+ ]
@@ -180,7 +180,7 @@ class ControllerApplication(zigpy.application.ControllerApplication):
180
180
 
181
181
  async def reset_network_info(self):
182
182
  # TODO: There does not appear to be a way to factory reset a Conbee
183
- await self.form_network()
183
+ await self.form_network(fast=True)
184
184
 
185
185
  async def write_network_info(self, *, network_info, node_info):
186
186
  try:
@@ -189,12 +189,19 @@ class ControllerApplication(zigpy.application.ControllerApplication):
189
189
  )
190
190
  except zigpy_deconz.exception.CommandError as ex:
191
191
  assert ex.status == Status.UNSUPPORTED
192
- fw_version = f"{int(self._api.firmware_version):#010x}"
193
- raise zigpy.exceptions.ControllerException(
194
- f"Please upgrade your adapter firmware. Firmware version {fw_version}"
195
- f" does not support writing the network key frame counter, which is"
196
- f" required for migration to succeed."
197
- )
192
+
193
+ # If we are resetting the adapter or forming a brand new network, we can
194
+ # skip this check
195
+ if not (
196
+ network_info.stack_specific.get("form_quickly", False)
197
+ or network_info.network_key.tx_counter == 0
198
+ ):
199
+ fw_version = f"{int(self._api.firmware_version):#010x}"
200
+ raise zigpy.exceptions.CannotWriteNetworkSettings(
201
+ f"Please upgrade your adapter firmware. Firmware version"
202
+ f" {fw_version} does not support writing the network key frame"
203
+ f" counter, which is required for migration to succeed."
204
+ )
198
205
 
199
206
  if node_info.logical_type == zdo_t.LogicalType.Coordinator:
200
207
  await self._api.write_parameter(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zigpy-deconz
3
- Version: 0.25.2
3
+ Version: 0.25.3
4
4
  Summary: A library which communicates with Deconz radios for zigpy
5
5
  Author-email: Daniel Schmidt <schmidt.d@aon.at>
6
6
  License: GPL-3.0
File without changes
File without changes
File without changes
File without changes
File without changes