diff --git a/main/zh_gateway.c b/main/zh_gateway.c index c4fee9e..a4e12a6 100755 --- a/main/zh_gateway.c +++ b/main/zh_gateway.c @@ -287,10 +287,9 @@ void zh_espnow_event_handler(void *arg, esp_event_base_t event_base, int32_t eve case ZHPT_UPDATE: if (xSemaphoreTake(gateway_config->espnow_ota_in_progress_mutex, portTICK_PERIOD_MS) == pdTRUE) { - gateway_config->espnow_ota_data.chip_type = data.payload_data.espnow_ota_message.chip_type; gateway_config->espnow_ota_data.device_type = data.device_type; - memcpy(gateway_config->espnow_ota_data.app_name, &data.payload_data.espnow_ota_message.app_name, sizeof(data.payload_data.espnow_ota_message.app_name)); - memcpy(gateway_config->espnow_ota_data.app_version, &data.payload_data.espnow_ota_message.app_version, sizeof(data.payload_data.espnow_ota_message.app_version)); + memcpy(gateway_config->espnow_ota_data.app_name, data.payload_data.ota_message.espnow_ota_data.app_name, sizeof(data.payload_data.ota_message.espnow_ota_data.app_name)); + memcpy(gateway_config->espnow_ota_data.app_version, data.payload_data.ota_message.espnow_ota_data.app_version, sizeof(data.payload_data.ota_message.espnow_ota_data.app_version)); memcpy(gateway_config->espnow_ota_data.mac_addr, recv_data->mac_addr, 6); xTaskCreatePinnedToCore(&zh_espnow_ota_update_task, "NULL", ZH_OTA_STACK_SIZE, gateway_config, ZH_OTA_TASK_PRIORITY, NULL, tskNO_AFFINITY); xSemaphoreGive(gateway_config->espnow_ota_in_progress_mutex); @@ -358,19 +357,17 @@ void zh_mqtt_event_handler(void *arg, esp_event_base_t event_base, int32_t event { vTaskDelete(gateway_config->gateway_attributes_message_task); vTaskDelete(gateway_config->gateway_keep_alive_message_task); - zh_keep_alive_message_t keep_alive_message = {0}; - keep_alive_message.online_status = ZH_OFFLINE; zh_espnow_data_t data = {0}; data.device_type = ZHDT_GATEWAY; data.payload_type = ZHPT_KEEP_ALIVE; - data.payload_data = (zh_payload_data_t)keep_alive_message; + data.payload_data.keep_alive_message.online_status = ZH_OFFLINE; zh_send_message(NULL, (uint8_t *)&data, sizeof(zh_espnow_data_t)); } gateway_config->mqtt_is_connected = false; break; case MQTT_EVENT_DATA: char incoming_topic[(event->topic_len) + 1]; - memset(&incoming_topic, 0, sizeof(incoming_topic)); + memset(incoming_topic, 0, sizeof(incoming_topic)); strncat(incoming_topic, event->topic, event->topic_len); uint8_t incoming_data_mac[6] = {0}; zh_device_type_t incoming_data_device_type = ZHDT_NONE; @@ -412,16 +409,10 @@ void zh_mqtt_event_handler(void *arg, esp_event_base_t event_base, int32_t event } } char incoming_payload[(event->data_len) + 1]; - memset(&incoming_payload, 0, sizeof(incoming_payload)); + memset(incoming_payload, 0, sizeof(incoming_payload)); strncat(incoming_payload, event->data, event->data_len); zh_espnow_data_t data = {0}; data.device_type = ZHDT_GATEWAY; - zh_status_message_t status_message = {0}; - zh_switch_status_message_t switch_status_message = {0}; - zh_led_status_message_t led_status_message = {0}; - zh_config_message_t config_message = {0}; - zh_switch_hardware_config_message_t switch_hardware_config_message = {0}; - zh_sensor_hardware_config_message_t sensor_hardware_config_message = {0}; switch (incoming_data_device_type) { case ZHDT_GATEWAY: @@ -472,10 +463,8 @@ void zh_mqtt_event_handler(void *arg, esp_event_base_t event_base, int32_t event { if (strncmp(incoming_payload, zh_get_on_off_type_value_name(i), strlen(incoming_payload) + 1) == 0) { - switch_status_message.status = i; - status_message = (zh_status_message_t)switch_status_message; + data.payload_data.status_message.switch_status_message.status = i; data.payload_type = ZHPT_SET; - data.payload_data = (zh_payload_data_t)status_message; zh_send_message(incoming_data_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t)); break; } @@ -487,64 +476,62 @@ void zh_mqtt_event_handler(void *arg, esp_event_base_t event_base, int32_t event { break; } - switch_hardware_config_message.relay_pin = zh_gpio_number_check(atoi(extracted_hardware_data)); + data.payload_data.config_message.switch_hardware_config_message.relay_pin = zh_gpio_number_check(atoi(extracted_hardware_data)); extracted_hardware_data = strtok(NULL, ","); // Extract relay on level value. if (extracted_hardware_data == NULL) { break; } - switch_hardware_config_message.relay_on_level = zh_bool_value_check(atoi(extracted_hardware_data)); + data.payload_data.config_message.switch_hardware_config_message.relay_on_level = zh_bool_value_check(atoi(extracted_hardware_data)); extracted_hardware_data = strtok(NULL, ","); // Extract led gpio number value. if (extracted_hardware_data == NULL) { break; } - switch_hardware_config_message.led_pin = zh_gpio_number_check(atoi(extracted_hardware_data)); + data.payload_data.config_message.switch_hardware_config_message.led_pin = zh_gpio_number_check(atoi(extracted_hardware_data)); extracted_hardware_data = strtok(NULL, ","); // Extract led on level value. if (extracted_hardware_data == NULL) { break; } - switch_hardware_config_message.led_on_level = zh_bool_value_check(atoi(extracted_hardware_data)); + data.payload_data.config_message.switch_hardware_config_message.led_on_level = zh_bool_value_check(atoi(extracted_hardware_data)); extracted_hardware_data = strtok(NULL, ","); // Extract internal button GPIO number value. if (extracted_hardware_data == NULL) { break; } - switch_hardware_config_message.int_button_pin = zh_gpio_number_check(atoi(extracted_hardware_data)); + data.payload_data.config_message.switch_hardware_config_message.int_button_pin = zh_gpio_number_check(atoi(extracted_hardware_data)); extracted_hardware_data = strtok(NULL, ","); // Extract internal button on level value. if (extracted_hardware_data == NULL) { break; } - switch_hardware_config_message.int_button_on_level = zh_bool_value_check(atoi(extracted_hardware_data)); + data.payload_data.config_message.switch_hardware_config_message.int_button_on_level = zh_bool_value_check(atoi(extracted_hardware_data)); extracted_hardware_data = strtok(NULL, ","); // Extract external button GPIO number value. if (extracted_hardware_data == NULL) { break; } - switch_hardware_config_message.ext_button_pin = zh_gpio_number_check(atoi(extracted_hardware_data)); + data.payload_data.config_message.switch_hardware_config_message.ext_button_pin = zh_gpio_number_check(atoi(extracted_hardware_data)); extracted_hardware_data = strtok(NULL, ","); // Extract external button on level value. if (extracted_hardware_data == NULL) { break; } - switch_hardware_config_message.ext_button_on_level = zh_bool_value_check(atoi(extracted_hardware_data)); + data.payload_data.config_message.switch_hardware_config_message.ext_button_on_level = zh_bool_value_check(atoi(extracted_hardware_data)); extracted_hardware_data = strtok(NULL, ","); // Extract sensor GPIO number value. if (extracted_hardware_data == NULL) { break; } - switch_hardware_config_message.sensor_pin = zh_gpio_number_check(atoi(extracted_hardware_data)); + data.payload_data.config_message.switch_hardware_config_message.sensor_pin = zh_gpio_number_check(atoi(extracted_hardware_data)); extracted_hardware_data = strtok(NULL, ","); // Extract sensor type value. if (extracted_hardware_data == NULL) { break; } - switch_hardware_config_message.sensor_type = zh_sensor_type_check(atoi(extracted_hardware_data)); - config_message = (zh_config_message_t)switch_hardware_config_message; + data.payload_data.config_message.switch_hardware_config_message.sensor_type = zh_sensor_type_check(atoi(extracted_hardware_data)); data.payload_type = ZHPT_HARDWARE; - data.payload_data = (zh_payload_data_t)config_message; zh_send_message(incoming_data_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t)); break; default: @@ -575,27 +562,21 @@ void zh_mqtt_event_handler(void *arg, esp_event_base_t event_base, int32_t event { if (strncmp(incoming_payload, zh_get_on_off_type_value_name(i), strlen(incoming_payload) + 1) == 0) { - led_status_message.status = i; - status_message = (zh_status_message_t)led_status_message; + data.payload_data.status_message.led_status_message.status = i; data.payload_type = ZHPT_SET; - data.payload_data = (zh_payload_data_t)status_message; zh_send_message(incoming_data_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t)); break; } } break; case ZHPT_BRIGHTNESS: - led_status_message.brightness = atoi(incoming_payload); - status_message = (zh_status_message_t)led_status_message; + data.payload_data.status_message.led_status_message.brightness = atoi(incoming_payload); data.payload_type = ZHPT_BRIGHTNESS; - data.payload_data = (zh_payload_data_t)status_message; zh_send_message(incoming_data_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t)); break; case ZHPT_TEMPERATURE: - led_status_message.temperature = atoi(incoming_payload); - status_message = (zh_status_message_t)led_status_message; + data.payload_data.status_message.led_status_message.temperature = atoi(incoming_payload); data.payload_type = ZHPT_TEMPERATURE; - data.payload_data = (zh_payload_data_t)status_message; zh_send_message(incoming_data_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t)); break; case ZHPT_RGB: @@ -604,22 +585,20 @@ void zh_mqtt_event_handler(void *arg, esp_event_base_t event_base, int32_t event { break; } - led_status_message.red = atoi(extracted_rgb_data); + data.payload_data.status_message.led_status_message.red = atoi(extracted_rgb_data); extracted_rgb_data = strtok(NULL, ","); // Extract green value. if (extracted_rgb_data == NULL) { break; } - led_status_message.green = atoi(extracted_rgb_data); + data.payload_data.status_message.led_status_message.green = atoi(extracted_rgb_data); extracted_rgb_data = strtok(NULL, ","); // Extract blue value. if (extracted_rgb_data == NULL) { break; } - led_status_message.blue = atoi(extracted_rgb_data); - status_message = (zh_status_message_t)led_status_message; + data.payload_data.status_message.led_status_message.blue = atoi(extracted_rgb_data); data.payload_type = ZHPT_RGB; - data.payload_data = (zh_payload_data_t)status_message; zh_send_message(incoming_data_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t)); break; default: @@ -651,40 +630,38 @@ void zh_mqtt_event_handler(void *arg, esp_event_base_t event_base, int32_t event { break; } - sensor_hardware_config_message.sensor_type = zh_sensor_type_check(atoi(extracted_hardware_data)); + data.payload_data.config_message.sensor_hardware_config_message.sensor_type = zh_sensor_type_check(atoi(extracted_hardware_data)); extracted_hardware_data = strtok(NULL, ","); // Extract sensor GPIO number 1 value. if (extracted_hardware_data == NULL) { break; } - sensor_hardware_config_message.sensor_pin_1 = zh_gpio_number_check(atoi(extracted_hardware_data)); + data.payload_data.config_message.sensor_hardware_config_message.sensor_pin_1 = zh_gpio_number_check(atoi(extracted_hardware_data)); extracted_hardware_data = strtok(NULL, ","); // Extract sensor GPIO number 2 value. if (extracted_hardware_data == NULL) { break; } - sensor_hardware_config_message.sensor_pin_2 = zh_gpio_number_check(atoi(extracted_hardware_data)); + data.payload_data.config_message.sensor_hardware_config_message.sensor_pin_2 = zh_gpio_number_check(atoi(extracted_hardware_data)); extracted_hardware_data = strtok(NULL, ","); // Extract sensor power control GPIO number value. if (extracted_hardware_data == NULL) { break; } - sensor_hardware_config_message.power_pin = zh_gpio_number_check(atoi(extracted_hardware_data)); + data.payload_data.config_message.sensor_hardware_config_message.power_pin = zh_gpio_number_check(atoi(extracted_hardware_data)); extracted_hardware_data = strtok(NULL, ","); // Extract sensor measurement frequency value. if (extracted_hardware_data == NULL) { break; } - sensor_hardware_config_message.measurement_frequency = zh_uint16_value_check(atoi(extracted_hardware_data)); + data.payload_data.config_message.sensor_hardware_config_message.measurement_frequency = zh_uint16_value_check(atoi(extracted_hardware_data)); extracted_hardware_data = strtok(NULL, ","); // Extract power mode. if (extracted_hardware_data == NULL) { break; } - sensor_hardware_config_message.battery_power = zh_bool_value_check(atoi(extracted_hardware_data)); - config_message = (zh_config_message_t)sensor_hardware_config_message; + data.payload_data.config_message.sensor_hardware_config_message.battery_power = zh_bool_value_check(atoi(extracted_hardware_data)); data.payload_type = ZHPT_HARDWARE; - data.payload_data = (zh_payload_data_t)config_message; zh_send_message(incoming_data_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t)); break; default: @@ -793,14 +770,13 @@ void zh_espnow_ota_update_task(void *pvParameter) { gateway_config_t *gateway_config = pvParameter; xSemaphoreTake(gateway_config->espnow_ota_in_progress_mutex, portMAX_DELAY); - zh_espnow_ota_message_t espnow_ota_message = {0}; zh_espnow_data_t data = {0}; data.device_type = ZHDT_GATEWAY; char *topic = (char *)heap_caps_malloc(strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(gateway_config->espnow_ota_data.device_type)) + 20, MALLOC_CAP_8BIT); memset(topic, 0, strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(gateway_config->espnow_ota_data.device_type)) + 20); sprintf(topic, "%s/%s/" MAC_STR, CONFIG_MQTT_TOPIC_PREFIX, zh_get_device_type_value_name(gateway_config->espnow_ota_data.device_type), MAC2STR(gateway_config->espnow_ota_data.mac_addr)); esp_mqtt_client_publish(gateway_config->mqtt_client, topic, "update_begin", 0, 2, true); - char espnow_ota_write_data[sizeof(espnow_ota_message.data) + 1] = {0}; + char espnow_ota_write_data[sizeof(data.payload_data.ota_message.espnow_ota_message.data) + 1] = {0}; char *app_name = (char *)heap_caps_malloc(strlen(CONFIG_FIRMWARE_UPGRADE_URL) + strlen(gateway_config->espnow_ota_data.app_name) + 6, MALLOC_CAP_8BIT); memset(app_name, 0, strlen(CONFIG_FIRMWARE_UPGRADE_URL) + strlen(gateway_config->espnow_ota_data.app_name) + 6); sprintf(app_name, "%s/%s.bin", CONFIG_FIRMWARE_UPGRADE_URL, gateway_config->espnow_ota_data.app_name); @@ -831,7 +807,7 @@ void zh_espnow_ota_update_task(void *pvParameter) esp_mqtt_client_publish(gateway_config->mqtt_client, topic, "update_progress", 0, 2, true); for (;;) { - int data_read_size = esp_http_client_read(https_client, espnow_ota_write_data, sizeof(espnow_ota_message.data)); + int data_read_size = esp_http_client_read(https_client, espnow_ota_write_data, sizeof(data.payload_data.ota_message.espnow_ota_message.data)); if (data_read_size < 0) { esp_http_client_close(https_client); @@ -843,11 +819,10 @@ void zh_espnow_ota_update_task(void *pvParameter) } else if (data_read_size > 0) { - espnow_ota_message.data_len = data_read_size; - ++espnow_ota_message.part; - memcpy(&espnow_ota_message.data, &espnow_ota_write_data, data_read_size); + data.payload_data.ota_message.espnow_ota_message.data_len = data_read_size; + ++data.payload_data.ota_message.espnow_ota_message.part; + memcpy(data.payload_data.ota_message.espnow_ota_message.data, espnow_ota_write_data, data_read_size); data.payload_type = ZHPT_UPDATE_PROGRESS; - data.payload_data = (zh_payload_data_t)espnow_ota_message; zh_send_message(gateway_config->espnow_ota_data.mac_addr, (uint8_t *)&data, sizeof(zh_espnow_data_t)); if (xSemaphoreTake(gateway_config->espnow_ota_data_semaphore, 10000 / portTICK_PERIOD_MS) != pdTRUE) { @@ -918,22 +893,20 @@ void zh_gateway_send_mqtt_json_attributes_message_task(void *pvParameter) { gateway_config_t *gateway_config = pvParameter; const esp_app_desc_t *app_info = esp_app_get_description(); - zh_attributes_message_t attributes_message = {0}; - attributes_message.chip_type = ZH_CHIP_TYPE; - strcpy(attributes_message.flash_size, CONFIG_ESPTOOLPY_FLASHSIZE); - attributes_message.cpu_frequency = CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ; - attributes_message.reset_reason = (uint8_t)esp_reset_reason(); - strcpy(attributes_message.app_name, app_info->project_name); - strcpy(attributes_message.app_version, app_info->version); zh_espnow_data_t data = {0}; data.device_type = ZHDT_GATEWAY; data.payload_type = ZHPT_ATTRIBUTES; + data.payload_data.attributes_message.chip_type = ZH_CHIP_TYPE; + strcpy(data.payload_data.attributes_message.flash_size, CONFIG_ESPTOOLPY_FLASHSIZE); + data.payload_data.attributes_message.cpu_frequency = CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ; + data.payload_data.attributes_message.reset_reason = (uint8_t)esp_reset_reason(); + strcpy(data.payload_data.attributes_message.app_name, app_info->project_name); + strcpy(data.payload_data.attributes_message.app_version, app_info->version); for (;;) { - attributes_message.heap_size = esp_get_free_heap_size(); - attributes_message.min_heap_size = esp_get_minimum_free_heap_size(); - attributes_message.uptime = esp_timer_get_time() / 1000000; - data.payload_data = (zh_payload_data_t)attributes_message; + data.payload_data.attributes_message.heap_size = esp_get_free_heap_size(); + data.payload_data.attributes_message.min_heap_size = esp_get_minimum_free_heap_size(); + data.payload_data.attributes_message.uptime = esp_timer_get_time() / 1000000; zh_espnow_send_mqtt_json_attributes_message(&data, gateway_config->self_mac, gateway_config); vTaskDelay(60000 / portTICK_PERIOD_MS); } @@ -942,44 +915,34 @@ void zh_gateway_send_mqtt_json_attributes_message_task(void *pvParameter) void zh_gateway_send_mqtt_json_config_message(const gateway_config_t *gateway_config) { - zh_binary_sensor_config_message_t binary_sensor_config_message = {0}; - binary_sensor_config_message.unique_id = 1; - binary_sensor_config_message.binary_sensor_device_class = HABSDC_CONNECTIVITY; - binary_sensor_config_message.payload_on = HAONOFT_CONNECT; - binary_sensor_config_message.payload_off = HAONOFT_NONE; - binary_sensor_config_message.expire_after = 30; - binary_sensor_config_message.enabled_by_default = true; - binary_sensor_config_message.force_update = true; - binary_sensor_config_message.qos = 2; - binary_sensor_config_message.retain = true; - zh_config_message_t config_message = {0}; - config_message = (zh_config_message_t)binary_sensor_config_message; zh_espnow_data_t data = {0}; data.device_type = ZHDT_GATEWAY; data.payload_type = ZHPT_CONFIG; - data.payload_data = (zh_payload_data_t)config_message; + data.payload_data.config_message.binary_sensor_config_message.unique_id = 1; + data.payload_data.config_message.binary_sensor_config_message.binary_sensor_device_class = HABSDC_CONNECTIVITY; + data.payload_data.config_message.binary_sensor_config_message.payload_on = HAONOFT_CONNECT; + data.payload_data.config_message.binary_sensor_config_message.payload_off = HAONOFT_NONE; + data.payload_data.config_message.binary_sensor_config_message.expire_after = 30; + data.payload_data.config_message.binary_sensor_config_message.enabled_by_default = true; + data.payload_data.config_message.binary_sensor_config_message.force_update = true; + data.payload_data.config_message.binary_sensor_config_message.qos = 2; + data.payload_data.config_message.binary_sensor_config_message.retain = true; zh_espnow_binary_sensor_send_mqtt_json_config_message(&data, gateway_config->self_mac, gateway_config); } void zh_gateway_send_mqtt_json_keep_alive_message_task(void *pvParameter) { gateway_config_t *gateway_config = pvParameter; - zh_keep_alive_message_t keep_alive_message = {0}; - keep_alive_message.online_status = ZH_ONLINE; - zh_binary_sensor_status_message_t binary_sensor_status_message = {0}; - binary_sensor_status_message.sensor_type = HAST_GATEWAY; - binary_sensor_status_message.connect = HAONOFT_CONNECT; - zh_status_message_t status_message = {0}; - status_message = (zh_status_message_t)binary_sensor_status_message; zh_espnow_data_t data = {0}; data.device_type = ZHDT_GATEWAY; + data.payload_data.keep_alive_message.online_status = ZH_ONLINE; + data.payload_data.status_message.binary_sensor_status_message.sensor_type = HAST_GATEWAY; + data.payload_data.status_message.binary_sensor_status_message.connect = HAONOFT_CONNECT; for (;;) { data.payload_type = ZHPT_KEEP_ALIVE; - data.payload_data = (zh_payload_data_t)keep_alive_message; zh_send_message(NULL, (uint8_t *)&data, sizeof(zh_espnow_data_t)); data.payload_type = ZHPT_STATE; - data.payload_data = (zh_payload_data_t)status_message; zh_espnow_binary_sensor_send_mqtt_json_status_message(&data, gateway_config->self_mac, gateway_config); vTaskDelay(10000 / portTICK_PERIOD_MS); } diff --git a/main/zh_gateway.h b/main/zh_gateway.h index 360b8a1..4285a82 100755 --- a/main/zh_gateway.h +++ b/main/zh_gateway.h @@ -60,17 +60,23 @@ typedef struct // Structure of data exchange between tasks, functions and event handlers. { - uint8_t self_mac[6]; // Gateway MAC address. @note Depends at WiFi operation mode. - bool sntp_is_enable; // SNTP client operation status flag. @note Used to control the SNTP functions when the network connection is established / lost. - bool mqtt_is_enable; // MQTT client operation status flag. @note Used to control the MQTT functions when the network connection is established / lost. - bool mqtt_is_connected; // MQTT broker connection status flag. @note Used to control the gateway system tasks when the MQTT connection is established / lost. - esp_timer_handle_t wifi_reconnect_timer; // Unique WiFi reconnection timer handle. @note Used when the number of attempts of unsuccessful connections is exceeded. - uint8_t wifi_reconnect_retry_num; // System counter for the number of unsuccessful WiFi connection attempts. - esp_mqtt_client_handle_t mqtt_client; // Unique MQTT client handle. - TaskHandle_t gateway_attributes_message_task; // Unique task handle for zh_gateway_send_mqtt_json_attributes_message_task(). - TaskHandle_t gateway_keep_alive_message_task; // Unique task handle for zh_gateway_send_mqtt_json_keep_alive_message_task(). - TaskHandle_t gateway_current_time_task; // Unique task handle for zh_send_espnow_current_time_task(). - zh_espnow_ota_data_t espnow_ota_data; // Structure for initial transfer system data to the node update task. + uint8_t self_mac[6]; // Gateway MAC address. @note Depends at WiFi operation mode. + bool sntp_is_enable; // SNTP client operation status flag. @note Used to control the SNTP functions when the network connection is established / lost. + bool mqtt_is_enable; // MQTT client operation status flag. @note Used to control the MQTT functions when the network connection is established / lost. + bool mqtt_is_connected; // MQTT broker connection status flag. @note Used to control the gateway system tasks when the MQTT connection is established / lost. + esp_timer_handle_t wifi_reconnect_timer; // Unique WiFi reconnection timer handle. @note Used when the number of attempts of unsuccessful connections is exceeded. + uint8_t wifi_reconnect_retry_num; // System counter for the number of unsuccessful WiFi connection attempts. + esp_mqtt_client_handle_t mqtt_client; // Unique MQTT client handle. + TaskHandle_t gateway_attributes_message_task; // Unique task handle for zh_gateway_send_mqtt_json_attributes_message_task(). + TaskHandle_t gateway_keep_alive_message_task; // Unique task handle for zh_gateway_send_mqtt_json_keep_alive_message_task(). + TaskHandle_t gateway_current_time_task; // Unique task handle for zh_send_espnow_current_time_task(). + struct // Structure for initial transfer system data to the node update task. + { + zh_device_type_t device_type; // ESP-NOW device type. + char app_name[32]; // Firmware application name. + char app_version[32]; // Firmware application version. + uint8_t mac_addr[6]; // ESP-NOW node MAC address. + } espnow_ota_data; SemaphoreHandle_t espnow_ota_data_semaphore; // Semaphore for control the acknowledgement of successful receipt of an update package from a node. SemaphoreHandle_t self_ota_in_progress_mutex; // Mutex blocking the second run of the gateway update task. SemaphoreHandle_t espnow_ota_in_progress_mutex; // Mutex blocking the second run of the node update task.