feat(zigbee): Add endpoint identification in read handlers + command structures fix (#11425)

* feat(zigbee): Add endpoint identification in read handlers

* fix(zigbee): initialize Zigbee command structures with zeros

* fix(zigbee): Spelling correction

* ci(pre-commit): Apply automatic fixes

---------

Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
This commit is contained in:
Jan Procházka 2025-06-04 16:40:28 +02:00 committed by GitHub
parent 375f2c002d
commit cae66e65a3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 390 additions and 89 deletions

View file

@ -34,7 +34,8 @@
#include "Zigbee.h"
/* Zigbee thermostat configuration */
#define THERMOSTAT_ENDPOINT_NUMBER 5
#define THERMOSTAT_ENDPOINT_NUMBER 1
#define USE_RECEIVE_TEMP_WITH_SOURCE 1
uint8_t button = BOOT_PIN;
ZigbeeThermostat zbThermostat = ZigbeeThermostat(THERMOSTAT_ENDPOINT_NUMBER);
@ -48,13 +49,28 @@ float sensor_tolerance;
struct tm timeinfo = {}; // Time structure for Time cluster
/****************** Temperature sensor handling *******************/
void recieveSensorTemp(float temperature) {
#if USE_RECEIVE_TEMP_WITH_SOURCE == 0
void receiveSensorTemp(float temperature) {
Serial.printf("Temperature sensor value: %.2f°C\n", temperature);
sensor_temp = temperature;
}
#else
void receiveSensorTempWithSource(float temperature, uint8_t src_endpoint, esp_zb_zcl_addr_t src_address) {
if (src_address.addr_type == ESP_ZB_ZCL_ADDR_TYPE_SHORT) {
Serial.printf("Temperature sensor value: %.2f°C from endpoint %d, address 0x%04x\n", temperature, src_endpoint, src_address.u.short_addr);
} else {
Serial.printf(
"Temperature sensor value: %.2f°C from endpoint %d, address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", temperature, src_endpoint,
src_address.u.ieee_addr[7], src_address.u.ieee_addr[6], src_address.u.ieee_addr[5], src_address.u.ieee_addr[4], src_address.u.ieee_addr[3],
src_address.u.ieee_addr[2], src_address.u.ieee_addr[1], src_address.u.ieee_addr[0]
);
}
sensor_temp = temperature;
}
#endif
void recieveSensorConfig(float min_temp, float max_temp, float tolerance) {
Serial.printf("Temperature sensor settings: min %.2f°C, max %.2f°C, tolerance %.2f°C\n", min_temp, max_temp, tolerance);
void receiveSensorConfig(float min_temp, float max_temp, float tolerance) {
Serial.printf("Temperature sensor config: min %.2f°C, max %.2f°C, tolerance %.2f°C\n", min_temp, max_temp, tolerance);
sensor_min_temp = min_temp;
sensor_max_temp = max_temp;
sensor_tolerance = tolerance;
@ -66,9 +82,15 @@ void setup() {
// Init button switch
pinMode(button, INPUT_PULLUP);
// Set callback functions for temperature and configuration receive
zbThermostat.onTempRecieve(recieveSensorTemp);
zbThermostat.onConfigRecieve(recieveSensorConfig);
// Set callback function for receiving temperature from sensor - Use only one option
#if USE_RECEIVE_TEMP_WITH_SOURCE == 0
zbThermostat.onTempReceive(receiveSensorTemp); // If you bound only one sensor or you don't need to know the source of the temperature
#else
zbThermostat.onTempReceiveWithSource(receiveSensorTempWithSource);
#endif
// Set callback function for receiving sensor configuration
zbThermostat.onConfigReceive(receiveSensorConfig);
//Optional: set Zigbee device name and model
zbThermostat.setManufacturerAndModel("Espressif", "ZigbeeThermostat");
@ -107,19 +129,30 @@ void setup() {
Serial.println();
// Get temperature sensor configuration
zbThermostat.getSensorSettings();
// Get temperature sensor configuration for all bound sensors by endpoint number and address
std::list<zb_device_params_t *> boundSensors = zbThermostat.getBoundDevices();
for (const auto &device : boundSensors) {
Serial.println("--------------------------------");
if (device->short_addr == 0x0000 || device->short_addr == 0xFFFF) { //End devices never have 0x0000 short address or 0xFFFF group address
Serial.printf(
"Device on endpoint %d, IEEE Address: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\r\n", device->endpoint, device->ieee_addr[7], device->ieee_addr[6],
device->ieee_addr[5], device->ieee_addr[4], device->ieee_addr[3], device->ieee_addr[2], device->ieee_addr[1], device->ieee_addr[0]
);
zbThermostat.getSensorSettings(device->endpoint, device->ieee_addr);
} else {
Serial.printf("Device on endpoint %d, short address: 0x%x\r\n", device->endpoint, device->short_addr);
zbThermostat.getSensorSettings(device->endpoint, device->short_addr);
}
}
}
void loop() {
// Handle button switch in loop()
if (digitalRead(button) == LOW) { // Push button pressed
// Key debounce handling
while (digitalRead(button) == LOW) {
delay(50);
}
// Set reporting interval for temperature sensor
zbThermostat.setTemperatureReporting(0, 10, 2);
}
@ -130,5 +163,6 @@ void loop() {
last_print = millis();
int temp_percent = (int)((sensor_temp - sensor_min_temp) / (sensor_max_temp - sensor_min_temp) * 100);
Serial.printf("Loop temperature info: %.2f°C (%d %%)\n", sensor_temp, temp_percent);
zbThermostat.printBoundDevices(Serial);
}
}

View file

@ -107,6 +107,7 @@ setLightColor KEYWORD2
# ZigbeeThermostat
onTempRecieve KEYWORD2
onConfigRecieve KEYWORD2
onTempReceiveWithSource KEYWORD2
getTemperature KEYWORD2
getSensorSettings KEYWORD2
setTemperatureReporting KEYWORD2
@ -191,4 +192,4 @@ ZIGBEE_DEFAULT_COORDINATOR_CONFIG LITERAL1
ZIGBEE_DEFAULT_RADIO_CONFIG LITERAL1
ZIGBEE_DEFAULT_UART_RCP_RADIO_CONFIG LITERAL1
ZIGBEE_DEFAULT_HOST_CONFIG LITERAL1
ZB_ARRAY_LENTH LITERAL1
ZB_ARRAY_LENGHT LITERAL1

View file

@ -145,7 +145,7 @@ bool ZigbeeEP::setBatteryVoltage(uint8_t voltage) {
bool ZigbeeEP::reportBatteryPercentage() {
/* Send report attributes command */
esp_zb_zcl_report_attr_cmd_t report_attr_cmd;
esp_zb_zcl_report_attr_cmd_t report_attr_cmd = {0};
report_attr_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
report_attr_cmd.attributeID = ESP_ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_PERCENTAGE_REMAINING_ID;
report_attr_cmd.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_CLI;
@ -166,7 +166,7 @@ bool ZigbeeEP::reportBatteryPercentage() {
char *ZigbeeEP::readManufacturer(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_addr) {
/* Read peer Manufacture Name & Model Identifier */
esp_zb_zcl_read_attr_cmd_t read_req;
esp_zb_zcl_read_attr_cmd_t read_req = {0};
if (short_addr != 0) {
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
@ -183,7 +183,7 @@ char *ZigbeeEP::readManufacturer(uint8_t endpoint, uint16_t short_addr, esp_zb_i
uint16_t attributes[] = {
ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID,
};
read_req.attr_number = ZB_ARRAY_LENTH(attributes);
read_req.attr_number = ZB_ARRAY_LENGHT(attributes);
read_req.attr_field = attributes;
if (_read_manufacturer != NULL) {
@ -204,7 +204,7 @@ char *ZigbeeEP::readManufacturer(uint8_t endpoint, uint16_t short_addr, esp_zb_i
char *ZigbeeEP::readModel(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_addr) {
/* Read peer Manufacture Name & Model Identifier */
esp_zb_zcl_read_attr_cmd_t read_req;
esp_zb_zcl_read_attr_cmd_t read_req = {0};
if (short_addr != 0) {
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
@ -221,7 +221,7 @@ char *ZigbeeEP::readModel(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_add
uint16_t attributes[] = {
ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID,
};
read_req.attr_number = ZB_ARRAY_LENTH(attributes);
read_req.attr_number = ZB_ARRAY_LENGHT(attributes);
read_req.attr_field = attributes;
if (_read_model != NULL) {
@ -375,7 +375,7 @@ bool ZigbeeEP::setTimezone(int32_t gmt_offset) {
tm ZigbeeEP::getTime(uint8_t endpoint, int32_t short_addr, esp_zb_ieee_addr_t ieee_addr) {
/* Read peer time */
esp_zb_zcl_read_attr_cmd_t read_req;
esp_zb_zcl_read_attr_cmd_t read_req = {0};
if (short_addr >= 0) {
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
@ -386,7 +386,7 @@ tm ZigbeeEP::getTime(uint8_t endpoint, int32_t short_addr, esp_zb_ieee_addr_t ie
}
uint16_t attributes[] = {ESP_ZB_ZCL_ATTR_TIME_TIME_ID};
read_req.attr_number = ZB_ARRAY_LENTH(attributes);
read_req.attr_number = ZB_ARRAY_LENGHT(attributes);
read_req.attr_field = attributes;
read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TIME;
@ -427,7 +427,7 @@ tm ZigbeeEP::getTime(uint8_t endpoint, int32_t short_addr, esp_zb_ieee_addr_t ie
int32_t ZigbeeEP::getTimezone(uint8_t endpoint, int32_t short_addr, esp_zb_ieee_addr_t ieee_addr) {
/* Read peer timezone */
esp_zb_zcl_read_attr_cmd_t read_req;
esp_zb_zcl_read_attr_cmd_t read_req = {0};
if (short_addr >= 0) {
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
@ -438,7 +438,7 @@ int32_t ZigbeeEP::getTimezone(uint8_t endpoint, int32_t short_addr, esp_zb_ieee_
}
uint16_t attributes[] = {ESP_ZB_ZCL_ATTR_TIME_TIME_ZONE_ID};
read_req.attr_number = ZB_ARRAY_LENTH(attributes);
read_req.attr_number = ZB_ARRAY_LENGHT(attributes);
read_req.attr_field = attributes;
read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TIME;
@ -543,7 +543,7 @@ static void findOTAServer(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t
}
void ZigbeeEP::requestOTAUpdate() {
esp_zb_zdo_match_desc_req_param_t req;
esp_zb_zdo_match_desc_req_param_t req = {0};
uint16_t cluster_list[] = {ESP_ZB_ZCL_CLUSTER_ID_OTA_UPGRADE};
/* Match the OTA server of coordinator */

View file

@ -12,7 +12,7 @@
#define ZB_CMD_TIMEOUT 10000 // 10 seconds
#define OTA_UPGRADE_QUERY_INTERVAL (1 * 60) // 1 hour = 60 minutes
#define ZB_ARRAY_LENTH(arr) (sizeof(arr) / sizeof(arr[0]))
#define ZB_ARRAY_LENGHT(arr) (sizeof(arr) / sizeof(arr[0]))
#define RGB_TO_XYZ(r, g, b, X, Y, Z) \
{ \
@ -131,7 +131,7 @@ public:
// list of all handlers function calls, to be override by EPs implementation
virtual void zbAttributeSet(const esp_zb_zcl_set_attr_value_message_t *message) {};
virtual void zbAttributeRead(uint16_t cluster_id, const esp_zb_zcl_attribute_t *attribute) {};
virtual void zbAttributeRead(uint16_t cluster_id, const esp_zb_zcl_attribute_t *attribute, uint8_t src_endpoint, esp_zb_zcl_addr_t src_address) {};
virtual void zbReadBasicCluster(const esp_zb_zcl_attribute_t *attribute); //already implemented
virtual void zbIdentify(const esp_zb_zcl_set_attr_value_message_t *message);
virtual void zbWindowCoveringMovementCmd(const esp_zb_zcl_window_covering_movement_message_t *message) {};

View file

@ -108,7 +108,9 @@ static esp_err_t zb_attribute_reporting_handler(const esp_zb_zcl_report_attr_mes
// List through all Zigbee EPs and call the callback function, with the message
for (std::list<ZigbeeEP *>::iterator it = Zigbee.ep_objects.begin(); it != Zigbee.ep_objects.end(); ++it) {
if (message->dst_endpoint == (*it)->getEndpoint()) {
(*it)->zbAttributeRead(message->cluster, &message->attribute); //method zbAttributeRead must be implemented in specific EP class
(*it)->zbAttributeRead(
message->cluster, &message->attribute, message->src_endpoint, message->src_address
); //method zbAttributeRead must be implemented in specific EP class
}
}
return ESP_OK;
@ -142,7 +144,9 @@ static esp_err_t zb_cmd_read_attr_resp_handler(const esp_zb_zcl_cmd_read_attr_re
} else if (message->info.cluster == ESP_ZB_ZCL_CLUSTER_ID_TIME) {
(*it)->zbReadTimeCluster(&variable->attribute); //method zbReadTimeCluster implemented in the common EP class
} else {
(*it)->zbAttributeRead(message->info.cluster, &variable->attribute); //method zbAttributeRead must be implemented in specific EP class
(*it)->zbAttributeRead(
message->info.cluster, &variable->attribute, message->info.src_endpoint, message->info.src_address
); //method zbAttributeRead must be implemented in specific EP class
}
}
variable = variable->next;

View file

@ -53,7 +53,7 @@ void ZigbeeColorDimmerSwitch::findCb(esp_zb_zdp_status_t zdo_status, uint16_t ad
ZigbeeColorDimmerSwitch *instance = static_cast<ZigbeeColorDimmerSwitch *>(user_ctx);
if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) {
log_d("Found light endpoint");
esp_zb_zdo_bind_req_param_t bind_req;
esp_zb_zdo_bind_req_param_t bind_req = {0};
zb_device_params_t *light = (zb_device_params_t *)malloc(sizeof(zb_device_params_t));
light->endpoint = endpoint;
light->short_addr = addr;
@ -97,7 +97,7 @@ void ZigbeeColorDimmerSwitch::findEndpoint(esp_zb_zdo_match_desc_req_param_t *cm
// Methods to control the light
void ZigbeeColorDimmerSwitch::lightToggle() {
if (_is_bound) {
esp_zb_zcl_on_off_cmd_t cmd_req;
esp_zb_zcl_on_off_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_TOGGLE_ID;
@ -112,7 +112,7 @@ void ZigbeeColorDimmerSwitch::lightToggle() {
void ZigbeeColorDimmerSwitch::lightToggle(uint16_t group_addr) {
if (_is_bound) {
esp_zb_zcl_on_off_cmd_t cmd_req;
esp_zb_zcl_on_off_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr;
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT;
@ -128,7 +128,7 @@ void ZigbeeColorDimmerSwitch::lightToggle(uint16_t group_addr) {
void ZigbeeColorDimmerSwitch::lightToggle(uint8_t endpoint, uint16_t short_addr) {
if (_is_bound) {
esp_zb_zcl_on_off_cmd_t cmd_req;
esp_zb_zcl_on_off_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.zcl_basic_cmd.dst_endpoint = endpoint;
cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
@ -145,7 +145,7 @@ void ZigbeeColorDimmerSwitch::lightToggle(uint8_t endpoint, uint16_t short_addr)
void ZigbeeColorDimmerSwitch::lightToggle(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) {
if (_is_bound) {
esp_zb_zcl_on_off_cmd_t cmd_req;
esp_zb_zcl_on_off_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.zcl_basic_cmd.dst_endpoint = endpoint;
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
@ -165,7 +165,7 @@ void ZigbeeColorDimmerSwitch::lightToggle(uint8_t endpoint, esp_zb_ieee_addr_t i
void ZigbeeColorDimmerSwitch::lightOn() {
if (_is_bound) {
esp_zb_zcl_on_off_cmd_t cmd_req;
esp_zb_zcl_on_off_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_ON_ID;
@ -180,7 +180,7 @@ void ZigbeeColorDimmerSwitch::lightOn() {
void ZigbeeColorDimmerSwitch::lightOn(uint16_t group_addr) {
if (_is_bound) {
esp_zb_zcl_on_off_cmd_t cmd_req;
esp_zb_zcl_on_off_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr;
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT;
@ -196,7 +196,7 @@ void ZigbeeColorDimmerSwitch::lightOn(uint16_t group_addr) {
void ZigbeeColorDimmerSwitch::lightOn(uint8_t endpoint, uint16_t short_addr) {
if (_is_bound) {
esp_zb_zcl_on_off_cmd_t cmd_req;
esp_zb_zcl_on_off_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.zcl_basic_cmd.dst_endpoint = endpoint;
cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
@ -213,7 +213,7 @@ void ZigbeeColorDimmerSwitch::lightOn(uint8_t endpoint, uint16_t short_addr) {
void ZigbeeColorDimmerSwitch::lightOn(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) {
if (_is_bound) {
esp_zb_zcl_on_off_cmd_t cmd_req;
esp_zb_zcl_on_off_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.zcl_basic_cmd.dst_endpoint = endpoint;
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
@ -233,7 +233,7 @@ void ZigbeeColorDimmerSwitch::lightOn(uint8_t endpoint, esp_zb_ieee_addr_t ieee_
void ZigbeeColorDimmerSwitch::lightOff() {
if (_is_bound) {
esp_zb_zcl_on_off_cmd_t cmd_req;
esp_zb_zcl_on_off_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_OFF_ID;
@ -248,7 +248,7 @@ void ZigbeeColorDimmerSwitch::lightOff() {
void ZigbeeColorDimmerSwitch::lightOff(uint16_t group_addr) {
if (_is_bound) {
esp_zb_zcl_on_off_cmd_t cmd_req;
esp_zb_zcl_on_off_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr;
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT;
@ -264,7 +264,7 @@ void ZigbeeColorDimmerSwitch::lightOff(uint16_t group_addr) {
void ZigbeeColorDimmerSwitch::lightOff(uint8_t endpoint, uint16_t short_addr) {
if (_is_bound) {
esp_zb_zcl_on_off_cmd_t cmd_req;
esp_zb_zcl_on_off_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.zcl_basic_cmd.dst_endpoint = endpoint;
cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
@ -281,7 +281,7 @@ void ZigbeeColorDimmerSwitch::lightOff(uint8_t endpoint, uint16_t short_addr) {
void ZigbeeColorDimmerSwitch::lightOff(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) {
if (_is_bound) {
esp_zb_zcl_on_off_cmd_t cmd_req;
esp_zb_zcl_on_off_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.zcl_basic_cmd.dst_endpoint = endpoint;
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
@ -301,7 +301,7 @@ void ZigbeeColorDimmerSwitch::lightOff(uint8_t endpoint, esp_zb_ieee_addr_t ieee
void ZigbeeColorDimmerSwitch::lightOffWithEffect(uint8_t effect_id, uint8_t effect_variant) {
if (_is_bound) {
esp_zb_zcl_on_off_off_with_effect_cmd_t cmd_req;
esp_zb_zcl_on_off_off_with_effect_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
cmd_req.effect_id = effect_id;
@ -317,7 +317,7 @@ void ZigbeeColorDimmerSwitch::lightOffWithEffect(uint8_t effect_id, uint8_t effe
void ZigbeeColorDimmerSwitch::lightOnWithSceneRecall() {
if (_is_bound) {
esp_zb_zcl_on_off_on_with_recall_global_scene_cmd_t cmd_req;
esp_zb_zcl_on_off_on_with_recall_global_scene_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
log_v("Sending 'light on with scene recall' command");
@ -331,7 +331,7 @@ void ZigbeeColorDimmerSwitch::lightOnWithSceneRecall() {
void ZigbeeColorDimmerSwitch::lightOnWithTimedOff(uint8_t on_off_control, uint16_t time_on, uint16_t time_off) {
if (_is_bound) {
esp_zb_zcl_on_off_on_with_timed_off_cmd_t cmd_req;
esp_zb_zcl_on_off_on_with_timed_off_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
cmd_req.on_off_control = on_off_control; //TODO: Test how it works, then maybe change API
@ -348,7 +348,7 @@ void ZigbeeColorDimmerSwitch::lightOnWithTimedOff(uint8_t on_off_control, uint16
void ZigbeeColorDimmerSwitch::setLightLevel(uint8_t level) {
if (_is_bound) {
esp_zb_zcl_move_to_level_cmd_t cmd_req;
esp_zb_zcl_move_to_level_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
cmd_req.level = level;
@ -364,7 +364,7 @@ void ZigbeeColorDimmerSwitch::setLightLevel(uint8_t level) {
void ZigbeeColorDimmerSwitch::setLightLevel(uint8_t level, uint16_t group_addr) {
if (_is_bound) {
esp_zb_zcl_move_to_level_cmd_t cmd_req;
esp_zb_zcl_move_to_level_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr;
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT;
@ -381,7 +381,7 @@ void ZigbeeColorDimmerSwitch::setLightLevel(uint8_t level, uint16_t group_addr)
void ZigbeeColorDimmerSwitch::setLightLevel(uint8_t level, uint8_t endpoint, uint16_t short_addr) {
if (_is_bound) {
esp_zb_zcl_move_to_level_cmd_t cmd_req;
esp_zb_zcl_move_to_level_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.zcl_basic_cmd.dst_endpoint = endpoint;
cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
@ -399,7 +399,7 @@ void ZigbeeColorDimmerSwitch::setLightLevel(uint8_t level, uint8_t endpoint, uin
void ZigbeeColorDimmerSwitch::setLightLevel(uint8_t level, uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) {
if (_is_bound) {
esp_zb_zcl_move_to_level_cmd_t cmd_req;
esp_zb_zcl_move_to_level_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.zcl_basic_cmd.dst_endpoint = endpoint;
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
@ -422,7 +422,7 @@ void ZigbeeColorDimmerSwitch::setLightColor(uint8_t red, uint8_t green, uint8_t
if (_is_bound) {
espXyColor_t xy_color = espRgbToXYColor(red, green, blue);
esp_zb_zcl_color_move_to_color_cmd_t cmd_req;
esp_zb_zcl_color_move_to_color_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
cmd_req.color_x = xy_color.x;
@ -441,7 +441,7 @@ void ZigbeeColorDimmerSwitch::setLightColor(uint8_t red, uint8_t green, uint8_t
if (_is_bound) {
espXyColor_t xy_color = espRgbToXYColor(red, green, blue);
esp_zb_zcl_color_move_to_color_cmd_t cmd_req;
esp_zb_zcl_color_move_to_color_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr;
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT;
@ -461,7 +461,7 @@ void ZigbeeColorDimmerSwitch::setLightColor(uint8_t red, uint8_t green, uint8_t
if (_is_bound) {
espXyColor_t xy_color = espRgbToXYColor(red, green, blue);
esp_zb_zcl_color_move_to_color_cmd_t cmd_req;
esp_zb_zcl_color_move_to_color_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.zcl_basic_cmd.dst_endpoint = endpoint;
cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
@ -482,7 +482,7 @@ void ZigbeeColorDimmerSwitch::setLightColor(uint8_t red, uint8_t green, uint8_t
if (_is_bound) {
espXyColor_t xy_color = espRgbToXYColor(red, green, blue);
esp_zb_zcl_color_move_to_color_cmd_t cmd_req;
esp_zb_zcl_color_move_to_color_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.zcl_basic_cmd.dst_endpoint = endpoint;
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;

View file

@ -52,7 +52,7 @@ void ZigbeeSwitch::findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t
ZigbeeSwitch *instance = static_cast<ZigbeeSwitch *>(user_ctx);
if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) {
log_d("Found light endpoint");
esp_zb_zdo_bind_req_param_t bind_req;
esp_zb_zdo_bind_req_param_t bind_req = {0};
zb_device_params_t *light = (zb_device_params_t *)malloc(sizeof(zb_device_params_t));
light->endpoint = endpoint;
light->short_addr = addr;
@ -94,7 +94,7 @@ void ZigbeeSwitch::findEndpoint(esp_zb_zdo_match_desc_req_param_t *cmd_req) {
// Methods to control the light
void ZigbeeSwitch::lightToggle() {
if (_is_bound) {
esp_zb_zcl_on_off_cmd_t cmd_req;
esp_zb_zcl_on_off_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_TOGGLE_ID;
@ -109,7 +109,7 @@ void ZigbeeSwitch::lightToggle() {
void ZigbeeSwitch::lightToggle(uint16_t group_addr) {
if (_is_bound) {
esp_zb_zcl_on_off_cmd_t cmd_req;
esp_zb_zcl_on_off_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr;
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT;
@ -125,7 +125,7 @@ void ZigbeeSwitch::lightToggle(uint16_t group_addr) {
void ZigbeeSwitch::lightToggle(uint8_t endpoint, uint16_t short_addr) {
if (_is_bound) {
esp_zb_zcl_on_off_cmd_t cmd_req;
esp_zb_zcl_on_off_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.zcl_basic_cmd.dst_endpoint = endpoint;
cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
@ -142,7 +142,7 @@ void ZigbeeSwitch::lightToggle(uint8_t endpoint, uint16_t short_addr) {
void ZigbeeSwitch::lightToggle(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) {
if (_is_bound) {
esp_zb_zcl_on_off_cmd_t cmd_req;
esp_zb_zcl_on_off_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.zcl_basic_cmd.dst_endpoint = endpoint;
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
@ -162,7 +162,7 @@ void ZigbeeSwitch::lightToggle(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) {
void ZigbeeSwitch::lightOn() {
if (_is_bound) {
esp_zb_zcl_on_off_cmd_t cmd_req;
esp_zb_zcl_on_off_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_ON_ID;
@ -177,7 +177,7 @@ void ZigbeeSwitch::lightOn() {
void ZigbeeSwitch::lightOn(uint16_t group_addr) {
if (_is_bound) {
esp_zb_zcl_on_off_cmd_t cmd_req;
esp_zb_zcl_on_off_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr;
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT;
@ -193,7 +193,7 @@ void ZigbeeSwitch::lightOn(uint16_t group_addr) {
void ZigbeeSwitch::lightOn(uint8_t endpoint, uint16_t short_addr) {
if (_is_bound) {
esp_zb_zcl_on_off_cmd_t cmd_req;
esp_zb_zcl_on_off_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.zcl_basic_cmd.dst_endpoint = endpoint;
cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
@ -210,7 +210,7 @@ void ZigbeeSwitch::lightOn(uint8_t endpoint, uint16_t short_addr) {
void ZigbeeSwitch::lightOn(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) {
if (_is_bound) {
esp_zb_zcl_on_off_cmd_t cmd_req;
esp_zb_zcl_on_off_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.zcl_basic_cmd.dst_endpoint = endpoint;
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
@ -230,7 +230,7 @@ void ZigbeeSwitch::lightOn(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) {
void ZigbeeSwitch::lightOff() {
if (_is_bound) {
esp_zb_zcl_on_off_cmd_t cmd_req;
esp_zb_zcl_on_off_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
cmd_req.on_off_cmd_id = ESP_ZB_ZCL_CMD_ON_OFF_OFF_ID;
@ -245,7 +245,7 @@ void ZigbeeSwitch::lightOff() {
void ZigbeeSwitch::lightOff(uint16_t group_addr) {
if (_is_bound) {
esp_zb_zcl_on_off_cmd_t cmd_req;
esp_zb_zcl_on_off_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr;
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT;
@ -261,7 +261,7 @@ void ZigbeeSwitch::lightOff(uint16_t group_addr) {
void ZigbeeSwitch::lightOff(uint8_t endpoint, uint16_t short_addr) {
if (_is_bound) {
esp_zb_zcl_on_off_cmd_t cmd_req;
esp_zb_zcl_on_off_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.zcl_basic_cmd.dst_endpoint = endpoint;
cmd_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
@ -278,7 +278,7 @@ void ZigbeeSwitch::lightOff(uint8_t endpoint, uint16_t short_addr) {
void ZigbeeSwitch::lightOff(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) {
if (_is_bound) {
esp_zb_zcl_on_off_cmd_t cmd_req;
esp_zb_zcl_on_off_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.zcl_basic_cmd.dst_endpoint = endpoint;
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
@ -298,7 +298,7 @@ void ZigbeeSwitch::lightOff(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) {
void ZigbeeSwitch::lightOffWithEffect(uint8_t effect_id, uint8_t effect_variant) {
if (_is_bound) {
esp_zb_zcl_on_off_off_with_effect_cmd_t cmd_req;
esp_zb_zcl_on_off_off_with_effect_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
cmd_req.effect_id = effect_id;
@ -314,7 +314,7 @@ void ZigbeeSwitch::lightOffWithEffect(uint8_t effect_id, uint8_t effect_variant)
void ZigbeeSwitch::lightOnWithSceneRecall() {
if (_is_bound) {
esp_zb_zcl_on_off_on_with_recall_global_scene_cmd_t cmd_req;
esp_zb_zcl_on_off_on_with_recall_global_scene_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
log_v("Sending 'light on with scene recall' command");
@ -327,7 +327,7 @@ void ZigbeeSwitch::lightOnWithSceneRecall() {
}
void ZigbeeSwitch::lightOnWithTimedOff(uint8_t on_off_control, uint16_t time_on, uint16_t time_off) {
if (_is_bound) {
esp_zb_zcl_on_off_on_with_timed_off_cmd_t cmd_req;
esp_zb_zcl_on_off_on_with_timed_off_cmd_t cmd_req = {0};
cmd_req.zcl_basic_cmd.src_endpoint = _endpoint;
cmd_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
cmd_req.on_off_control = on_off_control; //TODO: Test how it works, then maybe change API

View file

@ -65,7 +65,7 @@ void ZigbeeThermostat::findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uin
ZigbeeThermostat *instance = static_cast<ZigbeeThermostat *>(user_ctx);
if (zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) {
log_i("Found temperature sensor");
esp_zb_zdo_bind_req_param_t bind_req;
esp_zb_zdo_bind_req_param_t bind_req = {0};
/* Store the information of the remote device */
zb_device_params_t *sensor = (zb_device_params_t *)malloc(sizeof(zb_device_params_t));
sensor->endpoint = endpoint;
@ -115,31 +115,38 @@ void ZigbeeThermostat::findEndpoint(esp_zb_zdo_match_desc_req_param_t *param) {
esp_zb_zdo_match_cluster(param, ZigbeeThermostat::findCbWrapper, this);
}
void ZigbeeThermostat::zbAttributeRead(uint16_t cluster_id, const esp_zb_zcl_attribute_t *attribute) {
void ZigbeeThermostat::zbAttributeRead(uint16_t cluster_id, const esp_zb_zcl_attribute_t *attribute, uint8_t src_endpoint, esp_zb_zcl_addr_t src_address) {
static uint8_t read_config = 0;
if (cluster_id == ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT) {
if (attribute->id == ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID && attribute->data.type == ESP_ZB_ZCL_ATTR_TYPE_S16) {
int16_t value = attribute->data.value ? *(int16_t *)attribute->data.value : 0;
if (_on_temp_recieve) {
_on_temp_recieve(zb_s16_to_temperature(value));
if (_on_temp_receive) {
_on_temp_receive(zb_s16_to_temperature(value));
}
if (_on_temp_receive_with_source) {
_on_temp_receive_with_source(zb_s16_to_temperature(value), src_endpoint, src_address);
}
}
if (attribute->id == ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MIN_VALUE_ID && attribute->data.type == ESP_ZB_ZCL_ATTR_TYPE_S16) {
int16_t min_value = attribute->data.value ? *(int16_t *)attribute->data.value : 0;
_min_temp = zb_s16_to_temperature(min_value);
read_config++;
log_d("Received min temperature: %.2f°C from endpoint %d", _min_temp, src_endpoint);
}
if (attribute->id == ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MAX_VALUE_ID && attribute->data.type == ESP_ZB_ZCL_ATTR_TYPE_S16) {
int16_t max_value = attribute->data.value ? *(int16_t *)attribute->data.value : 0;
_max_temp = zb_s16_to_temperature(max_value);
read_config++;
log_d("Received max temperature: %.2f°C from endpoint %d", _max_temp, src_endpoint);
}
if (attribute->id == ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_TOLERANCE_ID && attribute->data.type == ESP_ZB_ZCL_ATTR_TYPE_U16) {
uint16_t tolerance = attribute->data.value ? *(uint16_t *)attribute->data.value : 0;
_tolerance = 1.0 * tolerance / 100;
read_config++;
log_d("Received tolerance: %.2f°C from endpoint %d", _tolerance, src_endpoint);
}
if (read_config == 3) {
log_d("All config attributes processed");
read_config = 0;
xSemaphoreGive(lock);
}
@ -147,14 +154,14 @@ void ZigbeeThermostat::zbAttributeRead(uint16_t cluster_id, const esp_zb_zcl_att
}
void ZigbeeThermostat::getTemperature() {
/* Send "read attributes" command to the bound sensor */
esp_zb_zcl_read_attr_cmd_t read_req;
/* Send "read attributes" command to all bound sensors */
esp_zb_zcl_read_attr_cmd_t read_req = {0};
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
read_req.zcl_basic_cmd.src_endpoint = _endpoint;
read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;
uint16_t attributes[] = {ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID};
read_req.attr_number = ZB_ARRAY_LENTH(attributes);
read_req.attr_number = ZB_ARRAY_LENGHT(attributes);
read_req.attr_field = attributes;
log_i("Sending 'read temperature' command");
@ -163,9 +170,68 @@ void ZigbeeThermostat::getTemperature() {
esp_zb_lock_release();
}
void ZigbeeThermostat::getTemperature(uint16_t group_addr) {
/* Send "read attributes" command to the group */
esp_zb_zcl_read_attr_cmd_t read_req = {0};
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT;
read_req.zcl_basic_cmd.src_endpoint = _endpoint;
read_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr;
read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;
uint16_t attributes[] = {ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID};
read_req.attr_number = ZB_ARRAY_LENGHT(attributes);
read_req.attr_field = attributes;
log_i("Sending 'read temperature' command to group address 0x%x", group_addr);
esp_zb_lock_acquire(portMAX_DELAY);
esp_zb_zcl_read_attr_cmd_req(&read_req);
esp_zb_lock_release();
}
void ZigbeeThermostat::getTemperature(uint8_t endpoint, uint16_t short_addr) {
/* Send "read attributes" command to specific endpoint */
esp_zb_zcl_read_attr_cmd_t read_req = {0};
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
read_req.zcl_basic_cmd.src_endpoint = _endpoint;
read_req.zcl_basic_cmd.dst_endpoint = endpoint;
read_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;
uint16_t attributes[] = {ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID};
read_req.attr_number = ZB_ARRAY_LENGHT(attributes);
read_req.attr_field = attributes;
log_i("Sending 'read temperature' command to endpoint %d, address 0x%x", endpoint, short_addr);
esp_zb_lock_acquire(portMAX_DELAY);
esp_zb_zcl_read_attr_cmd_req(&read_req);
esp_zb_lock_release();
}
void ZigbeeThermostat::getTemperature(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) {
/* Send "read attributes" command to specific endpoint */
esp_zb_zcl_read_attr_cmd_t read_req = {0};
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
read_req.zcl_basic_cmd.src_endpoint = _endpoint;
read_req.zcl_basic_cmd.dst_endpoint = endpoint;
read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;
memcpy(read_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t));
uint16_t attributes[] = {ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID};
read_req.attr_number = ZB_ARRAY_LENGHT(attributes);
read_req.attr_field = attributes;
log_i(
"Sending 'read temperature' command to endpoint %d, ieee address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", endpoint, ieee_addr[7], ieee_addr[6],
ieee_addr[5], ieee_addr[4], ieee_addr[3], ieee_addr[2], ieee_addr[1], ieee_addr[0]
);
esp_zb_lock_acquire(portMAX_DELAY);
esp_zb_zcl_read_attr_cmd_req(&read_req);
esp_zb_lock_release();
}
void ZigbeeThermostat::getSensorSettings() {
/* Send "read attributes" command to the bound sensor */
esp_zb_zcl_read_attr_cmd_t read_req;
/* Send "read attributes" command to all bound sensors */
esp_zb_zcl_read_attr_cmd_t read_req = {0};
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
read_req.zcl_basic_cmd.src_endpoint = _endpoint;
read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;
@ -173,10 +239,10 @@ void ZigbeeThermostat::getSensorSettings() {
uint16_t attributes[] = {
ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MIN_VALUE_ID, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MAX_VALUE_ID, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_TOLERANCE_ID
};
read_req.attr_number = ZB_ARRAY_LENTH(attributes);
read_req.attr_number = ZB_ARRAY_LENGHT(attributes);
read_req.attr_field = attributes;
log_i("Sending 'read temperature' command");
log_i("Sending 'read sensor settings' command");
esp_zb_lock_acquire(portMAX_DELAY);
esp_zb_zcl_read_attr_cmd_req(&read_req);
esp_zb_lock_release();
@ -187,13 +253,105 @@ void ZigbeeThermostat::getSensorSettings() {
return;
} else {
//Call the callback function when all attributes are read
_on_config_recieve(_min_temp, _max_temp, _tolerance);
_on_config_receive(_min_temp, _max_temp, _tolerance);
}
}
void ZigbeeThermostat::getSensorSettings(uint16_t group_addr) {
/* Send "read attributes" command to the group */
esp_zb_zcl_read_attr_cmd_t read_req = {0};
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT;
read_req.zcl_basic_cmd.src_endpoint = _endpoint;
read_req.zcl_basic_cmd.dst_addr_u.addr_short = group_addr;
read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;
uint16_t attributes[] = {
ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MIN_VALUE_ID, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MAX_VALUE_ID, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_TOLERANCE_ID
};
read_req.attr_number = ZB_ARRAY_LENGHT(attributes);
read_req.attr_field = attributes;
log_i("Sending 'read sensor settings' command to group address 0x%x", group_addr);
esp_zb_lock_acquire(portMAX_DELAY);
esp_zb_zcl_read_attr_cmd_req(&read_req);
esp_zb_lock_release();
//Take semaphore to wait for response of all attributes
if (xSemaphoreTake(lock, ZB_CMD_TIMEOUT) != pdTRUE) {
log_e("Error while reading attributes");
return;
} else {
//Call the callback function when all attributes are read
_on_config_receive(_min_temp, _max_temp, _tolerance);
}
}
void ZigbeeThermostat::getSensorSettings(uint8_t endpoint, uint16_t short_addr) {
/* Send "read attributes" command to specific endpoint */
esp_zb_zcl_read_attr_cmd_t read_req = {0};
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
read_req.zcl_basic_cmd.src_endpoint = _endpoint;
read_req.zcl_basic_cmd.dst_endpoint = endpoint;
read_req.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;
uint16_t attributes[] = {
ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MIN_VALUE_ID, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MAX_VALUE_ID, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_TOLERANCE_ID
};
read_req.attr_number = ZB_ARRAY_LENGHT(attributes);
read_req.attr_field = attributes;
log_i("Sending 'read sensor settings' command to endpoint %d, address 0x%x", endpoint, short_addr);
esp_zb_lock_acquire(portMAX_DELAY);
esp_zb_zcl_read_attr_cmd_req(&read_req);
esp_zb_lock_release();
//Take semaphore to wait for response of all attributes
if (xSemaphoreTake(lock, ZB_CMD_TIMEOUT) != pdTRUE) {
log_e("Error while reading attributes");
return;
} else {
//Call the callback function when all attributes are read
_on_config_receive(_min_temp, _max_temp, _tolerance);
}
}
void ZigbeeThermostat::getSensorSettings(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr) {
/* Send "read attributes" command to specific endpoint */
esp_zb_zcl_read_attr_cmd_t read_req = {0};
read_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
read_req.zcl_basic_cmd.src_endpoint = _endpoint;
read_req.zcl_basic_cmd.dst_endpoint = endpoint;
read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;
memcpy(read_req.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t));
uint16_t attributes[] = {
ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MIN_VALUE_ID, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_MAX_VALUE_ID, ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_TOLERANCE_ID
};
read_req.attr_number = ZB_ARRAY_LENGHT(attributes);
read_req.attr_field = attributes;
log_i(
"Sending 'read sensor settings' command to endpoint %d, ieee address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", endpoint, ieee_addr[7], ieee_addr[6],
ieee_addr[5], ieee_addr[4], ieee_addr[3], ieee_addr[2], ieee_addr[1], ieee_addr[0]
);
esp_zb_lock_acquire(portMAX_DELAY);
esp_zb_zcl_read_attr_cmd_req(&read_req);
esp_zb_lock_release();
//Take semaphore to wait for response of all attributes
if (xSemaphoreTake(lock, ZB_CMD_TIMEOUT) != pdTRUE) {
log_e("Error while reading attributes");
return;
} else {
//Call the callback function when all attributes are read
_on_config_receive(_min_temp, _max_temp, _tolerance);
}
}
void ZigbeeThermostat::setTemperatureReporting(uint16_t min_interval, uint16_t max_interval, float delta) {
/* Send "configure report attribute" command to the bound sensor */
esp_zb_zcl_config_report_cmd_t report_cmd;
/* Send "configure report attribute" command to all bound sensors */
esp_zb_zcl_config_report_cmd_t report_cmd = {0};
report_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
report_cmd.zcl_basic_cmd.src_endpoint = _endpoint;
report_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;
@ -206,10 +364,10 @@ void ZigbeeThermostat::setTemperatureReporting(uint16_t min_interval, uint16_t m
.attrType = ESP_ZB_ZCL_ATTR_TYPE_S16,
.min_interval = min_interval,
.max_interval = max_interval,
.reportable_change = &report_change,
.reportable_change = (void *)&report_change,
},
};
report_cmd.record_number = ZB_ARRAY_LENTH(records);
report_cmd.record_number = ZB_ARRAY_LENGHT(records);
report_cmd.record_field = records;
log_i("Sending 'configure reporting' command");
@ -218,4 +376,93 @@ void ZigbeeThermostat::setTemperatureReporting(uint16_t min_interval, uint16_t m
esp_zb_lock_release();
}
void ZigbeeThermostat::setTemperatureReporting(uint16_t group_addr, uint16_t min_interval, uint16_t max_interval, float delta) {
/* Send "configure report attribute" command to the group */
esp_zb_zcl_config_report_cmd_t report_cmd = {0};
report_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_16_GROUP_ENDP_NOT_PRESENT;
report_cmd.zcl_basic_cmd.src_endpoint = _endpoint;
report_cmd.zcl_basic_cmd.dst_addr_u.addr_short = group_addr;
report_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;
int16_t report_change = (int16_t)delta * 100;
esp_zb_zcl_config_report_record_t records[] = {
{
.direction = ESP_ZB_ZCL_REPORT_DIRECTION_SEND,
.attributeID = ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID,
.attrType = ESP_ZB_ZCL_ATTR_TYPE_S16,
.min_interval = min_interval,
.max_interval = max_interval,
.reportable_change = (void *)&report_change,
},
};
report_cmd.record_number = ZB_ARRAY_LENGHT(records);
report_cmd.record_field = records;
log_i("Sending 'configure reporting' command to group address 0x%x", group_addr);
esp_zb_lock_acquire(portMAX_DELAY);
esp_zb_zcl_config_report_cmd_req(&report_cmd);
esp_zb_lock_release();
}
void ZigbeeThermostat::setTemperatureReporting(uint8_t endpoint, uint16_t short_addr, uint16_t min_interval, uint16_t max_interval, float delta) {
/* Send "configure report attribute" command to specific endpoint */
esp_zb_zcl_config_report_cmd_t report_cmd = {0};
report_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
report_cmd.zcl_basic_cmd.src_endpoint = _endpoint;
report_cmd.zcl_basic_cmd.dst_endpoint = endpoint;
report_cmd.zcl_basic_cmd.dst_addr_u.addr_short = short_addr;
report_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;
int16_t report_change = (int16_t)delta * 100;
esp_zb_zcl_config_report_record_t records[] = {
{
.direction = ESP_ZB_ZCL_REPORT_DIRECTION_SEND,
.attributeID = ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID,
.attrType = ESP_ZB_ZCL_ATTR_TYPE_S16,
.min_interval = min_interval,
.max_interval = max_interval,
.reportable_change = (void *)&report_change,
},
};
report_cmd.record_number = ZB_ARRAY_LENGHT(records);
report_cmd.record_field = records;
log_i("Sending 'configure reporting' command to endpoint %d, address 0x%x", endpoint, short_addr);
esp_zb_lock_acquire(portMAX_DELAY);
esp_zb_zcl_config_report_cmd_req(&report_cmd);
esp_zb_lock_release();
}
void ZigbeeThermostat::setTemperatureReporting(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr, uint16_t min_interval, uint16_t max_interval, float delta) {
/* Send "configure report attribute" command to specific endpoint */
esp_zb_zcl_config_report_cmd_t report_cmd = {0};
report_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
report_cmd.zcl_basic_cmd.src_endpoint = _endpoint;
report_cmd.zcl_basic_cmd.dst_endpoint = endpoint;
report_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;
memcpy(report_cmd.zcl_basic_cmd.dst_addr_u.addr_long, ieee_addr, sizeof(esp_zb_ieee_addr_t));
int16_t report_change = (int16_t)delta * 100;
esp_zb_zcl_config_report_record_t records[] = {
{
.direction = ESP_ZB_ZCL_REPORT_DIRECTION_SEND,
.attributeID = ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID,
.attrType = ESP_ZB_ZCL_ATTR_TYPE_S16,
.min_interval = min_interval,
.max_interval = max_interval,
.reportable_change = (void *)&report_change,
},
};
report_cmd.record_number = ZB_ARRAY_LENGHT(records);
report_cmd.record_field = records;
log_i(
"Sending 'configure reporting' command to endpoint %d, ieee address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", endpoint, ieee_addr[7], ieee_addr[6],
ieee_addr[5], ieee_addr[4], ieee_addr[3], ieee_addr[2], ieee_addr[1], ieee_addr[0]
);
esp_zb_lock_acquire(portMAX_DELAY);
esp_zb_zcl_config_report_cmd_req(&report_cmd);
esp_zb_lock_release();
}
#endif // CONFIG_ZB_ENABLED

View file

@ -34,24 +34,39 @@ public:
ZigbeeThermostat(uint8_t endpoint);
~ZigbeeThermostat() {}
void onTempRecieve(void (*callback)(float)) {
_on_temp_recieve = callback;
void onTempReceive(void (*callback)(float)) {
_on_temp_receive = callback;
}
void onConfigRecieve(void (*callback)(float, float, float)) {
_on_config_recieve = callback;
void onTempReceiveWithSource(void (*callback)(float, uint8_t, esp_zb_zcl_addr_t)) {
_on_temp_receive_with_source = callback;
}
void onConfigReceive(void (*callback)(float, float, float)) {
_on_config_receive = callback;
}
void getTemperature();
void getTemperature(uint16_t group_addr);
void getTemperature(uint8_t endpoint, uint16_t short_addr);
void getTemperature(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr);
void getSensorSettings();
void getSensorSettings(uint16_t group_addr);
void getSensorSettings(uint8_t endpoint, uint16_t short_addr);
void getSensorSettings(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr);
void setTemperatureReporting(uint16_t min_interval, uint16_t max_interval, float delta);
void setTemperatureReporting(uint16_t group_addr, uint16_t min_interval, uint16_t max_interval, float delta);
void setTemperatureReporting(uint8_t endpoint, uint16_t short_addr, uint16_t min_interval, uint16_t max_interval, float delta);
void setTemperatureReporting(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr, uint16_t min_interval, uint16_t max_interval, float delta);
private:
// save instance of the class in order to use it in static functions
static ZigbeeThermostat *_instance;
zb_device_params_t *_device;
void (*_on_temp_recieve)(float);
void (*_on_config_recieve)(float, float, float);
void (*_on_temp_receive)(float);
void (*_on_temp_receive_with_source)(float, uint8_t, esp_zb_zcl_addr_t);
void (*_on_config_receive)(float, float, float);
float _min_temp;
float _max_temp;
float _tolerance;
@ -62,7 +77,7 @@ private:
static void bindCbWrapper(esp_zb_zdp_status_t zdo_status, void *user_ctx);
static void findCbWrapper(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx);
void zbAttributeRead(uint16_t cluster_id, const esp_zb_zcl_attribute_t *attribute) override;
void zbAttributeRead(uint16_t cluster_id, const esp_zb_zcl_attribute_t *attribute, uint8_t src_endpoint, esp_zb_zcl_addr_t src_address) override;
};
#endif // CONFIG_ZB_ENABLED