Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@janeswingler
Copy link
Contributor

@janeswingler janeswingler commented Aug 7, 2025

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.

  • Add register_packet_callback() method for raw packet callbacks
    • Supports address-specific filtering via AddrModeAddress and global callbacks when filter=None
    • Returns cancellation function for cleanup
  • Add notify_packet_callbacks() to dispatch packets to registered callbacks
  • Add _packet_callbacks storage using defaultdict

Usage:

# Global packet callback
cancel_global = app.register_packet_callback(None, my_global_handler)

# Address-specific callback  
cancel_specific = app.register_packet_callback(
    AddrModeAddress(addr_mode=AddrMode.IEEE, address=some_ieee),
    my_address_handler
)

# Clean up
cancel_global()
cancel_specific()

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.

janeswingler and others added 5 commits August 4, 2025 15:16
- 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]>
Copilot AI review requested due to automatic review settings August 7, 2025 17:43
Copy link

Copilot AI left a 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

# Add callback storage
self._packet_callbacks: collections.defaultdict[
t.AddrModeAddress | None,
list[typing.Callable[[t.ZigbeePacket], Any]]
Copy link

Copilot AI Aug 7, 2025

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.

Suggested change
list[typing.Callable[[t.ZigbeePacket], Any]]
list[typing.Callable[[t.ZigbeePacket], None]]

Copilot uses AI. Check for mistakes.

def cancel_callback() -> None:
"""Remove the callback."""
if callback in self._packet_callbacks[filter]:
Copy link

Copilot AI Aug 7, 2025

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.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator

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

"""Notify registered packet callbacks about a received Zigbee packet."""

# Notify global callbacks (registered with None filter)
for callback in self._packet_callbacks.get(None, []):
Copy link

Copilot AI Aug 7, 2025

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.

Suggested change
for callback in self._packet_callbacks.get(None, []):
for callback in self._packet_callbacks[None]:

Copilot uses AI. Check for mistakes.
LOGGER.exception("Error in global packet callback: %s", callback)

# Notify address-specific callbacks
for callback in self._packet_callbacks.get(packet.src, []):
Copy link

Copilot AI Aug 7, 2025

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.

Suggested change
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]:

Copilot uses AI. Check for mistakes.
@codecov
Copy link

codecov bot commented Aug 7, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.29%. Comparing base (88c3ba6) to head (c7faa35).
⚠️ Report is 4 commits behind head on dev.

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.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@A-Mundanilkunathil A-Mundanilkunathil force-pushed the feature/packet-reception-api branch from 0de6508 to 125d2a7 Compare August 7, 2025 22:11
Co-authored-by: Jane Swingler <[email protected]>
Co-authored-by: Aaron Mundanilkunathil <[email protected]>
@justin2186 justin2186 force-pushed the feature/packet-reception-api branch from 87c0a44 to 3fd5039 Compare August 7, 2025 22:49
@puddly
Copy link
Collaborator

puddly commented Aug 7, 2025

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]>
@justin2186
Copy link
Contributor

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.

  • Add register_packet_callback() method for raw packet callbacks

    • Supports address-specific filtering via AddrModeAddress and global callbacks when filter=None
    • Returns cancellation function for cleanup
  • Add notify_packet_callbacks() to dispatch packets to registered callbacks

  • Add _packet_callbacks storage using defaultdict

Usage:

# Global packet callback
cancel_global = app.register_packet_callback(None, my_global_handler)

# Address-specific callback  
cancel_specific = app.register_packet_callback(
    AddrModeAddress(addr_mode=AddrMode.IEEE, address=some_ieee),
    my_address_handler
)

# Clean up
cancel_global()
cancel_specific()

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.

Added unit tests to test different scenarios with packet reception handling.

  • register and cancel callbacks
  • packet address match vs mismatch
  • addr_mode mismatch (IEEE filter vs NWK packet)
  • multiple callbacks on same filter + selective cancel
  • exception isolation (one failing global callback does not block others)

utilizing .replace(), and use mock_calls assertions

Co-authored-by: Jane Swingler <[email protected]>
Co-authored-by: Aaron Mundanilkunathil <[email protected]>
@janeswingler janeswingler requested a review from puddly August 13, 2025 00:45
janeswingler and others added 2 commits August 12, 2025 19:14
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]>
Copy link
Collaborator

@puddly puddly left a 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 puddly changed the title [WIP] Add packet reception API (#1468) Add packet reception API Aug 13, 2025
@janeswingler
Copy link
Contributor Author

@puddly Do we need another approval to get this merged?

@puddly
Copy link
Collaborator

puddly commented Aug 18, 2025

We usually don't merge new features or APIs during the Home Assistant release cycle, I'll get it in in about a week.

@puddly puddly merged commit 88f0ae1 into zigpy:dev Sep 8, 2025
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants