espressif / esp-zigbee-sdk

Espressif Zigbee SDK
Apache License 2.0
178 stars 31 forks source link

Auto Enroll - Not receiving Zone Enroll Request command (TZ-1239) #462

Closed renatomotorline closed 4 weeks ago

renatomotorline commented 1 month ago

I'm trying to follow the Auto Enroll Request detailed in https://github.com/espressif/esp-zigbee-sdk/issues/42#issuecomment-1639229015 I'm able to set the CIE address using the following code:

  esp_zb_zcl_write_attr_cmd_t cie_write_req;
  cie_write_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
  memcpy(cie_write_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr,
         sizeof(esp_zb_ieee_addr_t));
  cie_write_req.zcl_basic_cmd.src_endpoint = GATEWAY_ENDPOINT;
  cie_write_req.zcl_basic_cmd.dst_endpoint = endpoint_id;
  cie_write_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_IAS_ZONE;

  // Get gateway address
  esp_zb_ieee_addr_t addr = {0};
  esp_zb_get_long_address(addr);

  // Write the CIE Address (Gateway's IEEE Address)
  esp_zb_zcl_attribute_t cie_attribute;
  cie_attribute.id = ESP_ZB_ZCL_ATTR_IAS_ZONE_IAS_CIE_ADDRESS_ID;
  cie_attribute.data.type = ESP_ZB_ZCL_ATTR_TYPE_IEEE_ADDR;
  cie_attribute.data.size = sizeof(esp_zb_ieee_addr_t);
  cie_attribute.data.value = addr;

  cie_write_req.attr_field = &cie_attribute;
  cie_write_req.attr_number = 1;

  esp_zb_zcl_write_attr_cmd_req(&cie_write_req);

After executing this code, I performed a read attribute operation on ESP_ZB_ZCL_ATTR_IAS_ZONE_IAS_CIE_ADDRESS_ID, and the address matched the one retrieved from esp_zb_get_long_address. However, I am not receiving any Zone Enroll request (ESP_ZB_CORE_CMD_IAS_ZONE_ZONE_ENROLL_REQUEST_ID).

Sensor Model: SonOff SNZB-03

With Zigbee2Mqtt the device enrolls successfully:

zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:controller:device: Interview - IAS - not enrolled, enrolling
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:controller:endpoint: ZCL command 0x744dbdfffe63f5e8/1 ssIasZone.write({"iasCieAddr":"0xe8e07efffe7c8a58"}, {"timeout":10000,"disableResponse":false,"disableRecovery":false,"disableDefaultResponse":true,"direction":0,"reservedBits":0,"writeUndiv":false,"sendPolicy":"immediate"})
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp: sendZclFrameToEndpointInternal 0x744dbdfffe63f5e8:41508/1 (0,0,1), timeout=10000
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:ezsp: ==> sendUnicast: {"type":0,"indexOrDestination":41508,"apsFrame":{"profileId":260,"sequence":80,"clusterId":1280,"sourceEndpoint":1,"destinationEndpoint":1,"groupId":0,"options":256},"messageTag":81,"message":{"type":"Buffer","data":[16,49,2,16,0,240,88,138,124,254,255,126,224,232]}}
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:ezsp: ==> {"_cls_":"sendUnicast","_id_":52,"_isRequest_":true,"type":0,"indexOrDestination":41508,"apsFrame":{"profileId":260,"sequence":80,"clusterId":1280,"sourceEndpoint":1,"destinationEndpoint":1,"groupId":0,"options":256},"messageTag":81,"message":{"type":"Buffer","data":[16,49,2,16,0,240,88,138,124,254,255,126,224,232]}}
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:uart: --> DATA (7,1,0): bf000134000024a20401000501010001000050510e1031021000f0588a7cfeff7ee0e8
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:uart: --> [71fd21a9602a1596fb904b25af5493499d4e27fbbcc077baffd66379a4f4435914b33e87920e7e]
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:uart: -?- waiting (0)
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:uart: <-- [10fda1a9602a150eea157e]
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:uart: <-- DATA (1,0,0): 10fda1a9602a150eea157e
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:uart: --> ACK  (2)
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:uart: --> [82503a7e]
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:uart: <-- ACK (0): 10fda1a9602a150eea157e
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:ezsp: <== Frame: bf8001340000bc
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:ezsp: <== 0x34: {"_cls_":"sendUnicast","_id_":52,"_isRequest_":false,"status":0,"sequence":188}
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:uart: -+- waiting (0) success
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:uart: <-- [20fdb1a96b2a1596fb904b25af5493499d4e2717bcce675fab7e]
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:uart: <-- DATA (2,0,0): 20fdb1a96b2a1596fb904b25af5493499d4e2717bcce675fab7e
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:uart: --> ACK  (3)
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:uart: --> [83401b7e]
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:uart: <-- ACK (0): 20fdb1a96b2a1596fb904b25af5493499d4e2717bcce675fab7e
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:ezsp: <== Frame: bf90013f000024a204010005010100010000bc510000
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:ezsp: <== 0x3f: {"_cls_":"messageSentHandler","_id_":63,"_isRequest_":false,"type":0,"indexOrDestination":41508,"apsFrame":{"profileId":260,"sequence":188,"clusterId":1280,"sourceEndpoint":1,"destinationEndpoint":1,"groupId":0,"options":256},"messageTag":81,"status":0,"message":{"type":"Buffer","data":[]}}
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:uart: <-- [30fdb5a9362afd473a6ab598e721577d3a7e]
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:uart: <-- DATA (3,0,0): 30fdb5a9362afd473a6ab598e721571a7e
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:uart: --> ACK  (4)
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:uart: --> [8430fc7e]
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:uart: <-- ACK (0): 30fdb5a9362afd473a6ab598e721571a7e
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:ezsp: <== Frame: bf94016200e8f563feffbd4d74
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:ezsp: <== 0x62: {"_cls_":"incomingSenderEui64Handler","_id_":98,"_isRequest_":false,"senderEui64":{"type":"Buffer","data":[116,77,189,255,254,99,245,232]}}
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:driv: Unhandled frame incomingSenderEui64Handler
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:uart: <-- [40fdb1a97d312a15b658944f24ab159f499c90d85ac96c9874f9de528dfc7c46647e]
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:uart: <-- DATA (4,0,0): 40fdb1a9112a15b658944f24ab159f499c90d85ac96c9874f9de528dfc7c46647e
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:uart: --> ACK  (5)
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:uart: --> [8520dd7e]
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:uart: <-- ACK (0): 40fdb1a9112a15b658944f24ab159f499c90d85ac96c9874f9de528dfc7c46647e
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:ezsp: <== Frame: bf9001450000040100050101400d0000defff124a2ffff041831040002
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp:ezsp: <== 0x45: {"_cls_":"incomingMessageHandler","_id_":69,"_isRequest_":false,"type":0,"apsFrame":{"profileId":260,"sequence":222,"clusterId":1280,"sourceEndpoint":1,"destinationEndpoint":1,"groupId":0,"options":3392},"lastHopLqi":255,"lastHopRssi":-15,"sender":41508,"bindingIndex":255,"addressIndex":255,"message":{"type":"Buffer","data":[24,49,4,0]}}
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:ezsp: processMessage: {"messageType":0,"apsFrame":{"profileId":260,"sequence":222,"clusterId":1280,"sourceEndpoint":1,"destinationEndpoint":1,"groupId":0,"options":3392},"lqi":255,"rssi":-15,"sender":41508,"bindingIndex":255,"addressIndex":255,"message":{"type":"Buffer","data":[24,49,4,0]}}
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:controller: Received payload: clusterID=1280, address=41508, groupID=0, endpoint=1, destinationEndpoint=1, wasBroadcast=false, linkQuality=255, frame={"header":{"frameControl":{"frameType":0,"manufacturerSpecific":false,"direction":1,"disableDefaultResponse":true,"reservedBits":0},"transactionSequenceNumber":49,"commandIdentifier":4},"payload":[{"status":0}],"command":{"ID":4,"name":"writeRsp","parameters":[{"name":"status","type":32},{"name":"attrId","type":33,"conditions":[{"type":"statusNotEquals","value":0}]}]}}
zigbee2mqtt    | [2024-10-22 10:35:46] info:    z2m:mqtt: MQTT publish: topic 'zigbee2mqtt/0x744dbdfffe63f5e8', payload '{"last_seen":"2024-10-22T09:35:46.920Z","linkquality":255,"position":100,"state":"OPEN"}'
zigbee2mqtt    | [2024-10-22 10:35:46] debug:   zh:controller:device: Interview - IAS - wrote iasCieAddr
zigbee2mqtt    | [2024-10-22 10:35:47] debug:   zh:ezsp:uart: <-- [50fdb1a96b2a7d334ea6944a7d33aa559249984e277d5e12ce67fe047e]
zigbee2mqtt    | [2024-10-22 10:35:47] debug:   zh:ezsp:uart: <-- DATA (5,0,0): 50fdb1a96b2a134ea6944a13aa559249984e277e12ce67fe047e
zigbee2mqtt    | [2024-10-22 10:35:47] debug:   zh:ezsp:uart: --> ACK  (6)
zigbee2mqtt    | [2024-10-22 10:35:47] debug:   zh:ezsp:uart: --> [8610be7e]
zigbee2mqtt    | [2024-10-22 10:35:47] debug:   zh:ezsp:uart: <-- ACK (0): 50fdb1a96b2a134ea6944a13aa559249984e277e12ce67fe047e
zigbee2mqtt    | [2024-10-22 10:35:47] debug:   zh:ezsp:ezsp: <== Frame: bf90013f0006fcff00003600000000040000d5ff0000
zigbee2mqtt    | [2024-10-22 10:35:47] debug:   zh:ezsp:ezsp: <== 0x3f: {"_cls_":"messageSentHandler","_id_":63,"_isRequest_":false,"type":6,"indexOrDestination":65532,"apsFrame":{"profileId":0,"sequence":213,"clusterId":54,"sourceEndpoint":0,"destinationEndpoint":0,"groupId":0,"options":1024},"messageTag":255,"status":0,"message":{"type":"Buffer","data":[]}}
zigbee2mqtt    | [2024-10-22 10:35:47] debug:   zh:controller:device: IAS - '0x744dbdfffe63f5e8' sending enroll response (auto enroll)

What could be causing the lack of Zone Enroll requests in my implementation? Are there any additional steps needed after setting the CIE address to trigger the enroll request?

xieqinan commented 1 month ago

Hi @renatomotorline ,

The IAS Zone cluster supports three methods for device enrollment, though it's unclear which one is used by the SonOff SNZB-03. It might be best to observe the communication with a sniffer to compare successful and failed attempts. Alternatively, feel free to share the .pcap files of both cases, and I can help analyze the issue.

renatomotorline commented 4 weeks ago

I successfully received the status by utilizing the "Auto-Enroll-Response" enrolling method, and after that, I send a config report command(esp_zb_zcl_config_report_cmd_req). Now, every time I pass in front of the sensor I receive an ESP_ZB_CORE_CMD_IAS_ZONE_ZONE_STATUS_CHANGE_NOT_ID event.

1. Send a Write Attribute command on the IAS Zone server’s CIE_IAS_Address attribute with its IEEE address

esp_zb_zcl_write_attr_cmd_t cie_write_req;
  cie_write_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
  memcpy(cie_write_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr,
         sizeof(esp_zb_ieee_addr_t));
  cie_write_req.zcl_basic_cmd.src_endpoint = GATEWAY_ENDPOINT;
  cie_write_req.zcl_basic_cmd.dst_endpoint = endpoint_id;
  cie_write_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_IAS_ZONE;

  // Get gateway address
  esp_zb_ieee_addr_t addr = {0};
  esp_zb_get_long_address(addr);

  // Write the CIE Address (Gateway's IEEE Address)
  esp_zb_zcl_attribute_t cie_attribute;
  cie_attribute.id = ESP_ZB_ZCL_ATTR_IAS_ZONE_IAS_CIE_ADDRESS_ID;
  cie_attribute.data.type = ESP_ZB_ZCL_ATTR_TYPE_IEEE_ADDR;
  cie_attribute.data.size = sizeof(esp_zb_ieee_addr_t);
  cie_attribute.data.value = addr;

  cie_write_req.attr_field = &cie_attribute;
  cie_write_req.attr_number = 1;

  esp_zb_lock_acquire(portMAX_DELAY);
  uint8_t seq = esp_zb_zcl_write_attr_cmd_req(&cie_write_req);
  esp_zb_lock_release();

2. Send a Zone Enroll Response, which assigns the IAS Zone server’s ZoneID attribute

  esp_zb_zcl_ias_zone_enroll_response_cmd_t cmd_resp;
  cmd_resp.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
  memcpy(cmd_resp.zcl_basic_cmd.dst_addr_u.addr_long, device->ieee_addr,
         sizeof(esp_zb_ieee_addr_t));
  cmd_resp.zcl_basic_cmd.dst_endpoint = endpoint_id;
  cmd_resp.zcl_basic_cmd.src_endpoint = GATEWAY_ENDPOINT;
  cmd_resp.zone_id = zone_id;
  cmd_resp.enroll_rsp_code = ESP_ZB_ZCL_IAS_ZONE_ENROLL_RESPONSE_CODE_SUCCESS;
  esp_zb_lock_acquire(portMAX_DELAY);
  uint8_t seq = esp_zb_zcl_ias_zone_enroll_cmd_resp(&cmd_resp);
  esp_zb_lock_release();

3. Send Config report command

  esp_zb_zcl_config_report_cmd_t report_cmd;
  report_cmd.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
  report_cmd.zcl_basic_cmd.dst_endpoint = dst_endpoint;
  report_cmd.zcl_basic_cmd.src_endpoint = GATEWAY_ENDPOINT;
  report_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;

  report_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_IAS_ZONE;
  esp_zb_zcl_config_report_record_t records_window[] = {{
      .direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_SRV, // Request direction
      .attributeID = ESP_ZB_ZCL_ATTR_IAS_ZONE_ZONESTATUS_ID,
      .attrType = ESP_ZB_ZCL_ATTR_TYPE_16BITMAP,        // Attribute variable type
      .min_interval = 0, // Min report time
      .max_interval = 30, // Max report time
      .reportable_change = &min_change,
  }};
  report_cmd.record_number =
      sizeof(records_window) / sizeof(esp_zb_zcl_config_report_record_t);
  report_cmd.record_field = records_window;
  esp_zb_lock_acquire(portMAX_DELAY);
  uint8_t seq = esp_zb_zcl_config_report_cmd_req(&report_cmd);
  esp_zb_lock_release();