-
Notifications
You must be signed in to change notification settings - Fork 199
Add packet reception API #1643
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
Add packet reception API #1643
Conversation
- Add register_packet_callback() method for registering packet callbacks - Add notify_packet_callbacks() to dispatch packets to registered callbacks - Support both global callbacks (filter=None) and address-specific filtering - Add _packet_callbacks storage using defaultdict for callback management
…bmission.Merge remote-tracking branch 'upstream/dev' into feature/packet-reception-api
This implements a generic packet reception API as referenced in issue zigpy#1468. It allows for registration of callbacks for raw ZigbeePacket objects, and enables future features like TouchLink support via inter-PAN communication. - Add register_packet_callback() method for raw packet callbacks - Add notify_packet_callbacks() to dispatch packets to callbacks - Add _packet_callbacks storage using defaultdict Co-authored-by: Justin Saminathen <[email protected]> Co-authored-by: Aaron Mundanilkunathil <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR implements a generic packet reception API to enable registration of callbacks for raw ZigbeePacket objects, primarily intended to support future TouchLink functionality via inter-PAN communication.
- Adds packet callback registration system with address-specific and global filtering capabilities
- Implements callback storage using defaultdict and notification mechanism with exception handling
- Provides cleanup functionality through returned cancellation functions
zigpy/application.py
Outdated
| # Add callback storage | ||
| self._packet_callbacks: collections.defaultdict[ | ||
| t.AddrModeAddress | None, | ||
| list[typing.Callable[[t.ZigbeePacket], Any]] |
Copilot
AI
Aug 7, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type annotation uses Any as return type but the actual callback parameter in register_packet_callback expects None. This inconsistency could confuse users about what their callback functions should return.
| list[typing.Callable[[t.ZigbeePacket], Any]] | |
| list[typing.Callable[[t.ZigbeePacket], None]] |
zigpy/application.py
Outdated
|
|
||
| def cancel_callback() -> None: | ||
| """Remove the callback.""" | ||
| if callback in self._packet_callbacks[filter]: |
Copilot
AI
Aug 7, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using list.remove() with in check results in O(n) operation twice. Consider checking the result of remove() directly or store callbacks in a set for O(1) removal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can probably use with contextlib.suppress(ValueError): to clean this up
zigpy/application.py
Outdated
| """Notify registered packet callbacks about a received Zigbee packet.""" | ||
|
|
||
| # Notify global callbacks (registered with None filter) | ||
| for callback in self._packet_callbacks.get(None, []): |
Copilot
AI
Aug 7, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using .get(None, []) creates a new empty list on each call when no global callbacks exist. Consider using self._packet_callbacks[None] directly since defaultdict will return an empty list.
| for callback in self._packet_callbacks.get(None, []): | |
| for callback in self._packet_callbacks[None]: |
zigpy/application.py
Outdated
| LOGGER.exception("Error in global packet callback: %s", callback) | ||
|
|
||
| # Notify address-specific callbacks | ||
| for callback in self._packet_callbacks.get(packet.src, []): |
Copilot
AI
Aug 7, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using .get(packet.src, []) creates a new empty list on each call when no callbacks exist for the address. Consider using self._packet_callbacks[packet.src] directly since defaultdict will return an empty list.
| for callback in self._packet_callbacks.get(packet.src, []): | |
| for callback in self._packet_callbacks[None]: | |
| try: | |
| callback(packet) | |
| except Exception: | |
| LOGGER.exception("Error in global packet callback: %s", callback) | |
| # Notify address-specific callbacks | |
| for callback in self._packet_callbacks[packet.src]: |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## dev #1643 +/- ##
=======================================
Coverage 99.29% 99.29%
=======================================
Files 57 57
Lines 11638 11656 +18
=======================================
+ Hits 11556 11574 +18
Misses 82 82 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
0de6508 to
125d2a7
Compare
Co-authored-by: Jane Swingler <[email protected]> Co-authored-by: Aaron Mundanilkunathil <[email protected]>
87c0a44 to
3fd5039
Compare
|
Thanks! This looks good to go once unit tests are added. |
Co-authored-by: Jane Swingler <[email protected]> Co-authored-by: Aaron Mundanilkunathil <[email protected]>
Added unit tests to test different scenarios with packet reception handling.
|
utilizing .replace(), and use mock_calls assertions Co-authored-by: Jane Swingler <[email protected]> Co-authored-by: Aaron Mundanilkunathil <[email protected]>
Co-authored-by: Justin Saminathen <[email protected]> Co-authored-by: Aaron Mundanilkunathil <[email protected]>
…tion API Co-authored-by: Justin Saminathen <[email protected]> Co-authored-by: Aaron Mundanilkunathil <[email protected]>
puddly
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks great, thank you!
|
@puddly Do we need another approval to get this merged? |
|
We usually don't merge new features or APIs during the Home Assistant release cycle, I'll get it in in about a week. |
This PR implements a generic packet reception API as referenced in issue #1468. It allows for registration of callbacks for raw ZigbeePacket objects to enable future features like TouchLink support via inter-PAN communication.
register_packet_callback()method for raw packet callbacksAddrModeAddressand global callbacks when filter=Nonenotify_packet_callbacks()to dispatch packets to registered callbacks_packet_callbacksstorage using defaultdictUsage:
Callback functions are called synchronously - async support could be added later as use cases develop. API is WIP and could be extended for more filters (cluster/profile ID etc).
Next, we will implement standalone parsing utilities for packet processing independent of device and cluster objects, enabling TouchLink cluster command processing using this packet callback interface.