@@ -19,6 +19,9 @@ ZigbeeEP::ZigbeeEP(uint8_t endpoint) {
19
19
_ep_config.endpoint = 0 ;
20
20
_cluster_list = nullptr ;
21
21
_on_identify = nullptr ;
22
+ _read_model = nullptr ; // Explicitly initialize here
23
+ _read_manufacturer = nullptr ; // Explicitly initialize here
24
+
22
25
_time_status = 0 ;
23
26
if (!lock) {
24
27
lock = xSemaphoreCreateBinary ();
@@ -33,43 +36,51 @@ void ZigbeeEP::setVersion(uint8_t version) {
33
36
}
34
37
35
38
bool ZigbeeEP::setManufacturerAndModel (const char *name, const char *model) {
36
- constexpr size_t ZB_MAX_NAME_LENGTH = 32 ;
39
+ constexpr size_t ZB_MAX_NAME_LENGTH = 32 ;
40
+
41
+ // Validate input lengths
42
+ size_t name_length = strlen (name);
43
+ size_t model_length = strlen (model);
44
+ if (name_length > ZB_MAX_NAME_LENGTH || model_length > ZB_MAX_NAME_LENGTH) {
45
+ log_e (" Manufacturer or model name is too long" );
46
+ return false ;
47
+ }
37
48
38
- // Convert manufacturer to ZCL string
39
- size_t name_length = strlen (name);
40
- size_t model_length = strlen (model );
41
- if (name_length > ZB_MAX_NAME_LENGTH || model_length > ZB_MAX_NAME_LENGTH) {
42
- log_e ( " Manufacturer or model name is too long " );
43
- return false ;
44
- }
45
- // Allocate an array of size length + 2 (1 for the length, 1 for null terminator)
46
- char zb_name[ZB_MAX_NAME_LENGTH + 2 ];
47
- char zb_model[ZB_MAX_NAME_LENGTH + 2 ];
48
- // Store the length as the first element
49
- zb_name[ 0 ] = static_cast < char >(name_length); // Cast size_t to char
50
- zb_model[0 ] = static_cast < char >(model_length) ;
51
- // Use memcpy to copy the characters to the result array
52
- memcpy (zb_name + 1 , name, name_length);
53
- memcpy (zb_model + 1 , model, model_length);
54
- // Null-terminate the array
55
- zb_name[name_length + 1 ] = ' \0 ' ;
56
- zb_model[model_length + 1 ] = ' \0 ' ;
57
-
58
- // Get the basic cluster and update the manufacturer and model attributes
59
- esp_zb_attribute_list_t *basic_cluster = esp_zb_cluster_list_get_cluster (_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_BASIC, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
60
- if (basic_cluster == nullptr ) {
61
- log_e ( " Failed to get basic cluster " );
62
- return false ;
63
- }
64
- esp_err_t ret_name = esp_zb_basic_cluster_add_attr (basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID, ( void *)zb_name);
65
- if (ret_name != ESP_OK) {
66
- log_e ( " Failed to set manufacturer: 0x%x: %s " , ret_name, esp_err_to_name (ret_name));
67
- }
68
- esp_err_t ret_model = esp_zb_basic_cluster_add_attr (basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID, ( void *)zb_model);
69
- if (ret_model != ESP_OK) {
70
- log_e ( " Failed to set model: 0x%x: %s " , ret_model, esp_err_to_name (ret_model));
71
- }
72
- return ret_name == ESP_OK && ret_model == ESP_OK;
49
+ // Use std::vector<char> for dynamic memory management - free() is for free when out of scope
50
+ std::vector< char > zb_name (name_length + 2 ); // +2 for length byte and null terminator
51
+ std::vector< char > zb_model (model_length + 2 );
52
+
53
+ // Convert manufacturer to ZCL string
54
+ zb_name[ 0 ] = static_cast < char >(name_length); // Store the length as the first element
55
+ memcpy (zb_name. data () + 1 , name, name_length);
56
+ zb_name[name_length + 1 ] = ' \0 ' ; // Null-terminate the array
57
+
58
+ // Convert model to ZCL string
59
+ zb_model[ 0 ] = static_cast < char >(model_length);
60
+ memcpy (zb_model. data () + 1 , model, model_length);
61
+ zb_model[model_length + 1 ] = ' \0 ' ;
62
+
63
+ // Get the basic cluster and update the manufacturer and model attributes
64
+ esp_zb_attribute_list_t *basic_cluster = esp_zb_cluster_list_get_cluster (
65
+ _cluster_list, ESP_ZB_ZCL_CLUSTER_ID_BASIC, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
66
+ if (!basic_cluster) {
67
+ log_e ( " Failed to get basic cluster " ) ;
68
+ return false ;
69
+ }
70
+
71
+ esp_err_t ret_name = esp_zb_basic_cluster_add_attr (
72
+ basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID, zb_name. data () );
73
+ if (ret_name != ESP_OK) {
74
+ log_e ( " Failed to set manufacturer: 0x%x: %s " , ret_name, esp_err_to_name (ret_name));
75
+ }
76
+
77
+ esp_err_t ret_model = esp_zb_basic_cluster_add_attr (
78
+ basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID, zb_model. data ());
79
+ if (ret_model != ESP_OK) {
80
+ log_e ( " Failed to set model: 0x%x: %s " , ret_model, esp_err_to_name (ret_model));
81
+ }
82
+
83
+ return ret_name == ESP_OK && ret_model == ESP_OK;
73
84
}
74
85
75
86
bool ZigbeeEP::setPowerSource (zb_power_source_t power_source, uint8_t battery_percentage) {
@@ -146,79 +157,77 @@ bool ZigbeeEP::reportBatteryPercentage() {
146
157
}
147
158
148
159
char *ZigbeeEP::readManufacturer (uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_addr) {
149
- /* Read peer Manufacture Name & Model Identifier */
150
- esp_zb_zcl_read_attr_cmd_t read_req;
151
-
152
- if (short_addr != 0 ) {
153
- read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
154
- read_req.zcl_basic_cmd .dst_addr_u .addr_short = short_addr;
155
- } else {
156
- read_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
157
- memcpy (read_req.zcl_basic_cmd .dst_addr_u .addr_long , ieee_addr, sizeof (esp_zb_ieee_addr_t ));
158
- }
160
+ /* Read peer Manufacturer Name */
161
+ esp_zb_zcl_read_attr_cmd_t read_req;
162
+
163
+ if (short_addr != 0 ) {
164
+ read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
165
+ read_req.zcl_basic_cmd .dst_addr_u .addr_short = short_addr;
166
+ } else {
167
+ read_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
168
+ memcpy (read_req.zcl_basic_cmd .dst_addr_u .addr_long , ieee_addr, sizeof (esp_zb_ieee_addr_t ));
169
+ }
159
170
160
- read_req.zcl_basic_cmd .src_endpoint = _endpoint;
161
- read_req.zcl_basic_cmd .dst_endpoint = endpoint;
162
- read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_BASIC;
171
+ read_req.zcl_basic_cmd .src_endpoint = _endpoint;
172
+ read_req.zcl_basic_cmd .dst_endpoint = endpoint;
173
+ read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_BASIC;
163
174
164
- uint16_t attributes[] = {
165
- ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID,
166
- };
167
- read_req.attr_number = ZB_ARRAY_LENTH (attributes);
168
- read_req.attr_field = attributes;
175
+ uint16_t attributes[] = {
176
+ ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID,
177
+ };
178
+ read_req.attr_number = ZB_ARRAY_LENTH (attributes);
179
+ read_req.attr_field = attributes;
169
180
170
- if (_read_manufacturer != nullptr ) {
181
+ // Free previously allocated memory for _read_manufacturer
171
182
free (_read_manufacturer);
172
- }
173
- _read_manufacturer = nullptr ;
183
+ _read_manufacturer = nullptr ;
174
184
175
- esp_zb_lock_acquire (portMAX_DELAY);
176
- esp_zb_zcl_read_attr_cmd_req (&read_req);
177
- esp_zb_lock_release ();
185
+ esp_zb_lock_acquire (portMAX_DELAY);
186
+ esp_zb_zcl_read_attr_cmd_req (&read_req);
187
+ esp_zb_lock_release ();
178
188
179
- // Wait for response or timeout
180
- if (xSemaphoreTake (lock, ZB_CMD_TIMEOUT) != pdTRUE) {
181
- log_e (" Error while reading manufacturer" );
182
- }
183
- return _read_manufacturer;
189
+ // Wait for response or timeout
190
+ if (xSemaphoreTake (lock, ZB_CMD_TIMEOUT) != pdTRUE) {
191
+ log_e (" Error while reading manufacturer" );
192
+ }
193
+ return _read_manufacturer;
184
194
}
185
195
186
196
char *ZigbeeEP::readModel (uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_addr) {
187
- /* Read peer Manufacture Name & Model Identifier */
188
- esp_zb_zcl_read_attr_cmd_t read_req;
197
+ /* Read peer Model Identifier */
198
+ esp_zb_zcl_read_attr_cmd_t read_req;
199
+
200
+ if (short_addr != 0 ) {
201
+ read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
202
+ read_req.zcl_basic_cmd .dst_addr_u .addr_short = short_addr;
203
+ } else {
204
+ read_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
205
+ memcpy (read_req.zcl_basic_cmd .dst_addr_u .addr_long , ieee_addr, sizeof (esp_zb_ieee_addr_t ));
206
+ }
189
207
190
- if (short_addr != 0 ) {
191
- read_req.address_mode = ESP_ZB_APS_ADDR_MODE_16_ENDP_PRESENT;
192
- read_req.zcl_basic_cmd .dst_addr_u .addr_short = short_addr;
193
- } else {
194
- read_req.address_mode = ESP_ZB_APS_ADDR_MODE_64_ENDP_PRESENT;
195
- memcpy (read_req.zcl_basic_cmd .dst_addr_u .addr_long , ieee_addr, sizeof (esp_zb_ieee_addr_t ));
196
- }
208
+ read_req.zcl_basic_cmd .src_endpoint = _endpoint;
209
+ read_req.zcl_basic_cmd .dst_endpoint = endpoint;
210
+ read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_BASIC;
197
211
198
- read_req.zcl_basic_cmd .src_endpoint = _endpoint;
199
- read_req.zcl_basic_cmd .dst_endpoint = endpoint;
200
- read_req.clusterID = ESP_ZB_ZCL_CLUSTER_ID_BASIC;
212
+ uint16_t attributes[] = {
213
+ ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID,
214
+ };
215
+ read_req.attr_number = ZB_ARRAY_LENTH (attributes);
216
+ read_req.attr_field = attributes;
201
217
202
- uint16_t attributes[] = {
203
- ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID,
204
- };
205
- read_req.attr_number = ZB_ARRAY_LENTH (attributes);
206
- read_req.attr_field = attributes;
207
-
208
- if (_read_model != nullptr ) {
218
+ // Free previously allocated memory for _read_model
209
219
free (_read_model);
210
- }
211
- _read_model = nullptr ;
220
+ _read_model = nullptr ;
212
221
213
- esp_zb_lock_acquire (portMAX_DELAY);
214
- esp_zb_zcl_read_attr_cmd_req (&read_req);
215
- esp_zb_lock_release ();
222
+ esp_zb_lock_acquire (portMAX_DELAY);
223
+ esp_zb_zcl_read_attr_cmd_req (&read_req);
224
+ esp_zb_lock_release ();
216
225
217
- // Wait for response or timeout
218
- if (xSemaphoreTake (lock, ZB_CMD_TIMEOUT) != pdTRUE) {
219
- log_e (" Error while reading model" );
220
- }
221
- return _read_model;
226
+ // Wait for response or timeout
227
+ if (xSemaphoreTake (lock, ZB_CMD_TIMEOUT) != pdTRUE) {
228
+ log_e (" Error while reading model" );
229
+ }
230
+ return _read_model;
222
231
}
223
232
224
233
void ZigbeeEP::printBoundDevices () {
@@ -246,25 +255,44 @@ void ZigbeeEP::printBoundDevices(Print &print) {
246
255
}
247
256
248
257
void ZigbeeEP::zbReadBasicCluster (const esp_zb_zcl_attribute_t *attribute) {
249
- /* Basic cluster attributes */
250
- if (attribute->id == ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID && attribute->data .type == ESP_ZB_ZCL_ATTR_TYPE_CHAR_STRING && attribute->data .value ) {
251
- zbstring_t *zbstr = (zbstring_t *)attribute->data .value ;
252
- char string[zbstr->len + 1 ];
253
- memcpy (string, zbstr->data , zbstr->len );
254
- string[zbstr->len ] = ' \0 ' ;
255
- log_i (" Peer Manufacturer is \" %s\" " , string);
256
- _read_manufacturer = string;
257
- xSemaphoreGive (lock);
258
- }
259
- if (attribute->id == ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID && attribute->data .type == ESP_ZB_ZCL_ATTR_TYPE_CHAR_STRING && attribute->data .value ) {
260
- zbstring_t *zbstr = (zbstring_t *)attribute->data .value ;
261
- char string[zbstr->len + 1 ];
262
- memcpy (string, zbstr->data , zbstr->len );
263
- string[zbstr->len ] = ' \0 ' ;
264
- log_i (" Peer Model is \" %s\" " , string);
265
- _read_model = string;
266
- xSemaphoreGive (lock);
267
- }
258
+ /* Basic cluster attributes */
259
+ if (attribute->id == ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID &&
260
+ attribute->data .type == ESP_ZB_ZCL_ATTR_TYPE_CHAR_STRING &&
261
+ attribute->data .value ) {
262
+ zbstring_t *zbstr = (zbstring_t *)attribute->data .value ;
263
+
264
+ // Use std::vector<char> for automatic memory management
265
+ std::vector<char > string (zbstr->len + 1 ); // Allocate space for the string and null terminator
266
+ memcpy (string.data (), zbstr->data , zbstr->len );
267
+ string[zbstr->len ] = ' \0 ' ; // Null-terminate the string
268
+
269
+ log_i (" Peer Manufacturer is \" %s\" " , string.data ());
270
+
271
+ // Update _read_manufacturer with a dynamically allocated copy
272
+ free (_read_manufacturer); // Free any previously allocated memory
273
+ _read_manufacturer = strdup (string.data ()); // Duplicate the string for persistent storage
274
+
275
+ xSemaphoreGive (lock);
276
+ }
277
+
278
+ if (attribute->id == ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID &&
279
+ attribute->data .type == ESP_ZB_ZCL_ATTR_TYPE_CHAR_STRING &&
280
+ attribute->data .value ) {
281
+ zbstring_t *zbstr = (zbstring_t *)attribute->data .value ;
282
+
283
+ // Use std::vector<char> for automatic memory management
284
+ std::vector<char > string (zbstr->len + 1 ); // Allocate space for the string and null terminator
285
+ memcpy (string.data (), zbstr->data , zbstr->len );
286
+ string[zbstr->len ] = ' \0 ' ; // Null-terminate the string
287
+
288
+ log_i (" Peer Model is \" %s\" " , string.data ());
289
+
290
+ // Update _read_model with a dynamically allocated copy
291
+ free (_read_model); // Free any previously allocated memory
292
+ _read_model = strdup (string.data ()); // Duplicate the string for persistent storage
293
+
294
+ xSemaphoreGive (lock);
295
+ }
268
296
}
269
297
270
298
void ZigbeeEP::zbIdentify (const esp_zb_zcl_set_attr_value_message_t *message) {
0 commit comments