Version 2.0.0

Added ESP32 - C2/C3/C6/S2/S3 support.
Added ESP-NOW v2.0 support.
Removed zh_network support.
Removed external sensor support.
Improved stability of work.
This commit is contained in:
Alexey Zholtikov 2025-01-26 11:51:51 +03:00
parent 02ec02edcc
commit 80d3c9953c
25 changed files with 185 additions and 497 deletions

15
.gitmodules vendored
View File

@ -1,18 +1,3 @@
[submodule "components/zh_ds18b20"]
path = components/zh_ds18b20
url = https://github.com/aZholtikov/zh_ds18b20
[submodule "components/zh_onewire"]
path = components/zh_onewire
url = https://github.com/aZholtikov/zh_onewire
[submodule "components/zh_dht"]
path = components/zh_dht
url = https://github.com/aZholtikov/zh_dht
[submodule "components/zh_network"]
path = components/zh_network
url = https://github.com/aZholtikov/zh_network
[submodule "components/zh_vector"]
path = components/zh_vector
url = https://github.com/aZholtikov/zh_vector
[submodule "components/zh_config"] [submodule "components/zh_config"]
path = components/zh_config path = components/zh_config
url = https://github.com/aZholtikov/zh_config url = https://github.com/aZholtikov/zh_config

View File

@ -1,30 +1,26 @@
# ESP-NOW switch # ESP-NOW switch
ESP-NOW based switch for ESP32 ESP-IDF and ESP8266 RTOS SDK. Alternate firmware for Tuya/SmartLife/eWeLink WiFi switches. ESP-NOW based switch for ESP32 ESP-IDF and ESP8266 RTOS_SDK. Alternate firmware for Tuya/SmartLife/eWeLink WiFi switches.
## Tested on ## Tested on
1. ESP8266 RTOS_SDK v3.4 1. ESP8266 RTOS_SDK v3.4
2. ESP32 ESP-IDF v5.2 2. ESP32 ESP-IDF v5.4
## Features ## Features
1. Saves the last state when the power is turned off. 1. Saves the last state when the power is turned off.
2. Automatically adds switch configuration to Home Assistan via MQTT discovery as a switch. 2. Automatically adds switch configuration to Home Assistan via MQTT discovery as a switch.
3. Update firmware from HTTPS server via ESP-NOW. 3. Update firmware from HTTPS server via ESP-NOW.
4. Optional support one external 1-wire sensor (DS18B20/DHT11/DHT22/AM2302/AM2320).
5. Direct or mesh work mode.
## Notes ## Notes
1. Work mode must be same with [gateway](https://github.com/aZholtikov/zh_gateway) work mode. 1. For initial settings use "menuconfig -> ZH ESP-NOW Switch Configuration". After first boot all settings will be stored in NVS memory for prevente change during OTA firmware update.
2. ESP-NOW mesh network based on the [zh_network](https://github.com/aZholtikov/zh_network). 2. To restart the switch, send the "restart" command to the root topic of the switch (example - "homeassistant/espnow_switch/24-62-AB-F9-1F-A8").
3. For initial settings use "menuconfig -> ZH ESP-NOW Switch Configuration". After first boot all settings will be stored in NVS memory for prevente change during OTA firmware update. 3. To update the switch firmware, send the "update" command to the root topic of the switch (example - "homeassistant/espnow_switch/70-03-9F-44-BE-F7"). The update path should be like as "https://your_server/zh_espnow_switch_esp32.bin" (for ESP32) or "https://your_server/zh_espnow_switch_esp8266.app1.bin + https://your_server/zh_espnow_switch_esp8266.app2.bin" (for ESP8266). Average update time is up to one minute. The status of the update will be displayed in the root switch topic.
4. To restart the switch, send the "restart" command to the root topic of the switch (example - "homeassistant/espnow_switch/24-62-AB-F9-1F-A8"). 4. To change initial settings of the switch, send the X1,X2,X3,X4,X5,X6,X7,X8 command to the hardware topic of the switch (example - "homeassistant/espnow_switch/70-03-9F-44-BE-F7/hardware"). The configuration will only be accepted if it does not cause errors. The current configuration status is displayed in the configuration topic of the switch (example - "homeassistant/espnow_switch/70-03-9F-44-BE-F7/config").
5. To update the switch firmware, send the "update" command to the root topic of the switch (example - "homeassistant/espnow_switch/70-03-9F-44-BE-F7"). The update path should be like as "https://your_server/zh_espnow_switch_esp32.bin" (for ESP32) or "https://your_server/zh_espnow_switch_esp8266.app1.bin + https://your_server/zh_espnow_switch_esp8266.app2.bin" (for ESP8266). Average update time is up to some minutes. The online status of the update will be displayed in the root switch topic.
6. To change initial settings of the switch (except work mode), send the X1,X2,X3,X4,X5,X6,X7,X8,X9,X10,X11 command to the hardware topic of the switch (example - "homeassistant/espnow_switch/70-03-9F-44-BE-F7/hardware"). The configuration will only be accepted if it does not cause errors. The current configuration status is displayed in the configuration topic of the switch (example - "homeassistant/espnow_switch/70-03-9F-44-BE-F7/config").
MQTT configuration message should filled according to the template "X1,X2,X3,X4,X5,X6,X7,X8,X9,X10". Where: MQTT configuration message should filled according to the template "X1,X2,X3,X4,X5,X6,X7,X8". Where:
1. X1 - Relay GPIO number. 0 - 48 (according to the module used), 255 if not used. 1. X1 - Relay GPIO number. 0 - 48 (according to the module used), 255 if not used.
2. X2 - Relay ON level. 1 for high, 0 for low. Only affected when X1 is used. 2. X2 - Relay ON level. 1 for high, 0 for low. Only affected when X1 is used.
@ -34,9 +30,6 @@ MQTT configuration message should filled according to the template "X1,X2,X3,X4,
6. X6 - Internal button trigger level. 1 for high, 0 for low. Only affected when X5 is used. 6. X6 - Internal button trigger level. 1 for high, 0 for low. Only affected when X5 is used.
7. X7 - External button GPIO number. 0 - 48 (according to the module used), 255 if not used. 7. X7 - External button GPIO number. 0 - 48 (according to the module used), 255 if not used.
8. X8 - External button trigger level. 1 for high, 0 for low. Only affected when X7 is used. 8. X8 - External button trigger level. 1 for high, 0 for low. Only affected when X7 is used.
9. X9 - Sensor GPIO number. 0 - 48 (according to the module used). 255 if not used.
10. X10 - Sensor type. 1 for DS18B20, 8 for DHT. Only affected when X9 is used.
11. X11 - Sensor measurement frequency. 1 - 65536 seconds. Only affected when X9 is used.
## Build and flash ## Build and flash

@ -1 +0,0 @@
Subproject commit 7662593a30319809aa5160fa382689b675615f15

@ -1 +0,0 @@
Subproject commit e53f9c8c3e55e132efc48cd786d9f3c4ed24c1ce

@ -1 +1 @@
Subproject commit d066c326e3accf6de824c20479b31282f599a4ce Subproject commit f4ecd08e4521dd1f46df15325304cb596296d42b

@ -1 +0,0 @@
Subproject commit ebe0b8cbf52c97b532c620b57ef0a3da7869228a

@ -1 +0,0 @@
Subproject commit fb8cfebbd00cea50fc5d8b5a1247f7ca8c33b650

@ -1 +0,0 @@
Subproject commit 4e0c0a6623afc0eb0816b0447d8567bf6867247c

View File

@ -14,7 +14,7 @@
Using MQTT: Using MQTT:
"12,1,4,0,13,0,255,0,255,0" "12,1,4,0,13,0,255,0"
``` ```
2. MINI 1CH 16A. Built on Tuya WiFi module WB2S (BK7231T chip). Replacement with ESP-02S (TYWE2S). [Photo](http://git.zh.com.ru/alexey.zholtikov/zh_espnow_switch/src/branch/main/hardware/MINI_1CH_16A). 2. MINI 1CH 16A. Built on Tuya WiFi module WB2S (BK7231T chip). Replacement with ESP-02S (TYWE2S). [Photo](http://git.zh.com.ru/alexey.zholtikov/zh_espnow_switch/src/branch/main/hardware/MINI_1CH_16A).
@ -33,7 +33,7 @@
Using MQTT: Using MQTT:
"13,1,4,0,3,0,14,1,255,0" "13,1,4,0,3,0,14,1"
``` ```
3. LIGHT E27 SOCKET. Built on Tuya WiFi module WA2 (WB2S) (BK7231T chip). Replacement with ESP-02S (TYWE2S). [Photo](http://git.zh.com.ru/alexey.zholtikov/zh_espnow_switch/src/branch/main/hardware/LIGHT_E27_SOCKET). 3. LIGHT E27 SOCKET. Built on Tuya WiFi module WA2 (WB2S) (BK7231T chip). Replacement with ESP-02S (TYWE2S). [Photo](http://git.zh.com.ru/alexey.zholtikov/zh_espnow_switch/src/branch/main/hardware/LIGHT_E27_SOCKET).
@ -50,7 +50,7 @@
Using MQTT: Using MQTT:
"12,1,4,0,13,0,255,0,255,0" "12,1,4,0,13,0,255,0"
``` ```
4. TH 1CH 16A + DS18B20. Built on ITEAD WiFi module PSF-B85 (ESP8285 chip). Replacement not required. [Photo](http://git.zh.com.ru/alexey.zholtikov/zh_espnow_switch/src/branch/main/hardware/TH_1CH_16A). 4. TH 1CH 16A + DS18B20. Built on ITEAD WiFi module PSF-B85 (ESP8285 chip). Replacement not required. [Photo](http://git.zh.com.ru/alexey.zholtikov/zh_espnow_switch/src/branch/main/hardware/TH_1CH_16A).
@ -64,10 +64,8 @@
Led ON level LOW Led ON level LOW
Internal button GPIO number 0 Internal button GPIO number 0
Internal button trigger level LOW Internal button trigger level LOW
Sensor GPIO number 14
Sensor type DS18B20
Using MQTT: Using MQTT:
"12,1,13,0,0,0,255,0,14,1" "12,1,13,0,0,0,255,0"
``` ```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 MiB

View File

@ -10,17 +10,6 @@ menu "ZH ESP-NOW Switch Configuration"
default 19 if IDF_TARGET_ESP32C3 default 19 if IDF_TARGET_ESP32C3
default 30 if IDF_TARGET_ESP32C6 default 30 if IDF_TARGET_ESP32C6
choice NETWORK_TYPE
prompt "Network type"
help
Network type.
default NETWORK_TYPE_DIRECT
config NETWORK_TYPE_DIRECT
bool "DIRECT"
config NETWORK_TYPE_MESH
bool "MESH"
endchoice
config RELAY_USING config RELAY_USING
bool "Enable using relay" bool "Enable using relay"
default true default true
@ -128,39 +117,4 @@ menu "ZH ESP-NOW Switch Configuration"
bool "LOW" bool "LOW"
endchoice endchoice
config SENSOR_USING
depends on RELAY_USING
bool "Enable using external sensor"
default false
help
Enable using external sensor.
config SENSOR_PIN
depends on SENSOR_USING
int "Sensor GPIO number"
range 0 GPIO_RANGE_MAX
default 2
help
Sensor GPIO.
choice SENSOR_TYPE
depends on SENSOR_USING
prompt "Sensor type"
help
Sensor type.
default SENSOR_TYPE_DS18B20
config SENSOR_TYPE_DS18B20
bool "DS18B20"
config SENSOR_TYPE_DHT
bool "DHT"
endchoice
config MEASUREMENT_FREQUENCY
depends on SENSOR_USING
int "Sensor measurement frequency"
range 1 65536
default 300
help
Sensor measurement frequency.
endmenu endmenu

View File

@ -15,23 +15,17 @@ void app_main(void)
wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT(); wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT();
esp_wifi_init(&wifi_init_config); esp_wifi_init(&wifi_init_config);
esp_wifi_set_mode(WIFI_MODE_STA); esp_wifi_set_mode(WIFI_MODE_STA);
#ifdef CONFIG_IDF_TARGET_ESP8266
esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N);
#else
esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N | WIFI_PROTOCOL_LR);
#endif
esp_wifi_start(); esp_wifi_start();
#ifdef CONFIG_NETWORK_TYPE_DIRECT
zh_espnow_init_config_t espnow_init_config = ZH_ESPNOW_INIT_CONFIG_DEFAULT(); zh_espnow_init_config_t espnow_init_config = ZH_ESPNOW_INIT_CONFIG_DEFAULT();
zh_espnow_init(&espnow_init_config); zh_espnow_init(&espnow_init_config);
#else xTaskCreatePinnedToCore(&zh_send_switch_attributes_message_task, "switch_attributes_message_task", ZH_MESSAGE_STACK_SIZE, switch_config, ZH_MESSAGE_TASK_PRIORITY, (TaskHandle_t *)&switch_config->switch_attributes_message_task, tskNO_AFFINITY);
zh_network_init_config_t network_init_config = ZH_NETWORK_INIT_CONFIG_DEFAULT(); vTaskSuspend(switch_config->switch_attributes_message_task);
zh_network_init(&network_init_config); xTaskCreatePinnedToCore(&zh_send_switch_keep_alive_message_task, "switch_keep_alive_message_task", ZH_MESSAGE_STACK_SIZE, switch_config, ZH_MESSAGE_TASK_PRIORITY, (TaskHandle_t *)&switch_config->switch_keep_alive_message_task, tskNO_AFFINITY);
#endif vTaskSuspend(switch_config->switch_keep_alive_message_task);
#ifdef CONFIG_IDF_TARGET_ESP8266 #ifdef CONFIG_IDF_TARGET_ESP8266
esp_event_handler_register(ZH_EVENT, ESP_EVENT_ANY_ID, &zh_espnow_event_handler, switch_config); esp_event_handler_register(ZH_ESPNOW, ESP_EVENT_ANY_ID, &zh_espnow_event_handler, switch_config);
#else #else
esp_event_handler_instance_register(ZH_EVENT, ESP_EVENT_ANY_ID, &zh_espnow_event_handler, switch_config, NULL); esp_event_handler_instance_register(ZH_ESPNOW, ESP_EVENT_ANY_ID, &zh_espnow_event_handler, switch_config, NULL);
const esp_partition_t *running = esp_ota_get_running_partition(); const esp_partition_t *running = esp_ota_get_running_partition();
esp_ota_img_states_t ota_state = {0}; esp_ota_img_states_t ota_state = {0};
esp_ota_get_state_partition(running, &ota_state); esp_ota_get_state_partition(running, &ota_state);
@ -92,19 +86,6 @@ void zh_load_config(switch_config_t *switch_config)
switch_config->hardware_config.ext_button_on_level = ZH_HIGH; switch_config->hardware_config.ext_button_on_level = ZH_HIGH;
#else #else
switch_config->hardware_config.ext_button_on_level = ZH_LOW; switch_config->hardware_config.ext_button_on_level = ZH_LOW;
#endif
#ifdef CONFIG_SENSOR_TYPE_DS18B20
switch_config->hardware_config.sensor_pin = CONFIG_SENSOR_PIN;
switch_config->hardware_config.sensor_type = HAST_DS18B20;
switch_config->hardware_config.measurement_frequency = CONFIG_MEASUREMENT_FREQUENCY;
#elif CONFIG_SENSOR_TYPE_DHT
switch_config->hardware_config.sensor_pin = CONFIG_SENSOR_PIN;
switch_config->hardware_config.sensor_type = HAST_DHT;
switch_config->hardware_config.measurement_frequency = CONFIG_MEASUREMENT_FREQUENCY;
#else
switch_config->hardware_config.sensor_pin = ZH_NOT_USED;
switch_config->hardware_config.sensor_type = HAST_NONE;
switch_config->hardware_config.measurement_frequency = ZH_NOT_USED;
#endif #endif
zh_save_config(switch_config); zh_save_config(switch_config);
return; return;
@ -118,9 +99,6 @@ void zh_load_config(switch_config_t *switch_config)
err += nvs_get_u8(nvs_handle, "int_btn_lvl", (uint8_t *)&switch_config->hardware_config.int_button_on_level); err += nvs_get_u8(nvs_handle, "int_btn_lvl", (uint8_t *)&switch_config->hardware_config.int_button_on_level);
err += nvs_get_u8(nvs_handle, "ext_btn_pin", &switch_config->hardware_config.ext_button_pin); err += nvs_get_u8(nvs_handle, "ext_btn_pin", &switch_config->hardware_config.ext_button_pin);
err += nvs_get_u8(nvs_handle, "ext_btn_lvl", (uint8_t *)&switch_config->hardware_config.ext_button_on_level); err += nvs_get_u8(nvs_handle, "ext_btn_lvl", (uint8_t *)&switch_config->hardware_config.ext_button_on_level);
err += nvs_get_u8(nvs_handle, "sensor_pin", &switch_config->hardware_config.sensor_pin);
err += nvs_get_u8(nvs_handle, "sensor_type", (uint8_t *)&switch_config->hardware_config.sensor_type);
err += nvs_get_u16(nvs_handle, "frequency", &switch_config->hardware_config.measurement_frequency);
nvs_close(nvs_handle); nvs_close(nvs_handle);
if (err != ESP_OK) if (err != ESP_OK)
{ {
@ -140,9 +118,6 @@ void zh_save_config(const switch_config_t *switch_config)
nvs_set_u8(nvs_handle, "int_btn_lvl", switch_config->hardware_config.int_button_on_level); nvs_set_u8(nvs_handle, "int_btn_lvl", switch_config->hardware_config.int_button_on_level);
nvs_set_u8(nvs_handle, "ext_btn_pin", switch_config->hardware_config.ext_button_pin); nvs_set_u8(nvs_handle, "ext_btn_pin", switch_config->hardware_config.ext_button_pin);
nvs_set_u8(nvs_handle, "ext_btn_lvl", switch_config->hardware_config.ext_button_on_level); nvs_set_u8(nvs_handle, "ext_btn_lvl", switch_config->hardware_config.ext_button_on_level);
nvs_set_u8(nvs_handle, "sensor_pin", switch_config->hardware_config.sensor_pin);
nvs_set_u8(nvs_handle, "sensor_type", switch_config->hardware_config.sensor_type);
nvs_set_u16(nvs_handle, "frequency", switch_config->hardware_config.measurement_frequency);
nvs_close(nvs_handle); nvs_close(nvs_handle);
} }
@ -187,7 +162,6 @@ void zh_gpio_init(switch_config_t *switch_config)
switch_config->hardware_config.led_pin = ZH_NOT_USED; switch_config->hardware_config.led_pin = ZH_NOT_USED;
switch_config->hardware_config.int_button_pin = ZH_NOT_USED; switch_config->hardware_config.int_button_pin = ZH_NOT_USED;
switch_config->hardware_config.ext_button_pin = ZH_NOT_USED; switch_config->hardware_config.ext_button_pin = ZH_NOT_USED;
switch_config->hardware_config.sensor_pin = ZH_NOT_USED;
return; return;
} }
if (switch_config->hardware_config.led_pin != ZH_NOT_USED) if (switch_config->hardware_config.led_pin != ZH_NOT_USED)
@ -229,7 +203,7 @@ void zh_gpio_init(switch_config_t *switch_config)
if (switch_config->hardware_config.int_button_pin != ZH_NOT_USED || switch_config->hardware_config.ext_button_pin != ZH_NOT_USED) if (switch_config->hardware_config.int_button_pin != ZH_NOT_USED || switch_config->hardware_config.ext_button_pin != ZH_NOT_USED)
{ {
switch_config->button_pushing_semaphore = xSemaphoreCreateBinary(); switch_config->button_pushing_semaphore = xSemaphoreCreateBinary();
xTaskCreatePinnedToCore(&zh_gpio_processing_task, "NULL", ZH_GPIO_STACK_SIZE, switch_config, ZH_GPIO_TASK_PRIORITY, NULL, tskNO_AFFINITY); xTaskCreatePinnedToCore(&zh_gpio_processing_task, "gpio_processing_task", ZH_GPIO_STACK_SIZE, switch_config, ZH_GPIO_TASK_PRIORITY, NULL, tskNO_AFFINITY);
gpio_install_isr_service(0); gpio_install_isr_service(0);
if (switch_config->hardware_config.int_button_pin != ZH_NOT_USED) if (switch_config->hardware_config.int_button_pin != ZH_NOT_USED)
{ {
@ -240,30 +214,6 @@ void zh_gpio_init(switch_config_t *switch_config)
gpio_isr_handler_add(switch_config->hardware_config.ext_button_pin, zh_gpio_isr_handler, switch_config); gpio_isr_handler_add(switch_config->hardware_config.ext_button_pin, zh_gpio_isr_handler, switch_config);
} }
} }
if (switch_config->hardware_config.sensor_pin != ZH_NOT_USED)
{
switch (switch_config->hardware_config.sensor_type)
{
case HAST_DS18B20:
if (zh_onewire_init(switch_config->hardware_config.sensor_pin) != ESP_OK)
{
switch_config->hardware_config.sensor_pin = ZH_NOT_USED;
}
break;
case HAST_DHT:;
zh_dht_init_config_t dht_init_config = ZH_DHT_INIT_CONFIG_DEFAULT();
dht_init_config.sensor_pin = switch_config->hardware_config.sensor_pin;
if (zh_dht_init(&dht_init_config) != ESP_OK)
{
switch_config->hardware_config.sensor_pin = ZH_NOT_USED;
}
break;
default:
switch_config->hardware_config.sensor_type = HAST_NONE;
switch_config->hardware_config.sensor_pin = ZH_NOT_USED;
break;
}
}
} }
} }
@ -293,7 +243,7 @@ void zh_gpio_set_level(switch_config_t *switch_config)
} }
} }
void zh_gpio_isr_handler(void *arg) void IRAM_ATTR zh_gpio_isr_handler(void *arg)
{ {
switch_config_t *switch_config = arg; switch_config_t *switch_config = arg;
if (switch_config->gpio_processing == false) if (switch_config->gpio_processing == false)
@ -340,7 +290,7 @@ void zh_send_switch_attributes_message_task(void *pvParameter)
data.payload_data.attributes_message.heap_size = esp_get_free_heap_size(); 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.min_heap_size = esp_get_minimum_free_heap_size();
data.payload_data.attributes_message.uptime = esp_timer_get_time() / 1000000; data.payload_data.attributes_message.uptime = esp_timer_get_time() / 1000000;
zh_send_message(switch_config->gateway_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t)); zh_espnow_send(switch_config->gateway_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t));
vTaskDelay(ZH_SWITCH_ATTRIBUTES_MESSAGE_FREQUENCY * 1000 / portTICK_PERIOD_MS); vTaskDelay(ZH_SWITCH_ATTRIBUTES_MESSAGE_FREQUENCY * 1000 / portTICK_PERIOD_MS);
} }
vTaskDelete(NULL); vTaskDelete(NULL);
@ -359,7 +309,7 @@ void zh_send_switch_config_message(const switch_config_t *switch_config)
data.payload_data.config_message.switch_config_message.optimistic = false; data.payload_data.config_message.switch_config_message.optimistic = false;
data.payload_data.config_message.switch_config_message.qos = 2; data.payload_data.config_message.switch_config_message.qos = 2;
data.payload_data.config_message.switch_config_message.retain = true; data.payload_data.config_message.switch_config_message.retain = true;
zh_send_message(switch_config->gateway_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t)); zh_espnow_send(switch_config->gateway_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t));
} }
void zh_send_switch_hardware_config_message(const switch_config_t *switch_config) void zh_send_switch_hardware_config_message(const switch_config_t *switch_config)
@ -375,9 +325,7 @@ void zh_send_switch_hardware_config_message(const switch_config_t *switch_config
data.payload_data.config_message.switch_hardware_config_message.int_button_on_level = switch_config->hardware_config.int_button_on_level; data.payload_data.config_message.switch_hardware_config_message.int_button_on_level = switch_config->hardware_config.int_button_on_level;
data.payload_data.config_message.switch_hardware_config_message.ext_button_pin = switch_config->hardware_config.ext_button_pin; data.payload_data.config_message.switch_hardware_config_message.ext_button_pin = switch_config->hardware_config.ext_button_pin;
data.payload_data.config_message.switch_hardware_config_message.ext_button_on_level = switch_config->hardware_config.ext_button_on_level; data.payload_data.config_message.switch_hardware_config_message.ext_button_on_level = switch_config->hardware_config.ext_button_on_level;
data.payload_data.config_message.switch_hardware_config_message.sensor_pin = switch_config->hardware_config.sensor_pin; zh_espnow_send(switch_config->gateway_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t));
data.payload_data.config_message.switch_hardware_config_message.sensor_type = switch_config->hardware_config.sensor_type;
zh_send_message(switch_config->gateway_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t));
} }
void zh_send_switch_keep_alive_message_task(void *pvParameter) void zh_send_switch_keep_alive_message_task(void *pvParameter)
@ -390,7 +338,7 @@ void zh_send_switch_keep_alive_message_task(void *pvParameter)
data.payload_data.keep_alive_message.message_frequency = ZH_SWITCH_KEEP_ALIVE_MESSAGE_FREQUENCY; data.payload_data.keep_alive_message.message_frequency = ZH_SWITCH_KEEP_ALIVE_MESSAGE_FREQUENCY;
for (;;) for (;;)
{ {
zh_send_message(switch_config->gateway_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t)); zh_espnow_send(switch_config->gateway_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t));
vTaskDelay(ZH_SWITCH_KEEP_ALIVE_MESSAGE_FREQUENCY * 1000 / portTICK_PERIOD_MS); vTaskDelay(ZH_SWITCH_KEEP_ALIVE_MESSAGE_FREQUENCY * 1000 / portTICK_PERIOD_MS);
} }
vTaskDelete(NULL); vTaskDelete(NULL);
@ -402,137 +350,7 @@ void zh_send_switch_status_message(const switch_config_t *switch_config)
data.device_type = ZHDT_SWITCH; data.device_type = ZHDT_SWITCH;
data.payload_type = ZHPT_STATE; data.payload_type = ZHPT_STATE;
data.payload_data.status_message.switch_status_message.status = switch_config->status.status; data.payload_data.status_message.switch_status_message.status = switch_config->status.status;
zh_send_message(switch_config->gateway_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t)); zh_espnow_send(switch_config->gateway_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t));
}
void zh_send_sensor_config_message(const switch_config_t *switch_config)
{
zh_espnow_data_t data = {0};
data.device_type = ZHDT_SENSOR;
data.payload_type = ZHPT_CONFIG;
data.payload_data.config_message.sensor_config_message.suggested_display_precision = 1;
data.payload_data.config_message.sensor_config_message.expire_after = switch_config->hardware_config.measurement_frequency * 1.5; // + 50% just in case.
data.payload_data.config_message.sensor_config_message.enabled_by_default = true;
data.payload_data.config_message.sensor_config_message.force_update = true;
data.payload_data.config_message.sensor_config_message.qos = 2;
data.payload_data.config_message.sensor_config_message.retain = true;
char *unit_of_measurement = NULL;
// For compatibility with zh_espnow_sensor.
data.payload_data.config_message.sensor_config_message.unique_id = 2;
data.payload_data.config_message.sensor_config_message.sensor_device_class = HASDC_VOLTAGE;
unit_of_measurement = "V";
strcpy(data.payload_data.config_message.sensor_config_message.unit_of_measurement, unit_of_measurement);
zh_send_message(switch_config->gateway_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t));
// For compatibility with zh_espnow_sensor.
switch (switch_config->hardware_config.sensor_type)
{
case HAST_DS18B20:
data.payload_data.config_message.sensor_config_message.unique_id = 3;
data.payload_data.config_message.sensor_config_message.sensor_device_class = HASDC_TEMPERATURE;
unit_of_measurement = "°C";
strcpy(data.payload_data.config_message.sensor_config_message.unit_of_measurement, unit_of_measurement);
zh_send_message(switch_config->gateway_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t));
break;
case HAST_DHT:
data.payload_data.config_message.sensor_config_message.unique_id = 3;
data.payload_data.config_message.sensor_config_message.sensor_device_class = HASDC_TEMPERATURE;
unit_of_measurement = "°C";
strcpy(data.payload_data.config_message.sensor_config_message.unit_of_measurement, unit_of_measurement);
zh_send_message(switch_config->gateway_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t));
data.payload_data.config_message.sensor_config_message.unique_id = 4;
data.payload_data.config_message.sensor_config_message.sensor_device_class = HASDC_HUMIDITY;
unit_of_measurement = "%";
strcpy(data.payload_data.config_message.sensor_config_message.unit_of_measurement, unit_of_measurement);
zh_send_message(switch_config->gateway_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t));
break;
default:
break;
}
}
void zh_send_sensor_attributes_message_task(void *pvParameter)
{
switch_config_t *switch_config = pvParameter;
const esp_app_desc_t *app_info = get_app_description();
zh_espnow_data_t data = {0};
data.device_type = ZHDT_SENSOR;
data.payload_type = ZHPT_ATTRIBUTES;
data.payload_data.attributes_message.chip_type = ZH_CHIP_TYPE;
data.payload_data.attributes_message.sensor_type = switch_config->hardware_config.sensor_type;
strcpy(data.payload_data.attributes_message.flash_size, CONFIG_ESPTOOLPY_FLASHSIZE);
data.payload_data.attributes_message.cpu_frequency = ZH_CPU_FREQUENCY;
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 (;;)
{
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_send_message(switch_config->gateway_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t));
vTaskDelay(ZH_SENSOR_ATTRIBUTES_MESSAGE_FREQUENCY * 1000 / portTICK_PERIOD_MS);
}
vTaskDelete(NULL);
}
void zh_send_sensor_status_message_task(void *pvParameter)
{
switch_config_t *switch_config = pvParameter;
float humidity = 0.0;
float temperature = 0.0;
zh_espnow_data_t data = {0};
data.device_type = ZHDT_SENSOR;
for (;;)
{
uint8_t attempts = 0;
READ_SENSOR:;
esp_err_t err = ESP_OK;
switch (switch_config->hardware_config.sensor_type)
{
case HAST_DS18B20:
err = zh_ds18b20_read(NULL, &temperature);
if (err == ESP_OK)
{
data.payload_data.status_message.sensor_status_message.temperature = temperature;
data.payload_data.status_message.sensor_status_message.voltage = 3.3; // For future development.
}
break;
case HAST_DHT:
err = zh_dht_read(&humidity, &temperature);
if (err == ESP_OK)
{
data.payload_data.status_message.sensor_status_message.humidity = humidity;
data.payload_data.status_message.sensor_status_message.temperature = temperature;
data.payload_data.status_message.sensor_status_message.voltage = 3.3; // For future development.
}
break;
default:
break;
}
if (err == ESP_OK)
{
data.payload_type = ZHPT_STATE;
data.payload_data.status_message.sensor_status_message.sensor_type = switch_config->hardware_config.sensor_type;
zh_send_message(switch_config->gateway_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t));
}
else
{
if (++attempts < ZH_SENSOR_READ_MAXIMUM_RETRY)
{
vTaskDelay(1000 / portTICK_PERIOD_MS);
goto READ_SENSOR;
}
data.payload_type = ZHPT_ERROR;
char *message = (char *)heap_caps_malloc(150, MALLOC_CAP_8BIT);
memset(message, 0, 150);
sprintf(message, "Sensor %s reading error. Error - %s.", zh_get_sensor_type_value_name(switch_config->hardware_config.sensor_type), esp_err_to_name(err));
strcpy(data.payload_data.status_message.error_message.message, message);
zh_send_message(switch_config->gateway_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t));
heap_caps_free(message);
}
vTaskDelay(switch_config->hardware_config.measurement_frequency * 1000 / portTICK_PERIOD_MS);
}
vTaskDelete(NULL);
} }
void zh_espnow_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) void zh_espnow_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
@ -540,21 +358,12 @@ void zh_espnow_event_handler(void *arg, esp_event_base_t event_base, int32_t eve
switch_config_t *switch_config = arg; switch_config_t *switch_config = arg;
switch (event_id) switch (event_id)
{ {
#ifdef CONFIG_NETWORK_TYPE_DIRECT
case ZH_ESPNOW_ON_RECV_EVENT:; case ZH_ESPNOW_ON_RECV_EVENT:;
zh_espnow_event_on_recv_t *recv_data = event_data; zh_espnow_event_on_recv_t *recv_data = event_data;
if (recv_data->data_len != sizeof(zh_espnow_data_t)) if (recv_data->data_len != sizeof(zh_espnow_data_t))
{ {
goto ZH_ESPNOW_EVENT_HANDLER_EXIT; 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 = (zh_espnow_data_t *)recv_data->data; zh_espnow_data_t *data = (zh_espnow_data_t *)recv_data->data;
switch (data->device_type) switch (data->device_type)
{ {
@ -564,59 +373,22 @@ void zh_espnow_event_handler(void *arg, esp_event_base_t event_base, int32_t eve
case ZHPT_KEEP_ALIVE: case ZHPT_KEEP_ALIVE:
if (data->payload_data.keep_alive_message.online_status == ZH_ONLINE) if (data->payload_data.keep_alive_message.online_status == ZH_ONLINE)
{ {
memcpy(switch_config->gateway_mac, recv_data->mac_addr, 6);
if (switch_config->gateway_is_available == false) if (switch_config->gateway_is_available == false)
{ {
switch_config->gateway_is_available = true; switch_config->gateway_is_available = true;
memcpy(switch_config->gateway_mac, recv_data->mac_addr, 6);
zh_send_switch_hardware_config_message(switch_config); zh_send_switch_hardware_config_message(switch_config);
if (switch_config->hardware_config.relay_pin != ZH_NOT_USED)
{
zh_send_switch_config_message(switch_config); zh_send_switch_config_message(switch_config);
zh_send_switch_status_message(switch_config); zh_send_switch_status_message(switch_config);
if (switch_config->hardware_config.sensor_pin != ZH_NOT_USED && switch_config->hardware_config.sensor_type != HAST_NONE)
{
zh_send_sensor_config_message(switch_config);
}
if (switch_config->is_first_connection == false)
{
xTaskCreatePinnedToCore(&zh_send_switch_attributes_message_task, "NULL", ZH_MESSAGE_STACK_SIZE, switch_config, ZH_MESSAGE_TASK_PRIORITY, (TaskHandle_t *)&switch_config->switch_attributes_message_task, tskNO_AFFINITY);
xTaskCreatePinnedToCore(&zh_send_switch_keep_alive_message_task, "NULL", ZH_MESSAGE_STACK_SIZE, switch_config, ZH_MESSAGE_TASK_PRIORITY, (TaskHandle_t *)&switch_config->switch_keep_alive_message_task, tskNO_AFFINITY);
if (switch_config->hardware_config.sensor_pin != ZH_NOT_USED && switch_config->hardware_config.sensor_type != HAST_NONE)
{
xTaskCreatePinnedToCore(&zh_send_sensor_status_message_task, "NULL", ZH_MESSAGE_STACK_SIZE, switch_config, ZH_MESSAGE_TASK_PRIORITY, (TaskHandle_t *)&switch_config->sensor_status_message_task, tskNO_AFFINITY);
xTaskCreatePinnedToCore(&zh_send_sensor_attributes_message_task, "NULL", ZH_MESSAGE_STACK_SIZE, switch_config, ZH_MESSAGE_TASK_PRIORITY, (TaskHandle_t *)&switch_config->sensor_attributes_message_task, tskNO_AFFINITY);
}
switch_config->is_first_connection = true;
}
else
{
vTaskResume(switch_config->switch_attributes_message_task); vTaskResume(switch_config->switch_attributes_message_task);
vTaskResume(switch_config->switch_keep_alive_message_task); vTaskResume(switch_config->switch_keep_alive_message_task);
if (switch_config->hardware_config.sensor_pin != ZH_NOT_USED && switch_config->hardware_config.sensor_type != HAST_NONE)
{
vTaskResume(switch_config->sensor_status_message_task);
vTaskResume(switch_config->sensor_attributes_message_task);
}
}
}
} }
} }
else else
{
if (switch_config->gateway_is_available == true)
{ {
switch_config->gateway_is_available = false; switch_config->gateway_is_available = false;
if (switch_config->hardware_config.relay_pin != ZH_NOT_USED)
{
vTaskSuspend(switch_config->switch_attributes_message_task); vTaskSuspend(switch_config->switch_attributes_message_task);
vTaskSuspend(switch_config->switch_keep_alive_message_task); vTaskSuspend(switch_config->switch_keep_alive_message_task);
if (switch_config->hardware_config.sensor_pin != ZH_NOT_USED && switch_config->hardware_config.sensor_type != HAST_NONE)
{
vTaskSuspend(switch_config->sensor_attributes_message_task);
vTaskSuspend(switch_config->sensor_status_message_task);
}
}
}
} }
break; break;
case ZHPT_SET: case ZHPT_SET:
@ -634,44 +406,10 @@ void zh_espnow_event_handler(void *arg, esp_event_base_t event_base, int32_t eve
switch_config->hardware_config.int_button_on_level = data->payload_data.config_message.switch_hardware_config_message.int_button_on_level; switch_config->hardware_config.int_button_on_level = data->payload_data.config_message.switch_hardware_config_message.int_button_on_level;
switch_config->hardware_config.ext_button_pin = data->payload_data.config_message.switch_hardware_config_message.ext_button_pin; switch_config->hardware_config.ext_button_pin = data->payload_data.config_message.switch_hardware_config_message.ext_button_pin;
switch_config->hardware_config.ext_button_on_level = data->payload_data.config_message.switch_hardware_config_message.ext_button_on_level; switch_config->hardware_config.ext_button_on_level = data->payload_data.config_message.switch_hardware_config_message.ext_button_on_level;
switch_config->hardware_config.sensor_pin = data->payload_data.config_message.switch_hardware_config_message.sensor_pin;
switch_config->hardware_config.sensor_type = data->payload_data.config_message.switch_hardware_config_message.sensor_type;
switch_config->hardware_config.measurement_frequency = data->payload_data.config_message.switch_hardware_config_message.measurement_frequency;
zh_save_config(switch_config); zh_save_config(switch_config);
if (switch_config->hardware_config.relay_pin != ZH_NOT_USED)
{
vTaskDelete(switch_config->switch_attributes_message_task);
vTaskDelete(switch_config->switch_keep_alive_message_task);
if (switch_config->hardware_config.sensor_pin != ZH_NOT_USED && switch_config->hardware_config.sensor_type != HAST_NONE)
{
vTaskDelete(switch_config->sensor_attributes_message_task);
vTaskDelete(switch_config->sensor_status_message_task);
}
}
data->device_type = ZHDT_SWITCH;
data->payload_type = ZHPT_KEEP_ALIVE;
data->payload_data.keep_alive_message.online_status = ZH_OFFLINE;
data->payload_data.keep_alive_message.message_frequency = ZH_SWITCH_KEEP_ALIVE_MESSAGE_FREQUENCY;
zh_send_message(switch_config->gateway_mac, (uint8_t *)data, sizeof(zh_espnow_data_t));
vTaskDelay(1000 / portTICK_PERIOD_MS);
esp_restart(); esp_restart();
break; break;
case ZHPT_UPDATE:; case ZHPT_UPDATE:;
if (switch_config->hardware_config.relay_pin != ZH_NOT_USED)
{
vTaskSuspend(switch_config->switch_attributes_message_task);
vTaskSuspend(switch_config->switch_keep_alive_message_task);
if (switch_config->hardware_config.sensor_pin != ZH_NOT_USED && switch_config->hardware_config.sensor_type != HAST_NONE)
{
vTaskSuspend(switch_config->sensor_attributes_message_task);
vTaskSuspend(switch_config->sensor_status_message_task);
}
}
data->device_type = ZHDT_SWITCH;
data->payload_type = ZHPT_KEEP_ALIVE;
data->payload_data.keep_alive_message.online_status = ZH_OFFLINE;
data->payload_data.keep_alive_message.message_frequency = ZH_SWITCH_KEEP_ALIVE_MESSAGE_FREQUENCY;
zh_send_message(switch_config->gateway_mac, (uint8_t *)data, sizeof(zh_espnow_data_t));
const esp_app_desc_t *app_info = get_app_description(); const esp_app_desc_t *app_info = get_app_description();
switch_config->update_partition = esp_ota_get_next_update_partition(NULL); switch_config->update_partition = esp_ota_get_next_update_partition(NULL);
strcpy(data->payload_data.ota_message.espnow_ota_data.app_version, app_info->version); strcpy(data->payload_data.ota_message.espnow_ota_data.app_version, app_info->version);
@ -685,7 +423,7 @@ void zh_espnow_event_handler(void *arg, esp_event_base_t event_base, int32_t eve
strcpy(data->payload_data.ota_message.espnow_ota_data.app_name, app_info->project_name); strcpy(data->payload_data.ota_message.espnow_ota_data.app_name, app_info->project_name);
#endif #endif
data->payload_type = ZHPT_UPDATE; data->payload_type = ZHPT_UPDATE;
zh_send_message(switch_config->gateway_mac, (uint8_t *)data, sizeof(zh_espnow_data_t)); zh_espnow_send(switch_config->gateway_mac, (uint8_t *)data, sizeof(zh_espnow_data_t));
break; break;
case ZHPT_UPDATE_BEGIN: case ZHPT_UPDATE_BEGIN:
#ifdef CONFIG_IDF_TARGET_ESP8266 #ifdef CONFIG_IDF_TARGET_ESP8266
@ -696,7 +434,7 @@ void zh_espnow_event_handler(void *arg, esp_event_base_t event_base, int32_t eve
switch_config->ota_message_part_number = 1; switch_config->ota_message_part_number = 1;
data->device_type = ZHDT_SWITCH; data->device_type = ZHDT_SWITCH;
data->payload_type = ZHPT_UPDATE_PROGRESS; data->payload_type = ZHPT_UPDATE_PROGRESS;
zh_send_message(switch_config->gateway_mac, (uint8_t *)data, sizeof(zh_espnow_data_t)); zh_espnow_send(switch_config->gateway_mac, (uint8_t *)data, sizeof(zh_espnow_data_t));
break; break;
case ZHPT_UPDATE_PROGRESS: case ZHPT_UPDATE_PROGRESS:
if (switch_config->ota_message_part_number == data->payload_data.ota_message.espnow_ota_message.part) if (switch_config->ota_message_part_number == data->payload_data.ota_message.espnow_ota_message.part)
@ -706,63 +444,27 @@ void zh_espnow_event_handler(void *arg, esp_event_base_t event_base, int32_t eve
} }
data->device_type = ZHDT_SWITCH; data->device_type = ZHDT_SWITCH;
data->payload_type = ZHPT_UPDATE_PROGRESS; data->payload_type = ZHPT_UPDATE_PROGRESS;
zh_send_message(switch_config->gateway_mac, (uint8_t *)data, sizeof(zh_espnow_data_t)); zh_espnow_send(switch_config->gateway_mac, (uint8_t *)data, sizeof(zh_espnow_data_t));
break; break;
case ZHPT_UPDATE_ERROR: case ZHPT_UPDATE_ERROR:
esp_ota_end(switch_config->update_handle); esp_ota_end(switch_config->update_handle);
if (switch_config->hardware_config.relay_pin != ZH_NOT_USED)
{
vTaskResume(switch_config->switch_attributes_message_task);
vTaskResume(switch_config->switch_keep_alive_message_task);
if (switch_config->hardware_config.sensor_pin != ZH_NOT_USED && switch_config->hardware_config.sensor_type != HAST_NONE)
{
vTaskResume(switch_config->sensor_attributes_message_task);
vTaskResume(switch_config->sensor_status_message_task);
}
}
break; break;
case ZHPT_UPDATE_END: case ZHPT_UPDATE_END:
if (esp_ota_end(switch_config->update_handle) != ESP_OK) if (esp_ota_end(switch_config->update_handle) != ESP_OK)
{ {
data->device_type = ZHDT_SWITCH; data->device_type = ZHDT_SWITCH;
data->payload_type = ZHPT_UPDATE_FAIL; data->payload_type = ZHPT_UPDATE_FAIL;
zh_send_message(switch_config->gateway_mac, (uint8_t *)data, sizeof(zh_espnow_data_t)); zh_espnow_send(switch_config->gateway_mac, (uint8_t *)data, sizeof(zh_espnow_data_t));
if (switch_config->hardware_config.relay_pin != ZH_NOT_USED)
{
vTaskResume(switch_config->switch_attributes_message_task);
vTaskResume(switch_config->switch_keep_alive_message_task);
if (switch_config->hardware_config.sensor_pin != ZH_NOT_USED && switch_config->hardware_config.sensor_type != HAST_NONE)
{
vTaskResume(switch_config->sensor_attributes_message_task);
vTaskResume(switch_config->sensor_status_message_task);
}
}
break; break;
} }
esp_ota_set_boot_partition(switch_config->update_partition); esp_ota_set_boot_partition(switch_config->update_partition);
data->device_type = ZHDT_SWITCH; data->device_type = ZHDT_SWITCH;
data->payload_type = ZHPT_UPDATE_SUCCESS; data->payload_type = ZHPT_UPDATE_SUCCESS;
zh_send_message(switch_config->gateway_mac, (uint8_t *)data, sizeof(zh_espnow_data_t)); zh_espnow_send(switch_config->gateway_mac, (uint8_t *)data, sizeof(zh_espnow_data_t));
vTaskDelay(1000 / portTICK_PERIOD_MS); vTaskDelay(1000 / portTICK_PERIOD_MS);
esp_restart(); esp_restart();
break; break;
case ZHPT_RESTART: case ZHPT_RESTART:
if (switch_config->hardware_config.relay_pin != ZH_NOT_USED)
{
vTaskDelete(switch_config->switch_attributes_message_task);
vTaskDelete(switch_config->switch_keep_alive_message_task);
if (switch_config->hardware_config.sensor_pin != ZH_NOT_USED && switch_config->hardware_config.sensor_type != HAST_NONE)
{
vTaskDelete(switch_config->sensor_attributes_message_task);
vTaskDelete(switch_config->sensor_status_message_task);
}
}
data->device_type = ZHDT_SWITCH;
data->payload_type = ZHPT_KEEP_ALIVE;
data->payload_data.keep_alive_message.online_status = ZH_OFFLINE;
data->payload_data.keep_alive_message.message_frequency = ZH_SWITCH_KEEP_ALIVE_MESSAGE_FREQUENCY;
zh_send_message(switch_config->gateway_mac, (uint8_t *)data, sizeof(zh_espnow_data_t));
vTaskDelay(1000 / portTICK_PERIOD_MS);
esp_restart(); esp_restart();
break; break;
default: default:
@ -772,7 +474,6 @@ void zh_espnow_event_handler(void *arg, esp_event_base_t event_base, int32_t eve
default: default:
break; break;
} }
#ifdef CONFIG_NETWORK_TYPE_DIRECT
ZH_ESPNOW_EVENT_HANDLER_EXIT: ZH_ESPNOW_EVENT_HANDLER_EXIT:
heap_caps_free(recv_data->data); heap_caps_free(recv_data->data);
break; break;
@ -781,40 +482,10 @@ void zh_espnow_event_handler(void *arg, esp_event_base_t event_base, int32_t eve
if (send_data->status == ZH_ESPNOW_SEND_FAIL && switch_config->gateway_is_available == true) if (send_data->status == ZH_ESPNOW_SEND_FAIL && switch_config->gateway_is_available == true)
{ {
switch_config->gateway_is_available = false; switch_config->gateway_is_available = false;
if (switch_config->hardware_config.relay_pin != ZH_NOT_USED)
{
vTaskSuspend(switch_config->switch_attributes_message_task); vTaskSuspend(switch_config->switch_attributes_message_task);
vTaskSuspend(switch_config->switch_keep_alive_message_task); vTaskSuspend(switch_config->switch_keep_alive_message_task);
if (switch_config->hardware_config.sensor_pin != ZH_NOT_USED && switch_config->hardware_config.sensor_type != HAST_NONE)
{
vTaskSuspend(switch_config->sensor_attributes_message_task);
vTaskSuspend(switch_config->sensor_status_message_task);
}
}
} }
break; break;
#else
ZH_NETWORK_EVENT_HANDLER_EXIT:
heap_caps_free(recv_data->data);
break;
case ZH_NETWORK_ON_SEND_EVENT:;
zh_network_event_on_send_t *send_data = event_data;
if (send_data->status == ZH_NETWORK_SEND_FAIL && switch_config->gateway_is_available == true)
{
switch_config->gateway_is_available = false;
if (switch_config->hardware_config.relay_pin != ZH_NOT_USED)
{
vTaskSuspend(switch_config->switch_attributes_message_task);
vTaskSuspend(switch_config->switch_keep_alive_message_task);
if (switch_config->hardware_config.sensor_pin != ZH_NOT_USED && switch_config->hardware_config.sensor_type != HAST_NONE)
{
vTaskSuspend(switch_config->sensor_attributes_message_task);
vTaskSuspend(switch_config->sensor_status_message_task);
}
}
}
break;
#endif
default: default:
break; break;
} }

View File

@ -8,34 +8,30 @@
#include "driver/gpio.h" #include "driver/gpio.h"
#include "esp_timer.h" #include "esp_timer.h"
#include "esp_ota_ops.h" #include "esp_ota_ops.h"
#include "zh_ds18b20.h"
#include "zh_dht.h"
#include "zh_config.h"
#ifdef CONFIG_NETWORK_TYPE_DIRECT
#include "zh_espnow.h" #include "zh_espnow.h"
#define zh_send_message(a, b, c) zh_espnow_send(a, b, c) #include "zh_config.h"
#define ZH_EVENT ZH_ESPNOW
#else
#include "zh_network.h"
#define zh_send_message(a, b, c) zh_network_send(a, b, c)
#define ZH_EVENT ZH_NETWORK
#endif
#ifdef CONFIG_IDF_TARGET_ESP8266 #ifdef CONFIG_IDF_TARGET_ESP8266
#define ZH_CHIP_TYPE HACHT_ESP8266 #define ZH_CHIP_TYPE HACHT_ESP8266
// #define ZH_CPU_FREQUENCY CONFIG_ESP8266_DEFAULT_CPU_FREQ_MHZ;
#elif CONFIG_IDF_TARGET_ESP32 #elif CONFIG_IDF_TARGET_ESP32
#define ZH_CHIP_TYPE HACHT_ESP32 #define ZH_CHIP_TYPE HACHT_ESP32
// #define ZH_CPU_FREQUENCY CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ;
#elif CONFIG_IDF_TARGET_ESP32S2 #elif CONFIG_IDF_TARGET_ESP32S2
#define ZH_CHIP_TYPE HACHT_ESP32S2 #define ZH_CHIP_TYPE HACHT_ESP32S2
// #define ZH_CPU_FREQUENCY CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ;
#elif CONFIG_IDF_TARGET_ESP32S3 #elif CONFIG_IDF_TARGET_ESP32S3
#define ZH_CHIP_TYPE HACHT_ESP32S3 #define ZH_CHIP_TYPE HACHT_ESP32S3
// #define ZH_CPU_FREQUENCY CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ;
#elif CONFIG_IDF_TARGET_ESP32C2 #elif CONFIG_IDF_TARGET_ESP32C2
#define ZH_CHIP_TYPE HACHT_ESP32C2 #define ZH_CHIP_TYPE HACHT_ESP32C2
// #define ZH_CPU_FREQUENCY CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ;
#elif CONFIG_IDF_TARGET_ESP32C3 #elif CONFIG_IDF_TARGET_ESP32C3
#define ZH_CHIP_TYPE HACHT_ESP32C3 #define ZH_CHIP_TYPE HACHT_ESP32C3
// #define ZH_CPU_FREQUENCY CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ;
#elif CONFIG_IDF_TARGET_ESP32C6 #elif CONFIG_IDF_TARGET_ESP32C6
#define ZH_CHIP_TYPE HACHT_ESP32C6 #define ZH_CHIP_TYPE HACHT_ESP32C6
// #define ZH_CPU_FREQUENCY CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ;
#endif #endif
#ifdef CONFIG_IDF_TARGET_ESP8266 #ifdef CONFIG_IDF_TARGET_ESP8266
@ -48,12 +44,10 @@
#define ZH_SWITCH_KEEP_ALIVE_MESSAGE_FREQUENCY 10 // Frequency of sending a switch keep alive message to the gateway (in seconds). #define ZH_SWITCH_KEEP_ALIVE_MESSAGE_FREQUENCY 10 // Frequency of sending a switch keep alive message to the gateway (in seconds).
#define ZH_SWITCH_ATTRIBUTES_MESSAGE_FREQUENCY 60 // Frequency of sending a switch attributes message to the gateway (in seconds). #define ZH_SWITCH_ATTRIBUTES_MESSAGE_FREQUENCY 60 // Frequency of sending a switch attributes message to the gateway (in seconds).
#define ZH_SENSOR_ATTRIBUTES_MESSAGE_FREQUENCY 60 // Frequency of sending a sensor attributes message to the gateway (in seconds).
#define ZH_SENSOR_READ_MAXIMUM_RETRY 5 // Maximum number of read sensor attempts.
#define ZH_GPIO_TASK_PRIORITY 3 // Prioritize the task of GPIO processing. #define ZH_GPIO_TASK_PRIORITY 10 // Prioritize the task of GPIO processing.
#define ZH_GPIO_STACK_SIZE 2048 // The stack size of the task of GPIO processing. #define ZH_GPIO_STACK_SIZE 2048 // The stack size of the task of GPIO processing.
#define ZH_MESSAGE_TASK_PRIORITY 2 // Prioritize the task of sending messages to the gateway. #define ZH_MESSAGE_TASK_PRIORITY 5 // Prioritize the task of sending messages to the gateway.
#define ZH_MESSAGE_STACK_SIZE 2048 // The stack size of the task of sending messages to the gateway. #define ZH_MESSAGE_STACK_SIZE 2048 // The stack size of the task of sending messages to the gateway.
typedef struct // Structure of data exchange between tasks, functions and event handlers. typedef struct // Structure of data exchange between tasks, functions and event handlers.
@ -68,22 +62,16 @@ typedef struct // Structure of data exchange between tasks, functions and event
bool int_button_on_level; // Internal button trigger level (if present). @note HIGH (true) / LOW (false). bool int_button_on_level; // Internal button trigger level (if present). @note HIGH (true) / LOW (false).
uint8_t ext_button_pin; // External button GPIO number (if present). uint8_t ext_button_pin; // External button GPIO number (if present).
bool ext_button_on_level; // External button trigger level (if present). @note HIGH (true) / LOW (false). bool ext_button_on_level; // External button trigger level (if present). @note HIGH (true) / LOW (false).
uint8_t sensor_pin; // Sensor GPIO number (if present).
ha_sensor_type_t sensor_type; // Sensor types (if present). @note Used to identify the sensor type by ESP-NOW gateway and send the appropriate sensor status messages to MQTT.
uint16_t measurement_frequency; // Sensor measurement frequency (if present).
} hardware_config; } hardware_config;
struct // Storage structure of switch status data. struct // Storage structure of switch status data.
{ {
ha_on_off_type_t status; // Status of the zh_espnow_switch. @note Example - ON / OFF. @attention Must be same with set on switch_config_message structure. ha_on_off_type_t status; // Status of the zh_espnow_switch. @note Example - ON / OFF. @attention Must be same with set on switch_config_message structure (zh_config).
} status; } status;
volatile bool gpio_processing; // GPIO processing flag. @note Used to prevent a repeated interrupt from triggering during GPIO processing. volatile bool gpio_processing; // GPIO processing flag. @note Used to prevent a repeated interrupt from triggering during GPIO processing.
volatile bool gateway_is_available; // Gateway availability status flag. @note Used to control the tasks when the gateway connection is established / lost. volatile bool gateway_is_available; // Gateway availability status flag. @note Used to control the tasks when the gateway connection is established / lost.
volatile bool is_first_connection; // First connection status flag. @note Used to control the tasks when the gateway connection is established / lost.
uint8_t gateway_mac[6]; // Gateway MAC address. uint8_t gateway_mac[6]; // Gateway MAC address.
TaskHandle_t switch_attributes_message_task; // Unique task handle for zh_send_switsh_attributes_message_task(). TaskHandle_t switch_attributes_message_task; // Unique task handle for zh_send_switsh_attributes_message_task().
TaskHandle_t switch_keep_alive_message_task; // Unique task handle for zh_send_switch_keep_alive_message_task(). TaskHandle_t switch_keep_alive_message_task; // Unique task handle for zh_send_switch_keep_alive_message_task().
TaskHandle_t sensor_attributes_message_task; // Unique task handle for zh_send_sensor_attributes_message_task().
TaskHandle_t sensor_status_message_task; // Unique task handle for zh_send_sensor_status_message_task().
SemaphoreHandle_t button_pushing_semaphore; // Unique semaphore handle for GPIO processing tasks. SemaphoreHandle_t button_pushing_semaphore; // Unique semaphore handle for GPIO processing tasks.
const esp_partition_t *update_partition; // Next update partition. const esp_partition_t *update_partition; // Next update partition.
esp_ota_handle_t update_handle; // Unique OTA handle. esp_ota_handle_t update_handle; // Unique OTA handle.
@ -181,27 +169,6 @@ void zh_send_switch_keep_alive_message_task(void *pvParameter);
*/ */
void zh_send_switch_status_message(const switch_config_t *switch_config); void zh_send_switch_status_message(const switch_config_t *switch_config);
/**
* @brief Function for prepare the sensor configuration message and sending it to the gateway.
*
* @param[in] switch_config Pointer to the structure of data exchange between tasks, functions and event handlers.
*/
void zh_send_sensor_config_message(const switch_config_t *switch_config);
/**
* @brief Task for prepare the sensor attributes message and sending it to the gateway.
*
* @param[in] pvParameter Pointer to structure of data exchange between tasks, functions and event handlers.
*/
void zh_send_sensor_attributes_message_task(void *pvParameter);
/**
* @brief Task for prepare the sensor status message and sending it to the gateway.
*
* @param[in] pvParameter Pointer to the structure of data exchange between tasks, functions and event handlers.
*/
void zh_send_sensor_status_message_task(void *pvParameter);
/** /**
* @brief Function for ESP-NOW event processing. * @brief Function for ESP-NOW event processing.
* *

7
partitions_esp32c2.csv Normal file
View File

@ -0,0 +1,7 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs, data, nvs, , 0x4000,
otadata, data, ota, , 0x2000,
phy_init, data, phy, , 0x1000,
ota_0, app, ota_0, , 900K,
ota_1, app, ota_1, , 900K,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
3 nvs, data, nvs, , 0x4000,
4 otadata, data, ota, , 0x2000,
5 phy_init, data, phy, , 0x1000,
6 ota_0, app, ota_0, , 900K,
7 ota_1, app, ota_1, , 900K,

7
partitions_esp32c3.csv Normal file
View File

@ -0,0 +1,7 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs, data, nvs, , 0x4000,
otadata, data, ota, , 0x2000,
phy_init, data, phy, , 0x1000,
ota_0, app, ota_0, , 1500K,
ota_1, app, ota_1, , 1500K,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
3 nvs, data, nvs, , 0x4000,
4 otadata, data, ota, , 0x2000,
5 phy_init, data, phy, , 0x1000,
6 ota_0, app, ota_0, , 1500K,
7 ota_1, app, ota_1, , 1500K,

7
partitions_esp32c6.csv Normal file
View File

@ -0,0 +1,7 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs, data, nvs, , 0x4000,
otadata, data, ota, , 0x2000,
phy_init, data, phy, , 0x1000,
ota_0, app, ota_0, , 1500K,
ota_1, app, ota_1, , 1500K,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
3 nvs, data, nvs, , 0x4000,
4 otadata, data, ota, , 0x2000,
5 phy_init, data, phy, , 0x1000,
6 ota_0, app, ota_0, , 1500K,
7 ota_1, app, ota_1, , 1500K,

7
partitions_esp32s2.csv Normal file
View File

@ -0,0 +1,7 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs, data, nvs, , 0x4000,
otadata, data, ota, , 0x2000,
phy_init, data, phy, , 0x1000,
ota_0, app, ota_0, , 1500K,
ota_1, app, ota_1, , 1500K,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
3 nvs, data, nvs, , 0x4000,
4 otadata, data, ota, , 0x2000,
5 phy_init, data, phy, , 0x1000,
6 ota_0, app, ota_0, , 1500K,
7 ota_1, app, ota_1, , 1500K,

7
partitions_esp32s3.csv Normal file
View File

@ -0,0 +1,7 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs, data, nvs, , 0x4000,
otadata, data, ota, , 0x2000,
phy_init, data, phy, , 0x1000,
ota_0, app, ota_0, , 1500K,
ota_1, app, ota_1, , 1500K,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
3 nvs, data, nvs, , 0x4000,
4 otadata, data, ota, , 0x2000,
5 phy_init, data, phy, , 0x1000,
6 ota_0, app, ota_0, , 1500K,
7 ota_1, app, ota_1, , 1500K,

View File

@ -0,0 +1,18 @@
CONFIG_BOOTLOADER_OFFSET_IN_FLASH=0x1000
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_LOG_LEVEL_NONE=y
CONFIG_BOOTLOADER_LOG_LEVEL=0
CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE=y
CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y
CONFIG_ESPTOOLPY_FLASHSIZE="2MB"
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_esp32c2.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions_esp32c2.csv"
CONFIG_PARTITION_TABLE_OFFSET=0x8000
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_LOG_DEFAULT_LEVEL_NONE=y
CONFIG_LOG_DEFAULT_LEVEL=0

View File

@ -0,0 +1,18 @@
CONFIG_BOOTLOADER_OFFSET_IN_FLASH=0x1000
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_LOG_LEVEL_NONE=y
CONFIG_BOOTLOADER_LOG_LEVEL=0
CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE=y
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_ESPTOOLPY_FLASHSIZE="4MB"
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_esp32c3.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions_esp32c3.csv"
CONFIG_PARTITION_TABLE_OFFSET=0x8000
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_LOG_DEFAULT_LEVEL_NONE=y
CONFIG_LOG_DEFAULT_LEVEL=0

View File

@ -0,0 +1,18 @@
CONFIG_BOOTLOADER_OFFSET_IN_FLASH=0x1000
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_LOG_LEVEL_NONE=y
CONFIG_BOOTLOADER_LOG_LEVEL=0
CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE=y
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_ESPTOOLPY_FLASHSIZE="4MB"
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_esp32c6.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions_esp32c6.csv"
CONFIG_PARTITION_TABLE_OFFSET=0x8000
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_LOG_DEFAULT_LEVEL_NONE=y
CONFIG_LOG_DEFAULT_LEVEL=0

View File

@ -0,0 +1,18 @@
CONFIG_BOOTLOADER_OFFSET_IN_FLASH=0x1000
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_LOG_LEVEL_NONE=y
CONFIG_BOOTLOADER_LOG_LEVEL=0
CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE=y
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_ESPTOOLPY_FLASHSIZE="4MB"
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_esp32s2.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions_esp32s2.csv"
CONFIG_PARTITION_TABLE_OFFSET=0x8000
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_LOG_DEFAULT_LEVEL_NONE=y
CONFIG_LOG_DEFAULT_LEVEL=0

View File

@ -0,0 +1,18 @@
CONFIG_BOOTLOADER_OFFSET_IN_FLASH=0x1000
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_LOG_LEVEL_NONE=y
CONFIG_BOOTLOADER_LOG_LEVEL=0
CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE=y
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_ESPTOOLPY_FLASHSIZE="4MB"
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_esp32s3.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions_esp32s3.csv"
CONFIG_PARTITION_TABLE_OFFSET=0x8000
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_LOG_DEFAULT_LEVEL_NONE=y
CONFIG_LOG_DEFAULT_LEVEL=0

View File

@ -1 +1 @@
1.0.7 2.0.0