Nice, didn’t know you could do that with the xbee in API mode. Glad you got it figured out. Sorry for the delay, have been travelling.
To anyone looking for the solution for a similar device, here is my final configuration for TOSR08-T. It can easily be modified for TOSR04-T or TOSR02-T by removing corresponding relays or the temperature sensor if your device doesn’t have it (without the “-T” part). I tested it on TOSR04-T, but I will post the solution for TOSR08-T since it is easier to remove sections than to add.
Supported:
- Relay control
- Getting relay states from the device
- Temperature sensor
Requires a recent version of zhaquircks.
homeassistant:
customize:
automation.update_tosr0x_switch:
hidden: true
automation.update_tosr0x_temp:
hidden: true
automation.update_tosr0x:
hidden: true
input_number.tosr0x_temp:
hidden: true
customize_glob:
"input_boolean.tosr0x_*_state":
hidden: true
logbook:
exclude:
entities:
- automation.update_tosr0x
- automation.update_tosr0x_temp
- automation.update_tosr0x_switch
# Internal hidden variables to hold TOSR0X relay state
input_boolean:
tosr0x_1_state:
name: TOSR0X Relay 1 State
tosr0x_2_state:
name: TOSR0X Relay 2 State
tosr0x_3_state:
name: TOSR0X Relay 3 State
tosr0x_4_state:
name: TOSR0X Relay 4 State
tosr0x_5_state:
name: TOSR0X Relay 5 State
tosr0x_6_state:
name: TOSR0X Relay 6 State
tosr0x_7_state:
name: TOSR0X Relay 7 State
tosr0x_8_state:
name: TOSR0X Relay 8 State
# Internal variable to hold TOSR0X-T temperature
input_number:
tosr0x_temp:
name: TOSR0X-T Temperature State
min: -55
max: 125
step: 0.125
mode: box
unit_of_measurement: '°C'
icon: mdi:temperature-celsius
# Sensor to display the TOSR0X-T temperature
sensor:
- platform: template
sensors:
tosr0x_temperature:
friendly_name: TOSR0X-T Temperature
entity_id: input_number.tosr0x_temp
value_template: "{{ states.input_number.tosr0x_temp.state }}"
device_class: temperature
unit_of_measurement: '°C'
# Switches to represent TOSR0X relays
# http://www.tinyosshop.com/datasheet/TOSR0X-T%20User%20Manual.pdf
switch:
- platform: template
switches:
tosr0x_1:
friendly_name: TOSR0X Relay 1
value_template: "{{ is_state('input_boolean.tosr0x_1_state', 'on') }}"
turn_on:
- service: zha.issue_zigbee_cluster_command
data:
ieee: 00:13:a2:00:40:f5:2a:be
endpoint_id: 232
cluster_id: 17
cluster_type: in
command: 0
command_type: server
args: "e[" # First character is to control the switch. Second character ('[') is to request an update of the switch states from the device in order to double confirm
- service: input_boolean.turn_on # Update switch state instantly without waiting for the update from the device (aka optimistic mode)
data:
entity_id: input_boolean.tosr0x_1_state
turn_off:
- service: zha.issue_zigbee_cluster_command
data:
ieee: 00:13:a2:00:40:f5:2a:be
endpoint_id: 232
cluster_id: 17
cluster_type: in
command: 0
command_type: server
args: "o["
- service: input_boolean.turn_off
data:
entity_id: input_boolean.tosr0x_1_state
tosr0x_2:
friendly_name: TOSR0X Relay 2
value_template: "{{ is_state('input_boolean.tosr0x_2_state', 'on') }}"
turn_on:
- service: zha.issue_zigbee_cluster_command
data:
ieee: 00:13:a2:00:40:f5:2a:be
endpoint_id: 232
cluster_id: 17
cluster_type: in
command: 0
command_type: server
args: "f["
- service: input_boolean.turn_on
data:
entity_id: input_boolean.tosr0x_2_state
turn_off:
- service: zha.issue_zigbee_cluster_command
data:
ieee: 00:13:a2:00:40:f5:2a:be
endpoint_id: 232
cluster_id: 17
cluster_type: in
command: 0
command_type: server
args: "p["
- service: input_boolean.turn_off
data:
entity_id: input_boolean.tosr0x_2_state
tosr0x_3:
friendly_name: TOSR0X Relay 3
value_template: "{{ is_state('input_boolean.tosr0x_3_state', 'on') }}"
turn_on:
- service: zha.issue_zigbee_cluster_command
data:
ieee: 00:13:a2:00:40:f5:2a:be
endpoint_id: 232
cluster_id: 17
cluster_type: in
command: 0
command_type: server
args: "g["
- service: input_boolean.turn_on
data:
entity_id: input_boolean.tosr0x_3_state
turn_off:
- service: zha.issue_zigbee_cluster_command
data:
ieee: 00:13:a2:00:40:f5:2a:be
endpoint_id: 232
cluster_id: 17
cluster_type: in
command: 0
command_type: server
args: "q["
- service: input_boolean.turn_off
data:
entity_id: input_boolean.tosr0x_3_state
tosr0x_4:
friendly_name: TOSR0X Relay 4
value_template: "{{ is_state('input_boolean.tosr0x_4_state', 'on') }}"
turn_on:
- service: zha.issue_zigbee_cluster_command
data:
ieee: 00:13:a2:00:40:f5:2a:be
endpoint_id: 232
cluster_id: 17
cluster_type: in
command: 0
command_type: server
args: "h["
- service: input_boolean.turn_on
data:
entity_id: input_boolean.tosr0x_4_state
turn_off:
- service: zha.issue_zigbee_cluster_command
data:
ieee: 00:13:a2:00:40:f5:2a:be
endpoint_id: 232
cluster_id: 17
cluster_type: in
command: 0
command_type: server
args: "r["
- service: input_boolean.turn_off
data:
entity_id: input_boolean.tosr0x_4_state
tosr0x_5:
value_template: "{{ is_state('input_boolean.tosr0x_5_state', 'on') }}"
turn_on:
- service: zha.issue_zigbee_cluster_command
data:
ieee: 00:13:a2:00:40:f5:2a:be
endpoint_id: 232
cluster_id: 17
cluster_type: out
command: 0
command_type: server
args: "i["
- service: input_boolean.turn_on
data:
entity_id: input_boolean.tosr0x_5_state
turn_off:
- service: zha.issue_zigbee_cluster_command
data:
ieee: 00:13:a2:00:40:f5:2a:be
endpoint_id: 232
cluster_id: 17
cluster_type: out
command: 0
command_type: server
args: "s["
- service: input_boolean.turn_off
data:
entity_id: input_boolean.tosr0x_5_state
tosr0x_6:
value_template: "{{ is_state('input_boolean.tosr0x_6_state', 'on') }}"
turn_on:
- service: zha.issue_zigbee_cluster_command
data:
ieee: 00:13:a2:00:40:f5:2a:be
endpoint_id: 232
cluster_id: 17
cluster_type: out
command: 0
command_type: server
args: "j["
- service: input_boolean.turn_on
data:
entity_id: input_boolean.tosr0x_6_state
turn_off:
- service: zha.issue_zigbee_cluster_command
data:
ieee: 00:13:a2:00:40:f5:2a:be
endpoint_id: 232
cluster_id: 17
cluster_type: out
command: 0
command_type: server
args: "t["
- service: input_boolean.turn_off
data:
entity_id: input_boolean.tosr0x_6_state
tosr0x_7:
value_template: "{{ is_state('input_boolean.tosr0x_7_state', 'on') }}"
turn_on:
- service: zha.issue_zigbee_cluster_command
data:
ieee: 00:13:a2:00:40:f5:2a:be
endpoint_id: 232
cluster_id: 17
cluster_type: out
command: 0
command_type: server
args: "k["
- service: input_boolean.turn_on
data:
entity_id: input_boolean.tosr0x_7_state
turn_off:
- service: zha.issue_zigbee_cluster_command
data:
ieee: 00:13:a2:00:40:f5:2a:be
endpoint_id: 232
cluster_id: 17
cluster_type: out
command: 0
command_type: server
args: "u["
- service: input_boolean.turn_off
data:
entity_id: input_boolean.tosr0x_7_state
tosr0x_8:
value_template: "{{ is_state('input_boolean.tosr0x_8_state', 'on') }}"
turn_on:
- service: zha.issue_zigbee_cluster_command
data:
ieee: 00:13:a2:00:40:f5:2a:be
endpoint_id: 232
cluster_id: 17
cluster_type: out
command: 0
command_type: server
args: "l["
- service: input_boolean.turn_on
data:
entity_id: input_boolean.tosr0x_8_state
turn_off:
- service: zha.issue_zigbee_cluster_command
data:
ieee: 00:13:a2:00:40:f5:2a:be
endpoint_id: 232
cluster_id: 17
cluster_type: out
command: 0
command_type: server
args: "v["
- service: input_boolean.turn_off
data:
entity_id: input_boolean.tosr0x_8_state
automation:
- alias: update_tosr0x # Request the temperature and relay states from TOSR0X
trigger:
- platform: time_pattern
minutes: '/5'
- platform: homeassistant
event: start
action:
service: zha.issue_zigbee_cluster_command
data:
ieee: 00:13:a2:00:40:f5:2a:be
endpoint_id: 232
cluster_id: 17
cluster_type: in
command: 0
command_type: server
args: "a[" # First character is for temperature, second character is for relay states, please see the TOSR0X manual
- alias: update_tosr0x_switch # Update relay states upon receiving them from TOSR0X
trigger:
platform: event
event_type: zha_event
event_data:
device_ieee: 00:13:a2:00:40:f5:2a:be
command: receive_data
condition:
condition: template
value_template: "{{ trigger.event.data.args | length == 1 }}" # A single byte response is probably a relay state update
action:
- service_template: >
{% if trigger.event.data.args.encode('latin1').hex() | int(base=16) | bitwise_and(2**0) %}
input_boolean.turn_on
{% else %}
input_boolean.turn_off
{% endif %}
data:
entity_id: input_boolean.tosr0x_1_state
- service_template: >
{% if trigger.event.data.args.encode('latin1').hex() | int(base=16) | bitwise_and(2**1) %}
input_boolean.turn_on
{% else %}
input_boolean.turn_off
{% endif %}
data:
entity_id: input_boolean.tosr0x_2_state
- service_template: >
{% if trigger.event.data.args.encode('latin1').hex() | int(base=16) | bitwise_and(2**2) %}
input_boolean.turn_on
{% else %}
input_boolean.turn_off
{% endif %}
data:
entity_id: input_boolean.tosr0x_3_state
- service_template: >
{% if trigger.event.data.args.encode('latin1').hex() | int(base=16) | bitwise_and(2**3) %}
input_boolean.turn_on
{% else %}
input_boolean.turn_off
{% endif %}
data:
entity_id: input_boolean.tosr0x_4_state
- service_template: >
{% if trigger.event.data.args.encode('latin1').hex() | int(base=16) | bitwise_and(2**4) %}
input_boolean.turn_on
{% else %}
input_boolean.turn_off
{% endif %}
data:
entity_id: input_boolean.tosr0x_5_state
- service_template: >
{% if trigger.event.data.args.encode('latin1').hex() | int(base=16) | bitwise_and(2**5) %}
input_boolean.turn_on
{% else %}
input_boolean.turn_off
{% endif %}
data:
entity_id: input_boolean.tosr0x_6_state
- service_template: >
{% if trigger.event.data.args.encode('latin1').hex() | int(base=16) | bitwise_and(2**6) %}
input_boolean.turn_on
{% else %}
input_boolean.turn_off
{% endif %}
data:
entity_id: input_boolean.tosr0x_7_state
- service_template: >
{% if trigger.event.data.args.encode('latin1').hex() | int(base=16) | bitwise_and(2**7) %}
input_boolean.turn_on
{% else %}
input_boolean.turn_off
{% endif %}
data:
entity_id: input_boolean.tosr0x_8_state
- alias: update_tosr0x_temp # Update temperature upon receiving it from TOSR0X
trigger:
platform: event
event_type: zha_event
event_data:
device_ieee: 00:13:a2:00:40:f5:2a:be
command: receive_data
condition:
condition: template
value_template: "{{ trigger.event.data.args | length == 2 }}" # A two-byte response is probably a temperature update (2's complement format)
action:
service: input_number.set_value
data_template:
entity_id: input_number.tosr0x_temp
value: >
{% if trigger.event.data.args.encode('latin1').hex() | int(base=16) > 32767 %}
{{ trigger.event.data.args.encode('latin1').hex() | int(base=16) / 16 - 4096 }}
{% else %}
{{ trigger.event.data.args.encode('latin1').hex() | int(base=16) / 16 }}
{% endif %}
group:
tosr0x:
name: TOSR0X
entities:
- zha.xbee_xbee_io
- sensor.tosr0x_temperature
- switch.tosr0x_1
- switch.tosr0x_2
- switch.tosr0x_3
- switch.tosr0x_4
- switch.tosr0x_5
- switch.tosr0x_6
- switch.tosr0x_7
- switch.tosr0x_8
Just found the discussion. How do you join the second Xbee to zha network?
Probably you could just enable join in HA interface (http://hassio.local:8123/config/zha/add) and press the commissioning button on the second xbee (pin 20 to ground) once.
If that doesn’t work, place the two xbees closer to each other.
Instead of commisioning button you can try XTCU to simulate it or to manually set the parameters. The important are:
CE=0
ZS=2
EE=1
EO=2
NK=0
KY=5a6967426565416c6c69616e63653039
Thanks.
Where you take the Encription key? Is it documented somethere? Can you change it?
I got it here: zigpy-xbee/zigpy_xbee/zigbee/application.py at d3dfb11b336e4bbaaaa0abe2d0b7627c6ac07f83 · zigpy/zigpy-xbee · GitHub
It is the default trusted center (usually, the coordinator node) link key documented in zigbee standard. It is used during join to transfer the actual network key, which is randomly generated by the trust center node. It is not used by nodes when they already joined.
You can. Please note however:
- The key must be preconfigured on all new nodes joining the network. If all your devices are xbee, then it is not a problem. For less configurable devices such as sensors it could be an issue.
- Currently the link key is hardcoded in the zigpy_xbee code. If you overwrite it, you will need to do it after every zigpy_xbee update.
Thanks, your information was very useful for me, saved many time.
Thanks, this thread has really helped me. One thing:
Note that the github projects referenced from this and the previous posts have been removed. It took me a while to eventually figure out that you had integrated your work into https://github.com/dmulcahey/zha-device-handlers/
Yes, my changes were accepted upstream, now you don’t need anything beyond a recent version of zhaquircks. I probably needed to mention that more explicitly in the post that I marked as a solution.
Thanks for a great solution
I struggled to come up with a solution for interfacing from Home Assistant to micropython on XBee3 until I stumbled on this.
I used a similar configuration to control XBee3 micropython which activates Seeed SPDT relays over i2c.
The configuration looks like this - I have just shown one of the four relays:
input_boolean:
xbee_aaca92_i2c_channel17_relay1_state:
name: "XBee i2c17 Relay 1 State"
switch:
- platform: template
switches:
xbee_aaca92_i2c_channel17_relay1:
friendly_name: Pool pump relay
value_template: "{{ is_state('input_boolean.xbee_aaca92_i2c_channel17_relay1_state', 'on') }}"
turn_on:
- service: zha.issue_zigbee_cluster_command
data:
ieee: 00:13:a2:00:41:aa:ca:92
endpoint_id: 232
cluster_id: 17
cluster_type: in
command: 0
command_type: server
args: '{"relay": 1, "status": true}'
- service: input_boolean.turn_on
data:
entity_id: input_boolean.xbee_aaca92_i2c_channel17_relay1_state
turn_off:
- service: zha.issue_zigbee_cluster_command
data:
ieee: 00:13:a2:00:41:aa:ca:92
endpoint_id: 232
cluster_id: 17
cluster_type: in
command: 0
command_type: server
args: '{"relay": 1, "status": false}'
- service: input_boolean.turn_off
data:
entity_id: input_boolean.xbee_aaca92_i2c_channel17_relay1_state
The micropython on the XBee3 looks as follows (The XBee3 needs to be configured in API mode):
import time
import xbee
from machine import I2C
import ujson
import struct
i2c = I2C(1)
CMD_CHANNEL_CTRL = 0x10
relayState = 0x0
while True:
# Check if the XBee has any message in the queue.
received_msg = xbee.receive()
if received_msg:
# Get the sender's 64-bit address and payload from the received message.
sender = received_msg['sender_eui64']
payload = received_msg['payload']
try:
obj = ujson.loads(payload.decode())
if obj['relay'] < 1 | obj['relay'] > 8:
print("relay must be an integer from 1 - 8")
else:
if obj['status']:
relayState |= (1 << obj['relay'] - 1)
else:
relayState &= ~(1 << obj['relay'] - 1)
cmdBytes = struct.pack("BB", CMD_CHANNEL_CTRL, relayState)
print(relayState)
print(cmdBytes)
i2c.writeto(17, cmdBytes)
# Send back the same payload to the sender.
print("Sending back a response...\n")
# xbee.transmit(sender, payload)
except ValueError:
print("Failed to parse json for payload:")
print(payload)
else:
# Wait 100 ms before checking for data again.
time.sleep(0.2)
I would like to look at using more standard Zigbee protocol message to drive the micropython, but for now I am pleased with the progress.
This may be of interest as another approach to manage relays.
My relays are controlled via i2c, but I presume you could make some changes to communicate via serial port from micropython on xbee3. I used Grove 4 / 8 channel SPDT relay via i2c
I wanted to use standard zigbee onoff endpoints to control relay. The latest version of xbee3 firmware (100A) now supports pass through of zdo to micropython. I use micropython to change the ZDO responses for Active_EP_req and Simple_Desc_rsp at the time that the xbee3 joins the HASS network. It sends a simple descriptor for each endpoint, indicating a simple OnOff (cluster id 0x06). Once set up, it:
- responds to on and off commands at the relevant endpoints by activating my relays over i2c
- responds to attribute requests to send current on/off status to HASS.
- it publishes reporting messages to act as a heartbeat and refresh current on/off status’s to HASS
I use the micropython which is supported on xbee3 to do this. I guess it could also be done with arduino or similar.
I have published the code I used for this at (https://github.com/petertrain/xbee3-i2c-relay).
I have copied and ported a fair amount of code for handling the zigbee communications from zibpy. I ran into two issues:
- I ran out of memory on the xbee3
- some of the standard python libraries used by zigpy aren’t supported on micropython (notably lib/enum).
As a result, I have butchered the zigpy code a fair amount to get it working. At times, I hardcoded encoded values instead of providing meaningful types. I might go back and try to clean some of that up.
The nice thing about this solution is that you don’t require use of quirks or any configuration in HASS to get it working. I just join the xbee3 with appropriate micropython module to the network and HASS is immediately configured to control the relevant relays.
Hello i need help,
i can´t detect in ZHA another xbee router…
I have a xbee s2c coordinator connected to ZHA. It works perfect with any zigbee product. But i cant connect other xbee for controling it´s IO pins.
If I scan devices in XCTU with router, i see the coordinator. But in adding router to ZHA was impossible.
I tried commmissioning button, and configure router with params:
CE=0
ZS=2
EE=1
EO=2
NK=0
KY=5a6967426565416c6c69616e63653039
I also tried using xbee ha platform, adding a light with router address like described here: ha xbee
Nothing worked…
Thanks!
Nothing worked…
Hi!
I only noticed your post now.
You are doing it correct. Once you configured these parameters, the module should start searching for the network. Go to Configuration → Integrations → ZHA > “Add device” to allow joining, then check XCTU again, at the very bottom you will see the section for Diagnostic commands. Refresh the AI parameter a few times and tell us which values it returns.
Sometimes it helps moving physically closer to the coordinator, or changing ZS to 0 and then back to 2 to trigger joining.
Hi Denis, Thank you for sharing details of your project here in HA. I’m new to HA and been to digi xbee forum but there are no examples for end device. Your configuration made my xbee detectable to the configurator!
Anyways my goal is to make an end device with power meter and relay switch to be controlled and displayed on HA. Upon trying the configurations on xbee, this controls (15), 2 analog outputs and 1 sensor binary input showed up. This board is just pre flashed with the latest xbee firmware and no micropython yet. I wonder where did those config files came from. I tried exploring XCTU but I cant see anything GPIO config related as far as I understand. And if you can point me to more resource in creating endpoint with xbee that would be great! TIA
Hi!
Probably the best source of information for now is this: zha-device-handlers/xbee.md at 4956114628a2aee435776c5e286a8e97d4f3df53 · zigpy/zha-device-handlers · GitHub
To put it simply, the on-off switches control digital output of XBee (or show you a digital input if configured so with XCTU). You will also have PWM as a number entity and analog input as sensors.
Now you need to connect your relays to the respective lines of XBee and that’s probably it. If you need a more complicated logic, you can use template sensor or template switch.
Thanks for the fast response! And great details on link! I appreciate it.
Hi,
I’m hoping that someone is still looking at this thread and can help me out here.
I have a Sonoff Zigbee USB device attached to Home Assistant and ZHA. I bought an XBee 2 and I’ve set it up with XCTU to attach it to ZHA and it was recognised as an XBee 3. I’m assuming that this isn’t a problem as it joined the network and comes up in Home Assistant.
I’ve started experimenting with the UART.
I’ve attached the XBee Tx/Rx to an ESP32 (via a level shifter) and I’ve been using Arduino to write code for the ESP32. I’m using the xbee Arduino library with XBeeWithCallbacks.
When I call the HA Service zha.issue_zigbee_cluster_command
the data appears at my ESP32 so I know the path works. This is what I’m using:
service: zha.issue_zigbee_cluster_command
data:
endpoint_id: 232
cluster_id: 17
cluster_type: in
command: 0
command_type: server
args: Hello World
ieee: 00:13:A2:00:41:F2:A5:19
And this is the display from my Arduino code
14:34:40.931 -> ER => RemAddr= 0 Src=1 Dst=E8 Clus= 11 Prof=260 Opt=0 Offset=17
14:34:40.931 -> Length = 11 Data = 48 65 6C 6C 6F 20 57 6F 72 6C 64
ER means ZBExplicitRxResponse in xbee.h
As you can see the data is “Hello World”
The problem I have is sending data from the ESP32.
I’ve used the developer tools in HA to listen to ‘zha_event’ but nothing happens (I do not have any other Zigbee devices).
This link says that incoming UART data will generate this Event in HA but I’ve tried all combinations of the various data structures from xbee.h on the Arduino.
This is my Arduino loop
#define BIGNUM 100000
void loop() {
xbee.loop();
if (ctr++ % BIGNUM == 0) {
// Create an array for holding the data you want to send.
uint8_t payload[] = { 'H', 'i' };
// Specify the address of the remote XBee (this is the SH + SL)
XBeeAddress64 addr64 = XBeeAddress64(0x00124B00, 0x26B72A67);
//XBeeAddress64 addr64 = XBeeAddress64(0x0, 0x0);
//XBeeAddress64 addr64 = XBeeAddress64(0x0, 0x7FFF);
// Create a TX Request
ZBTxRequest zbTx = ZBTxRequest(addr64, payload, sizeof(payload));
zbTx.setFrameId((ctr / BIGNUM) % 256);
// Send your request
xbee.send(zbTx);
}
}
When the above does the send I get an ZBTxStatusResponse callback with isSuccess set TRUE so I assume it works.
I’ve tried ZBTxRequest and ZBExplicitTxRequest. I also tried the series 1 versions: Tx16Request and Tx64Request.
I also have a packet sniffer setup and I can see a flurry of packets at the appropriate times but I have no idea whats going on. The data content looks nothing like the data I’m sending.
Can anyone help please. What code in the Arduino using xbee.h should I be using, anyone have examples of this setup working.
One more thing, I’m not sure if this is relevant but I have the logger set up in HA. When the Arduino sends I get this in the HA log file:
2022-10-29 14:50:52.818 DEBUG (MainThread) [zigpy_znp.api] Received command: ZDO.SrcRtgInd.Callback(DstAddr=0x293C, Relays=[])
Hi Dave,
If you have the sniffer, what are the source and destination endpoint ID do you see in the packets, are they 0xE8?
Hi and thanks,
I’ve screen grabbed an image of the sniffer, at each time the Arduino code does a send these 6 messages are captured. The “APS Dest Point” increments by 1. The “APS Src Endpoint” is always 0x67. Note that I have a filter set in the sniffer for the Dest Address to be 0x0.
Thanks again.
EDIT: I’ve also unselected the “Nwk Payload” and “Aps Payload” so they are not shown.
EDIT2:
I screen grabbed the data when I call the Home Assistant service
This is weird as the “APS Src Endpoint” shows 0x67 but when I receive the data my arduino displays it as 1 and the “APS Dest Point” as 0xE8 (232 decimal).
22:55:27.716 → ER => RemAddr= 0 Src=1 Dst=E8 Clus= 11 Prof=260 Opt=0 Offset=17
22:55:27.716 → Length = 11 Data = 48 65 6C 6C 6F 20 57 6F 72 6C 64
This is the code used to generate the above screen info so you can see what is hex and what is decimal.
Serial.printf("ER => RemAddr=%4X Src=%X Dst=%X Clus=%4X Prof=%d Opt=%d Offset=%d\n",
(int)rxe.getRemoteAddress16(), (int)rxe.getSrcEndpoint(), (int)rxe.getDstEndpoint(), (int)rxe.getClusterId(), (int)rxe.getProfileId(), (int)rxe.getOption(), (int)rxe.getDataOffset());
dumpBuffer(rxe.getData(), rxe.getDataLength());
EDIT3: Could it be that the data is encrypted and we can’t believe anything we see in the packet sniffer?
I think you need to configure zigpy to listen to the appropriate endpoint.