zh_gateway/main/zh_gateway.c

1594 lines
86 KiB
C
Raw Normal View History

2024-06-04 18:59:55 +03:00
#include "zh_gateway.h"
gateway_config_t gateway_main_config = {0};
void app_main(void)
{
gateway_config_t *gateway_config = &gateway_main_config;
nvs_flash_init();
esp_netif_init();
esp_event_loop_create_default();
#ifdef CONFIG_CONNECTION_TYPE_LAN
gpio_config_t config = {0};
config.intr_type = GPIO_INTR_DISABLE;
config.mode = GPIO_MODE_OUTPUT;
config.pin_bit_mask = (1ULL << ZH_LAN_MODULE_POWER_PIN);
config.pull_down_en = GPIO_PULLDOWN_DISABLE;
config.pull_up_en = GPIO_PULLUP_DISABLE;
gpio_config(&config);
gpio_set_level(ZH_LAN_MODULE_POWER_PIN, 1);
esp_netif_config_t esp_netif_config = ESP_NETIF_DEFAULT_ETH();
esp_netif_t *esp_netif_eth = esp_netif_new(&esp_netif_config);
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config);
esp_eth_phy_t *phy = ZH_LAN_MODULE_TYPE(&phy_config);
esp_eth_config_t esp_eth_config = ETH_DEFAULT_CONFIG(mac, phy);
esp_eth_handle_t esp_eth_handle = NULL;
esp_eth_driver_install(&esp_eth_config, &esp_eth_handle);
esp_netif_attach(esp_netif_eth, esp_eth_new_netif_glue(esp_eth_handle));
esp_event_handler_instance_register(ETH_EVENT, ESP_EVENT_ANY_ID, &zh_eth_event_handler, gateway_config, NULL);
esp_event_handler_instance_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &zh_eth_event_handler, gateway_config, NULL);
esp_eth_start(esp_eth_handle);
wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT();
esp_wifi_init(&wifi_init_config);
esp_wifi_set_mode(WIFI_MODE_STA);
esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_11B);
esp_wifi_start();
esp_read_mac(gateway_config->self_mac, ESP_MAC_WIFI_STA);
#else
esp_netif_create_default_wifi_sta();
wifi_init_config_t wifi_init_sta_config = WIFI_INIT_CONFIG_DEFAULT();
esp_wifi_init(&wifi_init_sta_config);
wifi_config_t wifi_config = {
.sta = {
.ssid = CONFIG_WIFI_SSID_NAME,
.password = CONFIG_WIFI_PASSWORD,
},
};
esp_wifi_set_mode(WIFI_MODE_APSTA);
esp_wifi_set_protocol(WIFI_IF_AP, WIFI_PROTOCOL_11B);
esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &zh_wifi_event_handler, gateway_config, NULL);
esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &zh_wifi_event_handler, gateway_config, NULL);
esp_wifi_start();
esp_read_mac(gateway_config->self_mac, ESP_MAC_WIFI_SOFTAP);
#endif
#ifdef CONFIG_NETWORK_TYPE_DIRECT
zh_espnow_init_config_t zh_espnow_init_config = ZH_ESPNOW_INIT_CONFIG_DEFAULT();
zh_espnow_init_config.queue_size = 128;
#ifdef CONFIG_CONNECTION_TYPE_WIFI
zh_espnow_init_config.wifi_interface = WIFI_IF_AP;
#endif
zh_espnow_init(&zh_espnow_init_config);
esp_event_handler_instance_register(ZH_EVENT, ESP_EVENT_ANY_ID, &zh_espnow_event_handler, gateway_config, NULL);
#else
zh_network_init_config_t zh_network_init_config = ZH_NETWORK_INIT_CONFIG_DEFAULT();
zh_network_init_config.queue_size = 128;
#ifdef CONFIG_CONNECTION_TYPE_WIFI
zh_network_init_config.wifi_interface = WIFI_IF_AP;
#endif
zh_network_init(&zh_network_init_config);
esp_event_handler_instance_register(ZH_EVENT, ESP_EVENT_ANY_ID, &zh_espnow_event_handler, gateway_config, NULL);
#endif
gateway_config->espnow_ota_data_semaphore = xSemaphoreCreateBinary();
gateway_config->self_ota_in_progress_mutex = xSemaphoreCreateMutex();
gateway_config->espnow_ota_in_progress_mutex = xSemaphoreCreateMutex();
const esp_partition_t *running = esp_ota_get_running_partition();
esp_ota_img_states_t ota_state = {0};
esp_ota_get_state_partition(running, &ota_state);
if (ota_state == ESP_OTA_IMG_PENDING_VERIFY)
{
vTaskDelay(60000 / portTICK_PERIOD_MS);
esp_ota_mark_app_valid_cancel_rollback();
}
}
#ifdef CONFIG_CONNECTION_TYPE_LAN
void zh_eth_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
{
gateway_config_t *gateway_config = arg;
switch (event_id)
{
case ETHERNET_EVENT_DISCONNECTED:
if (gateway_config->mqtt_is_enable == true)
{
esp_mqtt_client_stop(gateway_config->mqtt_client);
gateway_config->mqtt_is_enable = false;
}
if (gateway_config->sntp_is_enable == true)
{
esp_sntp_stop();
gateway_config->sntp_is_enable = false;
vTaskDelete(gateway_config->gateway_current_time_task);
}
break;
case IP_EVENT_ETH_GOT_IP:
if (gateway_config->mqtt_is_enable == false)
{
esp_mqtt_client_config_t mqtt_config = {
.broker.address.uri = CONFIG_MQTT_BROKER_URL,
.buffer.size = 2048,
};
gateway_config->mqtt_client = esp_mqtt_client_init(&mqtt_config);
esp_mqtt_client_register_event(gateway_config->mqtt_client, ESP_EVENT_ANY_ID, zh_mqtt_event_handler, gateway_config);
esp_mqtt_client_start(gateway_config->mqtt_client);
gateway_config->mqtt_is_enable = true;
}
if (gateway_config->sntp_is_enable == false)
{
esp_sntp_setoperatingmode(SNTP_OPMODE_POLL);
sntp_set_sync_mode(SNTP_SYNC_MODE_SMOOTH);
esp_sntp_setservername(0, CONFIG_NTP_SERVER_URL);
esp_sntp_init();
gateway_config->sntp_is_enable = true;
xTaskCreatePinnedToCore(&zh_send_espnow_current_time_task, "NULL", ZH_SNTP_STACK_SIZE, gateway_config, ZH_SNTP_TASK_PRIORITY, (TaskHandle_t *)&gateway_config->gateway_current_time_task, tskNO_AFFINITY);
}
break;
default:
break;
}
}
#endif
#ifdef CONFIG_CONNECTION_TYPE_WIFI
void zh_wifi_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
{
gateway_config_t *gateway_config = arg;
switch (event_id)
{
case WIFI_EVENT_STA_START:
esp_wifi_connect();
break;
case WIFI_EVENT_STA_DISCONNECTED:
if (gateway_config->mqtt_is_enable == true)
{
esp_mqtt_client_stop(gateway_config->mqtt_client);
gateway_config->mqtt_is_enable = false;
}
if (gateway_config->sntp_is_enable == true)
{
esp_sntp_stop();
gateway_config->sntp_is_enable = false;
vTaskDelete(gateway_config->gateway_current_time_task);
}
if (gateway_config->wifi_reconnect_retry_num < ZH_WIFI_MAXIMUM_RETRY)
{
esp_wifi_connect();
++gateway_config->wifi_reconnect_retry_num;
}
else
{
gateway_config->wifi_reconnect_retry_num = 0;
esp_timer_create_args_t wifi_reconnect_timer_args = {
.callback = (void *)esp_wifi_connect};
esp_timer_create(&wifi_reconnect_timer_args, &gateway_config->wifi_reconnect_timer);
esp_timer_start_once(gateway_config->wifi_reconnect_timer, ZH_WIFI_RECONNECT_TIME * 1000);
}
break;
case IP_EVENT_STA_GOT_IP:
gateway_config->wifi_reconnect_retry_num = 0;
if (gateway_config->mqtt_is_enable == false)
{
esp_mqtt_client_config_t mqtt_config = {
.broker.address.uri = CONFIG_MQTT_BROKER_URL,
.buffer.size = 2048,
};
gateway_config->mqtt_client = esp_mqtt_client_init(&mqtt_config);
esp_mqtt_client_register_event(gateway_config->mqtt_client, ESP_EVENT_ANY_ID, zh_mqtt_event_handler, gateway_config);
esp_mqtt_client_start(gateway_config->mqtt_client);
gateway_config->mqtt_is_enable = true;
}
if (gateway_config->sntp_is_enable == false)
{
esp_sntp_setoperatingmode(SNTP_OPMODE_POLL);
sntp_set_sync_mode(SNTP_SYNC_MODE_SMOOTH);
esp_sntp_setservername(0, CONFIG_NTP_SERVER_URL);
esp_sntp_init();
gateway_config->sntp_is_enable = true;
xTaskCreatePinnedToCore(&zh_send_espnow_current_time_task, "NULL", ZH_SNTP_STACK_SIZE, gateway_config, ZH_SNTP_TASK_PRIORITY, (TaskHandle_t *)&gateway_config->gateway_current_time_task, tskNO_AFFINITY);
}
break;
default:
break;
}
}
#endif
void zh_espnow_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
{
gateway_config_t *gateway_config = arg;
switch (event_id)
{
#ifdef CONFIG_NETWORK_TYPE_DIRECT
case ZH_ESPNOW_ON_RECV_EVENT:
zh_espnow_event_on_recv_t *recv_data = event_data;
if (recv_data->data_len != sizeof(zh_espnow_data_t))
{
goto ZH_ESPNOW_EVENT_HANDLER_EXIT;
}
#else
case ZH_NETWORK_ON_RECV_EVENT:
zh_network_event_on_recv_t *recv_data = event_data;
if (recv_data->data_len != sizeof(zh_espnow_data_t))
{
goto ZH_NETWORK_EVENT_HANDLER_EXIT;
}
#endif
zh_espnow_data_t data = {0};
memcpy(&data, recv_data->data, recv_data->data_len);
char *topic = (char *)heap_caps_malloc(strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(data.device_type)) + 20, MALLOC_CAP_8BIT);
memset(topic, 0, strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(data.device_type)) + 20);
sprintf(topic, "%s/%s/" MAC_STR, CONFIG_MQTT_TOPIC_PREFIX, zh_get_device_type_value_name(data.device_type), MAC2STR(recv_data->mac_addr));
switch (data.payload_type)
{
case ZHPT_ATTRIBUTES:
zh_espnow_send_mqtt_json_attributes_message(&data, recv_data->mac_addr, gateway_config);
break;
case ZHPT_KEEP_ALIVE:
zh_espnow_send_mqtt_json_keep_alive_message(&data, recv_data->mac_addr, gateway_config);
break;
case ZHPT_CONFIG:
switch (data.device_type)
{
case ZHDT_SWITCH:
zh_espnow_switch_send_mqtt_json_config_message(&data, recv_data->mac_addr, gateway_config);
break;
case ZHDT_LED:
zh_espnow_led_send_mqtt_json_config_message(&data, recv_data->mac_addr, gateway_config);
break;
case ZHDT_SENSOR:
zh_espnow_sensor_send_mqtt_json_config_message(&data, recv_data->mac_addr, gateway_config);
break;
case ZHDT_BINARY_SENSOR:
zh_espnow_binary_sensor_send_mqtt_json_config_message(&data, recv_data->mac_addr, gateway_config);
break;
default:
break;
}
break;
case ZHPT_HARDWARE:
switch (data.device_type)
{
case ZHDT_SWITCH:
zh_espnow_switch_send_mqtt_json_hardware_config_message(&data, recv_data->mac_addr, gateway_config);
break;
case ZHDT_LED:
break;
case ZHDT_SENSOR:
zh_espnow_sensor_send_mqtt_json_hardware_config_message(&data, recv_data->mac_addr, gateway_config);
break;
case ZHDT_BINARY_SENSOR:
break;
default:
break;
}
break;
case ZHPT_STATE:
switch (data.device_type)
{
case ZHDT_SWITCH:
zh_espnow_switch_send_mqtt_json_status_message(&data, recv_data->mac_addr, gateway_config);
break;
case ZHDT_LED:
zh_espnow_led_send_mqtt_json_status_message(&data, recv_data->mac_addr, gateway_config);
break;
case ZHDT_SENSOR:
zh_espnow_sensor_send_mqtt_json_status_message(&data, recv_data->mac_addr, gateway_config);
break;
case ZHDT_BINARY_SENSOR:
zh_espnow_binary_sensor_send_mqtt_json_status_message(&data, recv_data->mac_addr, gateway_config);
break;
default:
break;
}
break;
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.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);
}
break;
case ZHPT_UPDATE_PROGRESS:
xSemaphoreGive(gateway_config->espnow_ota_data_semaphore);
break;
case ZHPT_UPDATE_FAIL:
esp_mqtt_client_publish(gateway_config->mqtt_client, topic, "update_fail", 0, 2, true);
break;
case ZHPT_UPDATE_SUCCESS:
esp_mqtt_client_publish(gateway_config->mqtt_client, topic, "update_success", 0, 2, true);
break;
default:
break;
}
heap_caps_free(topic);
#ifdef CONFIG_NETWORK_TYPE_DIRECT
ZH_ESPNOW_EVENT_HANDLER_EXIT:
heap_caps_free(recv_data->data);
break;
case ZH_ESPNOW_ON_SEND_EVENT:
break;
#else
ZH_NETWORK_EVENT_HANDLER_EXIT:
heap_caps_free(recv_data->data);
break;
case ZH_NETWORK_ON_SEND_EVENT:
break;
#endif
default:
break;
}
}
void zh_mqtt_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
{
gateway_config_t *gateway_config = arg;
esp_mqtt_event_handle_t event = event_data;
switch (event_id)
{
case MQTT_EVENT_CONNECTED:
if (gateway_config->mqtt_is_connected == false)
{
char *topic_for_subscribe = NULL;
char *supported_device_type = NULL;
for (zh_device_type_t i = 1; i <= ZHDT_MAX; ++i)
{
supported_device_type = zh_get_device_type_value_name(i);
topic_for_subscribe = (char *)heap_caps_malloc(strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(supported_device_type) + 4, MALLOC_CAP_8BIT);
memset(topic_for_subscribe, 0, strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(supported_device_type) + 4);
sprintf(topic_for_subscribe, "%s/%s/#", CONFIG_MQTT_TOPIC_PREFIX, supported_device_type);
esp_mqtt_client_subscribe(gateway_config->mqtt_client, topic_for_subscribe, 2);
heap_caps_free(topic_for_subscribe);
}
zh_gateway_send_mqtt_json_config_message(gateway_config);
xTaskCreatePinnedToCore(&zh_gateway_send_mqtt_json_attributes_message_task, "NULL", ZH_MESSAGE_STACK_SIZE, gateway_config, ZH_MESSAGE_TASK_PRIORITY, (TaskHandle_t *)&gateway_config->gateway_attributes_message_task, tskNO_AFFINITY);
xTaskCreatePinnedToCore(&zh_gateway_send_mqtt_json_keep_alive_message_task, "NULL", ZH_MESSAGE_STACK_SIZE, gateway_config, ZH_MESSAGE_TASK_PRIORITY, (TaskHandle_t *)&gateway_config->gateway_keep_alive_message_task, tskNO_AFFINITY);
}
gateway_config->mqtt_is_connected = true;
break;
case MQTT_EVENT_DISCONNECTED:
if (gateway_config->mqtt_is_connected == true)
{
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;
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));
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;
zh_payload_type_t incoming_data_payload_type = ZHPT_NONE;
char *extracted_topic_data = strtok(incoming_topic, "/"); // Extract topic prefix.
if (extracted_topic_data == NULL)
{
break;
}
extracted_topic_data = strtok(NULL, "/"); // Extract device type.
if (extracted_topic_data == NULL)
{
break;
}
for (zh_device_type_t i = 1; i < ZHDT_MAX; ++i)
{
if (strncmp(extracted_topic_data, zh_get_device_type_value_name(i), strlen(extracted_topic_data) + 1) == 0)
{
incoming_data_device_type = i;
break;
}
}
extracted_topic_data = strtok(NULL, "/"); // Extract MAC address.
if (extracted_topic_data == NULL)
{
break;
}
sscanf(extracted_topic_data, "%hhX-%hhX-%hhX-%hhX-%hhX-%hhX", &incoming_data_mac[0], &incoming_data_mac[1], &incoming_data_mac[2], &incoming_data_mac[3], &incoming_data_mac[4], &incoming_data_mac[5]);
extracted_topic_data = strtok(NULL, "/"); // Extract payload type.
if (extracted_topic_data != NULL)
{
for (zh_payload_type_t i = 1; i < ZHPT_MAX; ++i)
{
if (strncmp(extracted_topic_data, zh_get_payload_type_value_name(i), strlen(extracted_topic_data) + 1) == 0)
{
incoming_data_payload_type = i;
break;
}
}
}
char incoming_payload[(event->data_len) + 1];
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:
if (incoming_data_payload_type == ZHPT_NONE)
{
if (memcmp(&gateway_config->self_mac, &incoming_data_mac, 6) == 0)
{
if (strncmp(incoming_payload, "update", strlen(incoming_payload) + 1) == 0)
{
if (xSemaphoreTake(gateway_config->self_ota_in_progress_mutex, portTICK_PERIOD_MS) == pdTRUE)
{
xTaskCreatePinnedToCore(&zh_self_ota_update_task, "NULL", ZH_OTA_STACK_SIZE, gateway_config, ZH_OTA_TASK_PRIORITY, NULL, tskNO_AFFINITY);
xSemaphoreGive(gateway_config->self_ota_in_progress_mutex);
}
}
else if (strncmp(incoming_payload, "restart", strlen(incoming_payload) + 1) == 0)
{
esp_restart();
}
else
{
break;
}
}
}
break;
case ZHDT_SWITCH:
switch (incoming_data_payload_type)
{
case ZHPT_NONE:
if (strncmp(incoming_payload, "update", strlen(incoming_payload) + 1) == 0)
{
data.payload_type = ZHPT_UPDATE;
zh_send_message(incoming_data_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t));
}
else if (strncmp(incoming_payload, "restart", strlen(incoming_payload) + 1) == 0)
{
data.payload_type = ZHPT_RESTART;
zh_send_message(incoming_data_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t));
}
else
{
break;
}
break;
case ZHPT_SET:
for (ha_on_off_type_t i = 1; i < HAONOFT_MAX; ++i)
{
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_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_HARDWARE:
char *extracted_hardware_data = strtok(incoming_payload, ","); // Extract relay gpio number value.
if (extracted_hardware_data == NULL)
{
break;
}
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));
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));
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));
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));
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));
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));
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));
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));
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_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:
break;
}
break;
case ZHDT_LED:
switch (incoming_data_payload_type)
{
case ZHPT_NONE:
if (strncmp(incoming_payload, "update", strlen(incoming_payload) + 1) == 0)
{
data.payload_type = ZHPT_UPDATE;
zh_send_message(incoming_data_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t));
}
else if (strncmp(incoming_payload, "restart", strlen(incoming_payload) + 1) == 0)
{
data.payload_type = ZHPT_RESTART;
zh_send_message(incoming_data_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t));
}
else
{
break;
}
break;
case ZHPT_SET:
for (ha_on_off_type_t i = 1; i < HAONOFT_MAX; ++i)
{
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_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_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_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:
char *extracted_rgb_data = strtok(incoming_payload, ","); // Extract red value.
if (extracted_rgb_data == NULL)
{
break;
}
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);
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_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:
break;
}
break;
case ZHDT_SENSOR:
switch (incoming_data_payload_type)
{
case ZHPT_NONE:
if (strncmp(incoming_payload, "update", strlen(incoming_payload) + 1) == 0)
{
data.payload_type = ZHPT_UPDATE;
zh_send_message(incoming_data_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t));
}
else if (strncmp(incoming_payload, "restart", strlen(incoming_payload) + 1) == 0)
{
data.payload_type = ZHPT_RESTART;
zh_send_message(incoming_data_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t));
}
else
{
break;
}
break;
case ZHPT_HARDWARE:
char *extracted_hardware_data = strtok(incoming_payload, ","); // Extract sensor type value.
if (extracted_hardware_data == NULL)
{
break;
}
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));
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));
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));
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));
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_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:
break;
}
break;
case ZHDT_BINARY_SENSOR:
switch (incoming_data_payload_type)
{
case ZHPT_NONE:
if (strncmp(incoming_payload, "update", strlen(incoming_payload) + 1) == 0)
{
data.payload_type = ZHPT_UPDATE;
zh_send_message(incoming_data_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t));
}
else if (strncmp(incoming_payload, "restart", strlen(incoming_payload) + 1) == 0)
{
data.payload_type = ZHPT_RESTART;
zh_send_message(incoming_data_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t));
}
else
{
break;
}
break;
default:
break;
}
break;
default:
break;
}
break;
}
}
void zh_self_ota_update_task(void *pvParameter)
{
gateway_config_t *gateway_config = pvParameter;
xSemaphoreTake(gateway_config->self_ota_in_progress_mutex, portMAX_DELAY);
char *topic = (char *)heap_caps_malloc(strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(ZHDT_GATEWAY)) + 20, MALLOC_CAP_8BIT);
memset(topic, 0, strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(ZHDT_GATEWAY)) + 20);
sprintf(topic, "%s/%s/" MAC_STR, CONFIG_MQTT_TOPIC_PREFIX, zh_get_device_type_value_name(ZHDT_GATEWAY), MAC2STR(gateway_config->self_mac));
char self_ota_write_data[1025] = {0};
esp_ota_handle_t update_handle = {0};
const esp_partition_t *update_partition = NULL;
esp_mqtt_client_publish(gateway_config->mqtt_client, topic, "update_begin", 0, 2, true);
const esp_app_desc_t *app_info = esp_app_get_description();
char *app_name = (char *)heap_caps_malloc(strlen(CONFIG_FIRMWARE_UPGRADE_URL) + strlen(app_info->project_name) + 6, MALLOC_CAP_8BIT);
memset(app_name, 0, strlen(CONFIG_FIRMWARE_UPGRADE_URL) + strlen(app_info->project_name) + 6);
sprintf(app_name, "%s/%s.bin", CONFIG_FIRMWARE_UPGRADE_URL, app_info->project_name);
esp_http_client_config_t config = {
.url = app_name,
.cert_pem = (char *)server_certificate_pem_start,
.timeout_ms = 5000,
.keep_alive_enable = true,
.skip_cert_common_name_check = true,
};
esp_http_client_handle_t https_client = esp_http_client_init(&config);
heap_caps_free(app_name);
esp_http_client_open(https_client, 0);
esp_http_client_fetch_headers(https_client);
update_partition = esp_ota_get_next_update_partition(NULL);
esp_mqtt_client_publish(gateway_config->mqtt_client, topic, "update_progress", 0, 2, true);
esp_ota_begin(update_partition, OTA_WITH_SEQUENTIAL_WRITES, &update_handle);
for (;;)
{
int data_read_size = esp_http_client_read(https_client, self_ota_write_data, 1024);
if (data_read_size < 0)
{
esp_http_client_close(https_client);
esp_http_client_cleanup(https_client);
esp_mqtt_client_publish(gateway_config->mqtt_client, topic, "update_error_data_size", 0, 2, true);
heap_caps_free(topic);
xSemaphoreGive(gateway_config->self_ota_in_progress_mutex);
vTaskDelete(NULL);
}
else if (data_read_size > 0)
{
esp_ota_write(update_handle, (const void *)self_ota_write_data, data_read_size);
}
else
{
break;
}
}
if (esp_ota_end(update_handle) != ESP_OK)
{
esp_http_client_close(https_client);
esp_http_client_cleanup(https_client);
esp_mqtt_client_publish(gateway_config->mqtt_client, topic, "update_fail", 0, 2, true);
heap_caps_free(topic);
xSemaphoreGive(gateway_config->self_ota_in_progress_mutex);
vTaskDelete(NULL);
}
esp_ota_set_boot_partition(update_partition);
esp_http_client_close(https_client);
esp_http_client_cleanup(https_client);
esp_mqtt_client_publish(gateway_config->mqtt_client, topic, "update_success", 0, 2, true);
heap_caps_free(topic);
vTaskDelay(1000 / portTICK_PERIOD_MS);
esp_restart();
}
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 *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);
esp_http_client_config_t config = {
.url = app_name,
.cert_pem = (char *)server_certificate_pem_start,
.timeout_ms = 5000,
.keep_alive_enable = true,
.skip_cert_common_name_check = true,
};
esp_http_client_handle_t https_client = esp_http_client_init(&config);
heap_caps_free(app_name);
esp_http_client_open(https_client, 0);
esp_http_client_fetch_headers(https_client);
data.payload_type = ZHPT_UPDATE_BEGIN;
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, 30000 / portTICK_PERIOD_MS) != pdTRUE)
{
esp_http_client_close(https_client);
esp_http_client_cleanup(https_client);
data.payload_type = ZHPT_UPDATE_ERROR;
zh_send_message(gateway_config->espnow_ota_data.mac_addr, (uint8_t *)&data, sizeof(zh_espnow_data_t));
esp_mqtt_client_publish(gateway_config->mqtt_client, topic, "update_error_begin_timeout", 0, 2, true);
heap_caps_free(topic);
xSemaphoreGive(gateway_config->espnow_ota_in_progress_mutex);
vTaskDelete(NULL);
}
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));
if (data_read_size < 0)
{
esp_http_client_close(https_client);
esp_http_client_cleanup(https_client);
esp_mqtt_client_publish(gateway_config->mqtt_client, topic, "update_error_data_size", 0, 2, true);
heap_caps_free(topic);
xSemaphoreGive(gateway_config->espnow_ota_in_progress_mutex);
vTaskDelete(NULL);
}
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_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)
{
esp_http_client_close(https_client);
esp_http_client_cleanup(https_client);
data.payload_type = ZHPT_UPDATE_ERROR;
zh_send_message(gateway_config->espnow_ota_data.mac_addr, (uint8_t *)&data, sizeof(zh_espnow_data_t));
esp_mqtt_client_publish(gateway_config->mqtt_client, topic, "update_error_progress_timeout", 0, 2, true);
heap_caps_free(topic);
xSemaphoreGive(gateway_config->espnow_ota_in_progress_mutex);
vTaskDelete(NULL);
}
}
else
{
esp_http_client_close(https_client);
esp_http_client_cleanup(https_client);
data.payload_type = ZHPT_UPDATE_END;
zh_send_message(gateway_config->espnow_ota_data.mac_addr, (uint8_t *)&data, sizeof(zh_espnow_data_t));
esp_mqtt_client_publish(gateway_config->mqtt_client, topic, "update_end", 0, 2, true);
heap_caps_free(topic);
xSemaphoreGive(gateway_config->espnow_ota_in_progress_mutex);
vTaskDelete(NULL);
}
}
}
void zh_send_espnow_current_time_task(void *pvParameter)
{
// gateway_config_t *gateway_config = pvParameter;
while (sntp_get_sync_status() != SNTP_SYNC_STATUS_COMPLETED)
{
vTaskDelay(5000 / portTICK_PERIOD_MS);
}
time_t now;
setenv("TZ", CONFIG_NTP_TIME_ZONE, 1);
tzset();
for (;;)
{
time(&now);
// To Do.
vTaskDelay(86400000 / portTICK_PERIOD_MS);
}
vTaskDelete(NULL);
}
uint8_t zh_gpio_number_check(int gpio)
{
return (gpio >= 0 && gpio <= ZH_MAX_GPIO_NUMBERS) ? gpio : ZH_NOT_USED;
}
bool zh_bool_value_check(int value)
{
return (value == 0) ? false : true;
}
uint8_t zh_sensor_type_check(int type)
{
return (type > HAST_NONE && type < HAST_MAX) ? type : HAST_NONE;
}
uint16_t zh_uint16_value_check(int value)
{
return (value >= 0 && value <= 65536) ? value : 60;
}
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;
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;
zh_espnow_send_mqtt_json_attributes_message(&data, gateway_config->self_mac, gateway_config);
vTaskDelay(60000 / portTICK_PERIOD_MS);
}
vTaskDelete(NULL);
}
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;
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;
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);
}
vTaskDelete(NULL);
}
void zh_espnow_send_mqtt_json_attributes_message(zh_espnow_data_t *device_data, const uint8_t *device_mac, const gateway_config_t *gateway_config)
{
uint32_t secs = device_data->payload_data.attributes_message.uptime;
uint32_t mins = secs / 60;
uint32_t hours = mins / 60;
uint32_t days = hours / 24;
char *mac = (char *)heap_caps_malloc(18, MALLOC_CAP_8BIT);
memset(mac, 0, 18);
sprintf(mac, "" MAC_STR "", MAC2STR(device_mac));
char *uptime = (char *)heap_caps_malloc(44, MALLOC_CAP_8BIT);
memset(uptime, 0, 44);
sprintf(uptime, "Days:%lu Hours:%lu Mins:%lu", days, hours - (days * 24), mins - (hours * 60));
char *cpu_frequency = heap_caps_malloc(4, MALLOC_CAP_8BIT);
memset(cpu_frequency, 0, 4);
sprintf(cpu_frequency, "%d", device_data->payload_data.attributes_message.cpu_frequency);
char *heap_size = heap_caps_malloc(7, MALLOC_CAP_8BIT);
memset(heap_size, 0, 7);
sprintf(heap_size, "%lu", device_data->payload_data.attributes_message.heap_size);
char *min_heap_size = heap_caps_malloc(7, MALLOC_CAP_8BIT);
memset(min_heap_size, 0, 7);
sprintf(min_heap_size, "%lu", device_data->payload_data.attributes_message.min_heap_size);
char *reset_reason = heap_caps_malloc(4, MALLOC_CAP_8BIT);
memset(reset_reason, 0, 4);
sprintf(reset_reason, "%d", device_data->payload_data.attributes_message.reset_reason);
zh_json_t json = {0};
char buffer[512] = {0};
zh_json_init(&json);
zh_json_add(&json, "Type", zh_get_device_type_value_name(device_data->device_type));
zh_json_add(&json, "MAC", mac);
zh_json_add(&json, "Chip", zh_get_chip_type_value_name(device_data->payload_data.attributes_message.chip_type));
if (device_data->payload_data.attributes_message.sensor_type != 0)
{
zh_json_add(&json, "Sensor", zh_get_sensor_type_value_name(device_data->payload_data.attributes_message.sensor_type));
}
zh_json_add(&json, "CPU frequency", cpu_frequency);
zh_json_add(&json, "Flash size", device_data->payload_data.attributes_message.flash_size);
zh_json_add(&json, "Current heap size", heap_size);
zh_json_add(&json, "Minimum heap size", min_heap_size);
zh_json_add(&json, "Last reset reason", reset_reason);
zh_json_add(&json, "App name", device_data->payload_data.attributes_message.app_name);
zh_json_add(&json, "App version", device_data->payload_data.attributes_message.app_version);
zh_json_add(&json, "Uptime", uptime);
zh_json_create(&json, buffer);
zh_json_free(&json);
char *topic = (char *)heap_caps_malloc(strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 31, MALLOC_CAP_8BIT);
memset(topic, 0, strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 31);
sprintf(topic, "%s/%s/" MAC_STR "/attributes", CONFIG_MQTT_TOPIC_PREFIX, zh_get_device_type_value_name(device_data->device_type), MAC2STR(device_mac));
esp_mqtt_client_publish(gateway_config->mqtt_client, topic, buffer, 0, 2, true);
heap_caps_free(mac);
heap_caps_free(uptime);
heap_caps_free(cpu_frequency);
heap_caps_free(heap_size);
heap_caps_free(min_heap_size);
heap_caps_free(reset_reason);
heap_caps_free(topic);
}
void zh_espnow_send_mqtt_json_keep_alive_message(const zh_espnow_data_t *device_data, const uint8_t *device_mac, const gateway_config_t *gateway_config)
{
char *status = (device_data->payload_data.keep_alive_message.online_status == ZH_ONLINE) ? "online" : "offline";
char *topic = (char *)heap_caps_malloc(strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 27, MALLOC_CAP_8BIT);
memset(topic, 0, strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 27);
sprintf(topic, "%s/%s/" MAC_STR "/status", CONFIG_MQTT_TOPIC_PREFIX, zh_get_device_type_value_name(device_data->device_type), MAC2STR(device_mac));
esp_mqtt_client_publish(gateway_config->mqtt_client, topic, status, 0, 2, true);
heap_caps_free(topic);
}
void zh_espnow_switch_send_mqtt_json_config_message(const zh_espnow_data_t *device_data, const uint8_t *device_mac, const gateway_config_t *gateway_config)
{
char *name = (char *)heap_caps_malloc(strlen(zh_get_device_type_value_name(device_data->device_type)) + 19, MALLOC_CAP_8BIT);
memset(name, 0, strlen(zh_get_device_type_value_name(device_data->device_type)) + 19);
sprintf(name, "%s " MAC_STR "", zh_get_device_type_value_name(device_data->device_type), MAC2STR(device_mac));
char *unique_id = (char *)heap_caps_malloc(22, MALLOC_CAP_8BIT);
memset(unique_id, 0, 22);
sprintf(unique_id, "" MAC_STR "-%d", MAC2STR(device_mac), device_data->payload_data.config_message.switch_config_message.unique_id);
char *state_topic = (char *)heap_caps_malloc(strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 26, MALLOC_CAP_8BIT);
memset(state_topic, 0, strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 26);
sprintf(state_topic, "%s/%s/" MAC_STR "/state", CONFIG_MQTT_TOPIC_PREFIX, zh_get_device_type_value_name(device_data->device_type), MAC2STR(device_mac));
char *availability_topic = (char *)heap_caps_malloc(strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 27, MALLOC_CAP_8BIT);
memset(availability_topic, 0, strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 27);
sprintf(availability_topic, "%s/%s/" MAC_STR "/status", CONFIG_MQTT_TOPIC_PREFIX, zh_get_device_type_value_name(device_data->device_type), MAC2STR(device_mac));
char *command_topic = (char *)heap_caps_malloc(strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 24, MALLOC_CAP_8BIT);
memset(command_topic, 0, strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 24);
sprintf(command_topic, "%s/%s/" MAC_STR "/set", CONFIG_MQTT_TOPIC_PREFIX, zh_get_device_type_value_name(device_data->device_type), MAC2STR(device_mac));
char *json_attributes_topic = (char *)heap_caps_malloc(strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 31, MALLOC_CAP_8BIT);
memset(json_attributes_topic, 0, strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 31);
sprintf(json_attributes_topic, "%s/%s/" MAC_STR "/attributes", CONFIG_MQTT_TOPIC_PREFIX, zh_get_device_type_value_name(device_data->device_type), MAC2STR(device_mac));
char *qos = (char *)heap_caps_malloc(4, MALLOC_CAP_8BIT);
memset(qos, 0, 4);
sprintf(qos, "%d", device_data->payload_data.config_message.switch_config_message.qos);
zh_json_t json = {0};
char buffer[512] = {0};
zh_json_init(&json);
zh_json_add(&json, "platform", "mqtt");
zh_json_add(&json, "name", name);
zh_json_add(&json, "unique_id", unique_id);
zh_json_add(&json, "device_class", zh_get_switch_device_class_value_name(device_data->payload_data.config_message.switch_config_message.device_class));
zh_json_add(&json, "state_topic", state_topic);
zh_json_add(&json, "value_template", "{{ value_json.state }}");
zh_json_add(&json, "availability_topic", availability_topic);
zh_json_add(&json, "command_topic", command_topic);
zh_json_add(&json, "json_attributes_topic", json_attributes_topic);
zh_json_add(&json, "enabled_by_default", (device_data->payload_data.config_message.switch_config_message.enabled_by_default == true) ? "true" : "false");
zh_json_add(&json, "optimistic", (device_data->payload_data.config_message.switch_config_message.optimistic == true) ? "true" : "false");
zh_json_add(&json, "payload_on", zh_get_on_off_type_value_name(device_data->payload_data.config_message.switch_config_message.payload_on));
zh_json_add(&json, "payload_off", zh_get_on_off_type_value_name(device_data->payload_data.config_message.switch_config_message.payload_off));
zh_json_add(&json, "qos", qos);
zh_json_add(&json, "retain", (device_data->payload_data.config_message.switch_config_message.retain == true) ? "true" : "false");
zh_json_create(&json, buffer);
zh_json_free(&json);
char *topic = (char *)heap_caps_malloc(strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(unique_id) + 16, MALLOC_CAP_8BIT);
memset(topic, 0, strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(unique_id) + 16);
sprintf(topic, "%s/switch/%s/config", CONFIG_MQTT_TOPIC_PREFIX, unique_id);
esp_mqtt_client_publish(gateway_config->mqtt_client, topic, buffer, 0, 2, true);
heap_caps_free(name);
heap_caps_free(unique_id);
heap_caps_free(state_topic);
heap_caps_free(availability_topic);
heap_caps_free(command_topic);
heap_caps_free(json_attributes_topic);
heap_caps_free(qos);
heap_caps_free(topic);
}
void zh_espnow_switch_send_mqtt_json_hardware_config_message(const zh_espnow_data_t *device_data, const uint8_t *device_mac, const gateway_config_t *gateway_config)
{
char *relay_pin = (char *)heap_caps_malloc(4, MALLOC_CAP_8BIT);
memset(relay_pin, 0, 4);
char *led_pin = (char *)heap_caps_malloc(4, MALLOC_CAP_8BIT);
memset(led_pin, 0, 4);
char *int_button_pin = (char *)heap_caps_malloc(4, MALLOC_CAP_8BIT);
memset(int_button_pin, 0, 4);
char *ext_button_pin = (char *)heap_caps_malloc(4, MALLOC_CAP_8BIT);
memset(ext_button_pin, 0, 4);
char *sensor_pin = (char *)heap_caps_malloc(4, MALLOC_CAP_8BIT);
memset(sensor_pin, 0, 4);
zh_json_t json = {0};
char buffer[512] = {0};
zh_json_init(&json);
if (device_data->payload_data.config_message.switch_hardware_config_message.relay_pin == ZH_NOT_USED)
{
zh_json_add(&json, "Relay GPIO number", "Not used");
zh_json_add(&json, "Relay ON level", "Not used");
}
else
{
sprintf(relay_pin, "%d", device_data->payload_data.config_message.switch_hardware_config_message.relay_pin);
zh_json_add(&json, "Relay GPIO number", relay_pin);
zh_json_add(&json, "Relay ON level", (device_data->payload_data.config_message.switch_hardware_config_message.relay_on_level == ZH_LOW) ? "Low" : "High");
}
if (device_data->payload_data.config_message.switch_hardware_config_message.led_pin == ZH_NOT_USED)
{
zh_json_add(&json, "Led GPIO number", "Not used");
zh_json_add(&json, "Led ON level", "Not used");
}
else
{
sprintf(led_pin, "%d", device_data->payload_data.config_message.switch_hardware_config_message.led_pin);
zh_json_add(&json, "Led GPIO number", led_pin);
zh_json_add(&json, "Led ON level", (device_data->payload_data.config_message.switch_hardware_config_message.led_on_level == ZH_LOW) ? "Low" : "High");
}
if (device_data->payload_data.config_message.switch_hardware_config_message.int_button_pin == ZH_NOT_USED)
{
zh_json_add(&json, "Internal button GPIO number", "Not used");
zh_json_add(&json, "Internal button trigger level", "Not used");
}
else
{
sprintf(int_button_pin, "%d", device_data->payload_data.config_message.switch_hardware_config_message.int_button_pin);
zh_json_add(&json, "Internal button GPIO number", int_button_pin);
zh_json_add(&json, "Internal button trigger level", (device_data->payload_data.config_message.switch_hardware_config_message.int_button_on_level == ZH_LOW) ? "Low" : "High");
}
if (device_data->payload_data.config_message.switch_hardware_config_message.ext_button_pin == ZH_NOT_USED)
{
zh_json_add(&json, "External button GPIO number", "Not used");
zh_json_add(&json, "External button trigger level", "Not used");
}
else
{
sprintf(ext_button_pin, "%d", device_data->payload_data.config_message.switch_hardware_config_message.ext_button_pin);
zh_json_add(&json, "External button GPIO number", ext_button_pin);
zh_json_add(&json, "External button trigger level", (device_data->payload_data.config_message.switch_hardware_config_message.ext_button_on_level == ZH_LOW) ? "Low" : "High");
}
if (device_data->payload_data.config_message.switch_hardware_config_message.sensor_pin == ZH_NOT_USED)
{
zh_json_add(&json, "Sensor GPIO number", "Not used");
zh_json_add(&json, "Sensor type", "Not used");
}
else
{
sprintf(sensor_pin, "%d", device_data->payload_data.config_message.switch_hardware_config_message.sensor_pin);
zh_json_add(&json, "Sensor GPIO number", sensor_pin);
zh_json_add(&json, "Sensor type", zh_get_sensor_type_value_name(device_data->payload_data.config_message.switch_hardware_config_message.sensor_type));
}
zh_json_create(&json, buffer);
zh_json_free(&json);
char *topic = (char *)heap_caps_malloc(strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 27, MALLOC_CAP_8BIT);
memset(topic, 0, strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 27);
sprintf(topic, "%s/%s/" MAC_STR "/config", CONFIG_MQTT_TOPIC_PREFIX, zh_get_device_type_value_name(device_data->device_type), MAC2STR(device_mac));
esp_mqtt_client_publish(gateway_config->mqtt_client, topic, buffer, 0, 2, true);
heap_caps_free(relay_pin);
heap_caps_free(led_pin);
heap_caps_free(int_button_pin);
heap_caps_free(ext_button_pin);
heap_caps_free(sensor_pin);
heap_caps_free(topic);
}
void zh_espnow_switch_send_mqtt_json_status_message(const zh_espnow_data_t *device_data, const uint8_t *device_mac, const gateway_config_t *gateway_config)
{
zh_json_t json = {0};
char buffer[128] = {0};
zh_json_init(&json);
zh_json_add(&json, "state", zh_get_on_off_type_value_name(device_data->payload_data.status_message.switch_status_message.status));
zh_json_create(&json, buffer);
zh_json_free(&json);
char *topic = (char *)heap_caps_malloc(strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 26, MALLOC_CAP_8BIT);
memset(topic, 0, strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 26);
sprintf(topic, "%s/%s/" MAC_STR "/state", CONFIG_MQTT_TOPIC_PREFIX, zh_get_device_type_value_name(device_data->device_type), MAC2STR(device_mac));
esp_mqtt_client_publish(gateway_config->mqtt_client, topic, buffer, 0, 2, true);
heap_caps_free(topic);
}
void zh_espnow_led_send_mqtt_json_config_message(const zh_espnow_data_t *device_data, const uint8_t *device_mac, const gateway_config_t *gateway_config)
{
char *name = (char *)heap_caps_malloc(strlen(zh_get_device_type_value_name(device_data->device_type)) + 19, MALLOC_CAP_8BIT);
memset(name, 0, strlen(zh_get_device_type_value_name(device_data->device_type)) + 19);
sprintf(name, "%s " MAC_STR "", zh_get_device_type_value_name(device_data->device_type), MAC2STR(device_mac));
char *unique_id = (char *)heap_caps_malloc(22, MALLOC_CAP_8BIT);
memset(unique_id, 0, 22);
sprintf(unique_id, "" MAC_STR "-%d", MAC2STR(device_mac), device_data->payload_data.config_message.led_config_message.unique_id);
char *state_topic = (char *)heap_caps_malloc(strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 26, MALLOC_CAP_8BIT);
memset(state_topic, 0, strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 26);
sprintf(state_topic, "%s/%s/" MAC_STR "/state", CONFIG_MQTT_TOPIC_PREFIX, zh_get_device_type_value_name(device_data->device_type), MAC2STR(device_mac));
char *availability_topic = (char *)heap_caps_malloc(strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 27, MALLOC_CAP_8BIT);
memset(availability_topic, 0, strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 27);
sprintf(availability_topic, "%s/%s/" MAC_STR "/status", CONFIG_MQTT_TOPIC_PREFIX, zh_get_device_type_value_name(device_data->device_type), MAC2STR(device_mac));
char *command_topic = (char *)heap_caps_malloc(strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 24, MALLOC_CAP_8BIT);
memset(command_topic, 0, strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 24);
sprintf(command_topic, "%s/%s/" MAC_STR "/set", CONFIG_MQTT_TOPIC_PREFIX, zh_get_device_type_value_name(device_data->device_type), MAC2STR(device_mac));
char *json_attributes_topic = (char *)heap_caps_malloc(strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 31, MALLOC_CAP_8BIT);
memset(json_attributes_topic, 0, strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 31);
sprintf(json_attributes_topic, "%s/%s/" MAC_STR "/attributes", CONFIG_MQTT_TOPIC_PREFIX, zh_get_device_type_value_name(device_data->device_type), MAC2STR(device_mac));
char *qos = (char *)heap_caps_malloc(4, MALLOC_CAP_8BIT);
memset(qos, 0, 4);
sprintf(qos, "%d", device_data->payload_data.config_message.led_config_message.qos);
char *brightness_command_topic = (char *)heap_caps_malloc(strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 31, MALLOC_CAP_8BIT);
memset(brightness_command_topic, 0, strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 31);
sprintf(brightness_command_topic, "%s/%s/" MAC_STR "/brightness", CONFIG_MQTT_TOPIC_PREFIX, zh_get_device_type_value_name(device_data->device_type), MAC2STR(device_mac));
char *color_temp_command_topic = (char *)heap_caps_malloc(strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 32, MALLOC_CAP_8BIT);
memset(color_temp_command_topic, 0, strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 32);
sprintf(color_temp_command_topic, "%s/%s/" MAC_STR "/temperature", CONFIG_MQTT_TOPIC_PREFIX, zh_get_device_type_value_name(device_data->device_type), MAC2STR(device_mac));
char *rgb_command_topic = (char *)heap_caps_malloc(strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 24, MALLOC_CAP_8BIT);
memset(rgb_command_topic, 0, strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 24);
sprintf(rgb_command_topic, "%s/%s/" MAC_STR "/rgb", CONFIG_MQTT_TOPIC_PREFIX, zh_get_device_type_value_name(device_data->device_type), MAC2STR(device_mac));
zh_json_t json = {0};
char buffer[1024] = {0};
zh_json_init(&json);
zh_json_add(&json, "platform", "mqtt");
zh_json_add(&json, "name", name);
zh_json_add(&json, "unique_id", unique_id);
zh_json_add(&json, "state_topic", state_topic);
zh_json_add(&json, "state_value_template", "{{ value_json.state }}");
zh_json_add(&json, "availability_topic", availability_topic);
zh_json_add(&json, "command_topic", command_topic);
zh_json_add(&json, "json_attributes_topic", json_attributes_topic);
zh_json_add(&json, "enabled_by_default", (device_data->payload_data.config_message.led_config_message.enabled_by_default == true) ? "true" : "false");
zh_json_add(&json, "optimistic", (device_data->payload_data.config_message.led_config_message.optimistic == true) ? "true" : "false");
zh_json_add(&json, "payload_on", zh_get_on_off_type_value_name(device_data->payload_data.config_message.led_config_message.payload_on));
zh_json_add(&json, "payload_off", zh_get_on_off_type_value_name(device_data->payload_data.config_message.led_config_message.payload_off));
zh_json_add(&json, "qos", qos);
zh_json_add(&json, "retain", (device_data->payload_data.config_message.led_config_message.retain == true) ? "true" : "false");
zh_json_add(&json, "brightness_state_topic", state_topic);
zh_json_add(&json, "brightness_value_template", "{{ value_json.brightness }}");
zh_json_add(&json, "brightness_command_topic", brightness_command_topic);
if (device_data->payload_data.config_message.led_config_message.led_type == HALT_WW || device_data->payload_data.config_message.led_config_message.led_type == HALT_RGBWW)
{
zh_json_add(&json, "color_temp_state_topic", state_topic);
zh_json_add(&json, "color_temp_value_template", "{{ value_json.temperature }}");
zh_json_add(&json, "color_temp_command_topic", color_temp_command_topic);
}
if (device_data->payload_data.config_message.led_config_message.led_type == HALT_RGB || device_data->payload_data.config_message.led_config_message.led_type == HALT_RGBW || device_data->payload_data.config_message.led_config_message.led_type == HALT_RGBWW)
{
zh_json_add(&json, "rgb_state_topic", state_topic);
zh_json_add(&json, "rgb_value_template", "{{ value_json.rgb | join(',') }}");
zh_json_add(&json, "rgb_command_topic", rgb_command_topic);
}
zh_json_create(&json, buffer);
zh_json_free(&json);
char *topic = (char *)heap_caps_malloc(strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(unique_id) + 15, MALLOC_CAP_8BIT);
memset(topic, 0, strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(unique_id) + 15);
sprintf(topic, "%s/light/%s/config", CONFIG_MQTT_TOPIC_PREFIX, unique_id);
esp_mqtt_client_publish(gateway_config->mqtt_client, topic, buffer, 0, 2, true);
heap_caps_free(name);
heap_caps_free(unique_id);
heap_caps_free(state_topic);
heap_caps_free(availability_topic);
heap_caps_free(command_topic);
heap_caps_free(json_attributes_topic);
heap_caps_free(qos);
heap_caps_free(brightness_command_topic);
heap_caps_free(color_temp_command_topic);
heap_caps_free(rgb_command_topic);
heap_caps_free(topic);
}
void zh_espnow_led_send_mqtt_json_status_message(const zh_espnow_data_t *device_data, const uint8_t *device_mac, const gateway_config_t *gateway_config)
{
char *brightness = (char *)heap_caps_malloc(4, MALLOC_CAP_8BIT);
memset(brightness, 0, 4);
sprintf(brightness, "%d", device_data->payload_data.status_message.led_status_message.brightness);
char *temperature = (char *)heap_caps_malloc(6, MALLOC_CAP_8BIT);
memset(temperature, 0, 6);
sprintf(temperature, "%d", device_data->payload_data.status_message.led_status_message.temperature);
char *rgb = (char *)heap_caps_malloc(12, MALLOC_CAP_8BIT);
memset(rgb, 0, 12);
sprintf(rgb, "%d,%d,%d", device_data->payload_data.status_message.led_status_message.red, device_data->payload_data.status_message.led_status_message.green, device_data->payload_data.status_message.led_status_message.blue);
zh_json_t json = {0};
char buffer[128] = {0};
zh_json_init(&json);
zh_json_add(&json, "state", zh_get_on_off_type_value_name(device_data->payload_data.status_message.led_status_message.status));
zh_json_add(&json, "brightness", brightness);
zh_json_add(&json, "temperature", temperature);
zh_json_add(&json, "rgb", rgb);
zh_json_create(&json, buffer);
zh_json_free(&json);
char *topic = (char *)heap_caps_malloc(strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 26, MALLOC_CAP_8BIT);
memset(topic, 0, strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 26);
sprintf(topic, "%s/%s/" MAC_STR "/state", CONFIG_MQTT_TOPIC_PREFIX, zh_get_device_type_value_name(device_data->device_type), MAC2STR(device_mac));
esp_mqtt_client_publish(gateway_config->mqtt_client, topic, buffer, 0, 2, true);
heap_caps_free(topic);
}
void zh_espnow_sensor_send_mqtt_json_config_message(zh_espnow_data_t *device_data, const uint8_t *device_mac, const gateway_config_t *gateway_config)
{
char *name = (char *)heap_caps_malloc(strlen(zh_get_device_type_value_name(device_data->device_type)) + 19, MALLOC_CAP_8BIT);
memset(name, 0, strlen(zh_get_device_type_value_name(device_data->device_type)) + 19);
sprintf(name, "%s " MAC_STR "", zh_get_device_type_value_name(device_data->device_type), MAC2STR(device_mac));
char *unique_id = (char *)heap_caps_malloc(22, MALLOC_CAP_8BIT);
memset(unique_id, 0, 22);
sprintf(unique_id, "" MAC_STR "-%d", MAC2STR(device_mac), device_data->payload_data.config_message.sensor_config_message.unique_id);
char *state_topic = (char *)heap_caps_malloc(strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 26, MALLOC_CAP_8BIT);
memset(state_topic, 0, strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 26);
sprintf(state_topic, "%s/%s/" MAC_STR "/state", CONFIG_MQTT_TOPIC_PREFIX, zh_get_device_type_value_name(device_data->device_type), MAC2STR(device_mac));
char *value_template = (char *)heap_caps_malloc(strlen(zh_get_sensor_device_class_value_name(device_data->payload_data.config_message.sensor_config_message.sensor_device_class)) + 18, MALLOC_CAP_8BIT);
memset(value_template, 0, strlen(zh_get_sensor_device_class_value_name(device_data->payload_data.config_message.sensor_config_message.sensor_device_class)) + 18);
sprintf(value_template, "{{ value_json.%s }}", zh_get_sensor_device_class_value_name(device_data->payload_data.config_message.sensor_config_message.sensor_device_class));
char *json_attributes_topic = (char *)heap_caps_malloc(strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 31, MALLOC_CAP_8BIT);
memset(json_attributes_topic, 0, strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 31);
sprintf(json_attributes_topic, "%s/%s/" MAC_STR "/attributes", CONFIG_MQTT_TOPIC_PREFIX, zh_get_device_type_value_name(device_data->device_type), MAC2STR(device_mac));
char *qos = (char *)heap_caps_malloc(4, MALLOC_CAP_8BIT);
memset(qos, 0, 4);
sprintf(qos, "%d", device_data->payload_data.config_message.sensor_config_message.qos);
char *expire_after = (char *)heap_caps_malloc(6, MALLOC_CAP_8BIT);
memset(expire_after, 0, 6);
sprintf(expire_after, "%d", device_data->payload_data.config_message.sensor_config_message.expire_after);
char *suggested_display_precision = (char *)heap_caps_malloc(4, MALLOC_CAP_8BIT);
memset(suggested_display_precision, 0, 4);
sprintf(suggested_display_precision, "%d", device_data->payload_data.config_message.sensor_config_message.suggested_display_precision);
zh_json_t json = {0};
char buffer[512] = {0};
zh_json_init(&json);
zh_json_add(&json, "platform", "mqtt");
zh_json_add(&json, "name", name);
zh_json_add(&json, "unique_id", unique_id);
zh_json_add(&json, "device_class", zh_get_sensor_device_class_value_name(device_data->payload_data.config_message.sensor_config_message.sensor_device_class));
zh_json_add(&json, "state_topic", state_topic);
zh_json_add(&json, "value_template", value_template);
zh_json_add(&json, "json_attributes_topic", json_attributes_topic);
zh_json_add(&json, "enabled_by_default", (device_data->payload_data.config_message.sensor_config_message.enabled_by_default == true) ? "true" : "false");
zh_json_add(&json, "qos", qos);
zh_json_add(&json, "retain", (device_data->payload_data.config_message.sensor_config_message.retain == true) ? "true" : "false");
zh_json_add(&json, "expire_after", expire_after);
zh_json_add(&json, "force_update", (device_data->payload_data.config_message.sensor_config_message.force_update == true) ? "true" : "false");
zh_json_add(&json, "suggested_display_precision", suggested_display_precision);
zh_json_add(&json, "unit_of_measurement", device_data->payload_data.config_message.sensor_config_message.unit_of_measurement);
zh_json_create(&json, buffer);
zh_json_free(&json);
char *topic = (char *)heap_caps_malloc(strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(unique_id) + 16, MALLOC_CAP_8BIT);
memset(topic, 0, strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(unique_id) + 16);
sprintf(topic, "%s/sensor/%s/config", CONFIG_MQTT_TOPIC_PREFIX, unique_id);
esp_mqtt_client_publish(gateway_config->mqtt_client, topic, buffer, 0, 2, true);
heap_caps_free(name);
heap_caps_free(unique_id);
heap_caps_free(state_topic);
heap_caps_free(value_template);
heap_caps_free(json_attributes_topic);
heap_caps_free(qos);
heap_caps_free(expire_after);
heap_caps_free(suggested_display_precision);
heap_caps_free(topic);
}
void zh_espnow_sensor_send_mqtt_json_hardware_config_message(const zh_espnow_data_t *device_data, const uint8_t *device_mac, const gateway_config_t *gateway_config)
{
char *sensor_pin_1 = (char *)heap_caps_malloc(4, MALLOC_CAP_8BIT);
memset(sensor_pin_1, 0, 4);
char *sensor_pin_2 = (char *)heap_caps_malloc(4, MALLOC_CAP_8BIT);
memset(sensor_pin_2, 0, 4);
char *power_pin = (char *)heap_caps_malloc(4, MALLOC_CAP_8BIT);
memset(power_pin, 0, 4);
char *measurement_frequency = (char *)heap_caps_malloc(6, MALLOC_CAP_8BIT);
memset(measurement_frequency, 0, 6);
zh_json_t json = {0};
char buffer[512] = {0};
zh_json_init(&json);
if (device_data->payload_data.config_message.sensor_hardware_config_message.sensor_pin_1 == ZH_NOT_USED)
{
zh_json_add(&json, "Sensor type", "Not used");
}
else
{
zh_json_add(&json, "Sensor type", zh_get_sensor_type_value_name(device_data->payload_data.config_message.sensor_hardware_config_message.sensor_type));
}
if (device_data->payload_data.config_message.sensor_hardware_config_message.sensor_pin_1 == ZH_NOT_USED)
{
zh_json_add(&json, "Sensor GPIO number 1", "Not used");
}
else
{
sprintf(sensor_pin_1, "%d", device_data->payload_data.config_message.sensor_hardware_config_message.sensor_pin_1);
zh_json_add(&json, "Sensor GPIO number 1", sensor_pin_1);
}
if (device_data->payload_data.config_message.sensor_hardware_config_message.sensor_pin_2 == ZH_NOT_USED)
{
zh_json_add(&json, "Sensor GPIO number 2", "Not used");
}
else
{
if (device_data->payload_data.config_message.sensor_hardware_config_message.sensor_pin_1 == ZH_NOT_USED)
{
zh_json_add(&json, "Sensor GPIO number 2", "Not used");
}
else
{
sprintf(sensor_pin_2, "%d", device_data->payload_data.config_message.sensor_hardware_config_message.sensor_pin_2);
zh_json_add(&json, "Sensor GPIO number 2", sensor_pin_2);
}
}
if (device_data->payload_data.config_message.sensor_hardware_config_message.power_pin == ZH_NOT_USED)
{
zh_json_add(&json, "Sensor power control GPIO number", "Not used");
}
else
{
sprintf(power_pin, "%d", device_data->payload_data.config_message.sensor_hardware_config_message.power_pin);
zh_json_add(&json, "Sensor power control GPIO number", power_pin);
}
sprintf(measurement_frequency, "%d", device_data->payload_data.config_message.sensor_hardware_config_message.measurement_frequency);
zh_json_add(&json, "Measurement frequency", measurement_frequency);
zh_json_add(&json, "Power mode", (device_data->payload_data.config_message.sensor_hardware_config_message.battery_power == true) ? "Battery" : "External");
zh_json_create(&json, buffer);
zh_json_free(&json);
char *topic = (char *)heap_caps_malloc(strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 27, MALLOC_CAP_8BIT);
memset(topic, 0, strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 27);
sprintf(topic, "%s/%s/" MAC_STR "/config", CONFIG_MQTT_TOPIC_PREFIX, zh_get_device_type_value_name(device_data->device_type), MAC2STR(device_mac));
esp_mqtt_client_publish(gateway_config->mqtt_client, topic, buffer, 0, 2, true);
heap_caps_free(sensor_pin_1);
heap_caps_free(sensor_pin_2);
heap_caps_free(power_pin);
heap_caps_free(measurement_frequency);
heap_caps_free(topic);
}
void zh_espnow_sensor_send_mqtt_json_status_message(const zh_espnow_data_t *device_data, const uint8_t *device_mac, const gateway_config_t *gateway_config)
{
char *temperature = (char *)heap_caps_malloc(317, MALLOC_CAP_8BIT);
memset(temperature, 0, 317);
char *humidity = (char *)heap_caps_malloc(317, MALLOC_CAP_8BIT);
memset(humidity, 0, 317);
zh_json_t json = {0};
char buffer[512] = {0};
zh_json_init(&json);
switch (device_data->payload_data.status_message.sensor_status_message.sensor_type)
{
case HAST_DS18B20:
sprintf(temperature, "%f", device_data->payload_data.status_message.sensor_status_message.temperature);
zh_json_add(&json, "temperature", temperature);
break;
case HAST_DHT11:
sprintf(temperature, "%f", device_data->payload_data.status_message.sensor_status_message.temperature);
sprintf(humidity, "%f", device_data->payload_data.status_message.sensor_status_message.humidity);
zh_json_add(&json, "temperature", temperature);
zh_json_add(&json, "humidity", humidity);
break;
case HAST_DHT22:
sprintf(temperature, "%f", device_data->payload_data.status_message.sensor_status_message.temperature);
sprintf(humidity, "%f", device_data->payload_data.status_message.sensor_status_message.humidity);
zh_json_add(&json, "temperature", temperature);
zh_json_add(&json, "humidity", humidity);
break;
default:
break;
}
zh_json_create(&json, buffer);
zh_json_free(&json);
char *topic = (char *)heap_caps_malloc(strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 31, MALLOC_CAP_8BIT);
memset(topic, 0, strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 31);
sprintf(topic, "%s/%s/" MAC_STR "/state", CONFIG_MQTT_TOPIC_PREFIX, zh_get_device_type_value_name(device_data->device_type), MAC2STR(device_mac));
esp_mqtt_client_publish(gateway_config->mqtt_client, topic, buffer, 0, 2, true);
heap_caps_free(temperature);
heap_caps_free(humidity);
heap_caps_free(topic);
}
void zh_espnow_binary_sensor_send_mqtt_json_config_message(const zh_espnow_data_t *device_data, const uint8_t *device_mac, const gateway_config_t *gateway_config)
{
char *name = (char *)heap_caps_malloc(strlen(zh_get_device_type_value_name(device_data->device_type)) + 19, MALLOC_CAP_8BIT);
memset(name, 0, strlen(zh_get_device_type_value_name(device_data->device_type)) + 19);
sprintf(name, "%s " MAC_STR "", zh_get_device_type_value_name(device_data->device_type), MAC2STR(device_mac));
char *unique_id = (char *)heap_caps_malloc(22, MALLOC_CAP_8BIT);
memset(unique_id, 0, 22);
sprintf(unique_id, "" MAC_STR "-%d", MAC2STR(device_mac), device_data->payload_data.config_message.binary_sensor_config_message.unique_id);
char *state_topic = (char *)heap_caps_malloc(strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 26, MALLOC_CAP_8BIT);
memset(state_topic, 0, strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 26);
sprintf(state_topic, "%s/%s/" MAC_STR "/state", CONFIG_MQTT_TOPIC_PREFIX, zh_get_device_type_value_name(device_data->device_type), MAC2STR(device_mac));
char *value_template = (char *)heap_caps_malloc(strlen(zh_get_binary_sensor_device_class_value_name(device_data->payload_data.config_message.binary_sensor_config_message.binary_sensor_device_class)) + 18, MALLOC_CAP_8BIT);
memset(value_template, 0, strlen(zh_get_binary_sensor_device_class_value_name(device_data->payload_data.config_message.binary_sensor_config_message.binary_sensor_device_class)) + 18);
sprintf(value_template, "{{ value_json.%s }}", zh_get_binary_sensor_device_class_value_name(device_data->payload_data.config_message.binary_sensor_config_message.binary_sensor_device_class));
char *json_attributes_topic = (char *)heap_caps_malloc(strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 31, MALLOC_CAP_8BIT);
memset(json_attributes_topic, 0, strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 31);
sprintf(json_attributes_topic, "%s/%s/" MAC_STR "/attributes", CONFIG_MQTT_TOPIC_PREFIX, zh_get_device_type_value_name(device_data->device_type), MAC2STR(device_mac));
char *qos = (char *)heap_caps_malloc(4, MALLOC_CAP_8BIT);
memset(qos, 0, 4);
sprintf(qos, "%d", device_data->payload_data.config_message.binary_sensor_config_message.qos);
char *expire_after = (char *)heap_caps_malloc(6, MALLOC_CAP_8BIT);
memset(expire_after, 0, 6);
sprintf(expire_after, "%d", device_data->payload_data.config_message.binary_sensor_config_message.expire_after);
char *off_delay = (char *)heap_caps_malloc(6, MALLOC_CAP_8BIT);
memset(off_delay, 0, 6);
sprintf(off_delay, "%d", device_data->payload_data.config_message.binary_sensor_config_message.off_delay);
zh_json_t json = {0};
char buffer[512] = {0};
zh_json_init(&json);
zh_json_add(&json, "platform", "mqtt");
zh_json_add(&json, "name", name);
zh_json_add(&json, "unique_id", unique_id);
zh_json_add(&json, "device_class", zh_get_binary_sensor_device_class_value_name(device_data->payload_data.config_message.binary_sensor_config_message.binary_sensor_device_class));
zh_json_add(&json, "state_topic", state_topic);
zh_json_add(&json, "value_template", value_template);
zh_json_add(&json, "json_attributes_topic", json_attributes_topic);
zh_json_add(&json, "enabled_by_default", (device_data->payload_data.config_message.binary_sensor_config_message.enabled_by_default == true) ? "true" : "false");
zh_json_add(&json, "payload_on", zh_get_on_off_type_value_name(device_data->payload_data.config_message.binary_sensor_config_message.payload_on));
zh_json_add(&json, "payload_off", zh_get_on_off_type_value_name(device_data->payload_data.config_message.binary_sensor_config_message.payload_off));
zh_json_add(&json, "qos", qos);
zh_json_add(&json, "retain", (device_data->payload_data.config_message.binary_sensor_config_message.retain == true) ? "true" : "false");
if (device_data->payload_data.config_message.binary_sensor_config_message.expire_after != 0)
{
zh_json_add(&json, "expire_after", expire_after);
}
zh_json_add(&json, "force_update", (device_data->payload_data.config_message.binary_sensor_config_message.force_update == true) ? "true" : "false");
if (device_data->payload_data.config_message.binary_sensor_config_message.off_delay != 0)
{
zh_json_add(&json, "off_delay", off_delay);
}
zh_json_create(&json, buffer);
zh_json_free(&json);
char *topic = (char *)heap_caps_malloc(strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(unique_id) + 23, MALLOC_CAP_8BIT);
memset(topic, 0, strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(unique_id) + 23);
sprintf(topic, "%s/binary_sensor/%s/config", CONFIG_MQTT_TOPIC_PREFIX, unique_id);
esp_mqtt_client_publish(gateway_config->mqtt_client, topic, buffer, 0, 2, true);
heap_caps_free(name);
heap_caps_free(unique_id);
heap_caps_free(state_topic);
heap_caps_free(value_template);
heap_caps_free(json_attributes_topic);
heap_caps_free(qos);
heap_caps_free(expire_after);
heap_caps_free(off_delay);
heap_caps_free(topic);
}
void zh_espnow_binary_sensor_send_mqtt_json_status_message(const zh_espnow_data_t *device_data, const uint8_t *device_mac, const gateway_config_t *gateway_config)
{
zh_json_t json = {0};
char buffer[512] = {0};
zh_json_init(&json);
switch (device_data->payload_data.status_message.binary_sensor_status_message.sensor_type)
{
case HAST_GATEWAY:
zh_json_add(&json, "connectivity", zh_get_on_off_type_value_name(device_data->payload_data.status_message.binary_sensor_status_message.connect));
break;
case HAST_WINDOW:
zh_json_add(&json, "window", zh_get_on_off_type_value_name(device_data->payload_data.status_message.binary_sensor_status_message.open));
zh_json_add(&json, "battery", zh_get_on_off_type_value_name(device_data->payload_data.status_message.binary_sensor_status_message.battery));
break;
case HAST_DOOR:
zh_json_add(&json, "door", zh_get_on_off_type_value_name(device_data->payload_data.status_message.binary_sensor_status_message.open));
zh_json_add(&json, "battery", zh_get_on_off_type_value_name(device_data->payload_data.status_message.binary_sensor_status_message.battery));
break;
case HAST_LEAKAGE:
zh_json_add(&json, "moisture", zh_get_on_off_type_value_name(device_data->payload_data.status_message.binary_sensor_status_message.leakage));
zh_json_add(&json, "battery", zh_get_on_off_type_value_name(device_data->payload_data.status_message.binary_sensor_status_message.battery));
break;
default:
break;
}
zh_json_create(&json, buffer);
zh_json_free(&json);
char *topic = (char *)heap_caps_malloc(strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 31, MALLOC_CAP_8BIT);
memset(topic, 0, strlen(CONFIG_MQTT_TOPIC_PREFIX) + strlen(zh_get_device_type_value_name(device_data->device_type)) + 31);
sprintf(topic, "%s/%s/" MAC_STR "/state", CONFIG_MQTT_TOPIC_PREFIX, zh_get_device_type_value_name(device_data->device_type), MAC2STR(device_mac));
esp_mqtt_client_publish(gateway_config->mqtt_client, topic, buffer, 0, 2, true);
heap_caps_free(topic);
}