Fix H500 hub child list handling in SMART flows.#1695
Open
jimboca wants to merge 3 commits into
Open
Fix H500 hub child list handling in SMART flows.#1695jimboca wants to merge 3 commits into
jimboca wants to merge 3 commits into
Conversation
Handle paginated SMART/SMARTCAM child responses that omit list fields to avoid StopIteration and KeyError crashes on Tapo H500, and add regression coverage for the no-list pagination shape. Co-authored-by: Cursor <cursoragent@cursor.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1695 +/- ##
==========================================
- Coverage 93.22% 93.18% -0.05%
==========================================
Files 157 157
Lines 9815 9839 +24
Branches 1003 1010 +7
==========================================
+ Hits 9150 9168 +18
- Misses 472 475 +3
- Partials 193 196 +3 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Exercise the H500 defensive child-list fallbacks directly so Codecov sees the new no-list paths as covered. Co-authored-by: Cursor <cursoragent@cursor.com>
…els. Treat non-dict get_device_info/component_nego payloads as transient device errors and make Device.__repr__ fall back to a safe host-only form, so H500 and camera responses with SmartErrorCode do not blow up logging or model access. Keep the repr fallback explicitly string-typed so mypy accepts the exception path as well. Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Handle paginated SMART/SMARTCAM child responses that omit list fields to avoid StopIteration and KeyError crashes on Tapo H500, and add regression coverage for the no-list pagination shape.
Summary
SmartProtocol._handle_response_liststo safely handle paginated responses that includestart_indexandsumbut do not include any list-typed fields.StopIteration(fromnext(iter(...))) which surfaces asRuntimeError: coroutine raised StopIterationin async flows.test_handle_response_lists_no_list_fieldsintests/protocols/test_smartprotocol.py.Why
Some devices (observed with Tapo H500) can return a paginated response shape where no list key is present. Current code assumes at least one list field exists and raises at runtime. This causes repeated update failures during negotiation/discovery.
Changes
kasa/protocols/smartprotocol.py:next(iter([...]))assumption with:list_keystests/protocols/test_smartprotocol.py:start_index/sum+ non-list payload shape.Test Plan
python -m pytest -o addopts='' tests/protocols/test_smartprotocol.py::test_handle_response_lists_no_list_fields -q --tb=shortStopIteration/ runtime crash in this path).Notes
First change resulted in a traceback still showing up:
2026-05-06 07:21:49.180 Thread-10 (run_forever) udi_interface ERROR Controller:update_dev: Failed to update 'child_component_list': <DeviceType.Hub at 192.168.1.150 - Tapo_H500_06D8 (H50
0)>
Traceback (most recent call last):
File "/usr/home/admin/dev/pg3/plugins/udi-poly-kasa/nodes/Controller.py", line 207, in update_dev
await dev.update()
File "/usr/home/admin/dev/pg3/plugins/udi-poly-kasa/kasa/smart/smartdevice.py", line 279, in update
children_changed = await self._update_children_info()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/home/admin/dev/pg3/plugins/udi-poly-kasa/kasa/smartcam/smartcamdevice.py", line 114, in _update_children_info
changed = await self._create_delete_children(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/home/admin/dev/pg3/plugins/udi-poly-kasa/kasa/smart/smartdevice.py", line 114, in _create_delete_children
for child in child_device_components_resp["child_component_list"]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^
KeyError: 'child_component_list'
After plugin restart, logs confirmed:
RuntimeError: coroutine raised StopIterationno longer appears.smartprotocol:_handle_response_lists ... no list fields in result ... skipping additional list pagesKeyError: 'child_component_list'inkasa/smart/smartdevice.py::_create_delete_children.Follow-up fix applied in
kasa/smart/smartdevice.py:child_device_components_resp.get("child_component_list")andchild_device_resp.get("child_device_list").smart_children_componentsonly from dict entries containingdevice_id.preserving behavior for normal payloads.
This change is intentionally narrow and defensive: it only alters behavior when no list-typed fields exist in a response that otherwise looks paginated.
Existing behavior for normal paginated list responses is unchanged.