5 Commits

Author SHA1 Message Date
02ec02edcc Version 1.0.7
Fixed small bug.
Updated some components.
2024-07-25 10:46:28 +03:00
b5def82a15 Version 1.0.6
Added changing sensor measurement time.
Added multiple attempts to read the sensor.
2024-07-19 19:22:38 +03:00
708bf211fa Version 1.0.5
Changed WiFi protocol.
Reduced sensor status message fruquency.
Reduced time threshold for sensor availability.
Changed sensor reading error message.
Added offline message.
Changed task management.
2024-07-18 13:30:09 +03:00
31b7789873 Version 1.0.4
Added sensor reading error message.
Updated components.
2024-07-16 14:12:28 +03:00
6e27f40bf1 Update README.md 2024-07-05 13:48:21 +03:00
11 changed files with 192 additions and 89 deletions

View File

@ -21,8 +21,8 @@ ESP-NOW based switch for ESP32 ESP-IDF and ESP8266 RTOS SDK. Alternate firmware
2. ESP-NOW mesh network based on the [zh_network](https://github.com/aZholtikov/zh_network). 2. ESP-NOW mesh network based on the [zh_network](https://github.com/aZholtikov/zh_network).
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. 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.
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 restart the switch, send the "restart" command to the root topic of the switch (example - "homeassistant/espnow_switch/24-62-AB-F9-1F-A8").
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). The time and success of the update depends on the load on WiFi channel 1. Average update time is up to five minutes. The online status of the update will be displayed in the root switch topic. 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 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"). 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,X9,X10". Where:
@ -36,6 +36,7 @@ MQTT configuration message should filled according to the template "X1,X2,X3,X4,
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. 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. 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

View File

@ -155,4 +155,12 @@ menu "ZH ESP-NOW Switch Configuration"
bool "DHT" bool "DHT"
endchoice 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,7 +15,11 @@ 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);
esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_11B); #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 #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();
@ -48,6 +52,7 @@ void zh_load_config(switch_config_t *switch_config)
{ {
nvs_set_u8(nvs_handle, "present", 0xFE); nvs_set_u8(nvs_handle, "present", 0xFE);
nvs_close(nvs_handle); nvs_close(nvs_handle);
SETUP_INITIAL_SETTINGS:
#ifdef CONFIG_RELAY_USING #ifdef CONFIG_RELAY_USING
switch_config->hardware_config.relay_pin = CONFIG_RELAY_PIN; switch_config->hardware_config.relay_pin = CONFIG_RELAY_PIN;
#else #else
@ -91,27 +96,36 @@ void zh_load_config(switch_config_t *switch_config)
#ifdef CONFIG_SENSOR_TYPE_DS18B20 #ifdef CONFIG_SENSOR_TYPE_DS18B20
switch_config->hardware_config.sensor_pin = CONFIG_SENSOR_PIN; switch_config->hardware_config.sensor_pin = CONFIG_SENSOR_PIN;
switch_config->hardware_config.sensor_type = HAST_DS18B20; switch_config->hardware_config.sensor_type = HAST_DS18B20;
switch_config->hardware_config.measurement_frequency = CONFIG_MEASUREMENT_FREQUENCY;
#elif CONFIG_SENSOR_TYPE_DHT #elif CONFIG_SENSOR_TYPE_DHT
switch_config->hardware_config.sensor_pin = CONFIG_SENSOR_PIN; switch_config->hardware_config.sensor_pin = CONFIG_SENSOR_PIN;
switch_config->hardware_config.sensor_type = HAST_DHT; switch_config->hardware_config.sensor_type = HAST_DHT;
switch_config->hardware_config.measurement_frequency = CONFIG_MEASUREMENT_FREQUENCY;
#else #else
switch_config->hardware_config.sensor_pin = ZH_NOT_USED; switch_config->hardware_config.sensor_pin = ZH_NOT_USED;
switch_config->hardware_config.sensor_type = HAST_NONE; 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;
} }
nvs_get_u8(nvs_handle, "relay_pin", &switch_config->hardware_config.relay_pin); esp_err_t err = ESP_OK;
nvs_get_u8(nvs_handle, "relay_lvl", (uint8_t *)&switch_config->hardware_config.relay_on_level); err += nvs_get_u8(nvs_handle, "relay_pin", &switch_config->hardware_config.relay_pin);
nvs_get_u8(nvs_handle, "led_pin", &switch_config->hardware_config.led_pin); err += nvs_get_u8(nvs_handle, "relay_lvl", (uint8_t *)&switch_config->hardware_config.relay_on_level);
nvs_get_u8(nvs_handle, "led_lvl", (uint8_t *)&switch_config->hardware_config.led_on_level); err += nvs_get_u8(nvs_handle, "led_pin", &switch_config->hardware_config.led_pin);
nvs_get_u8(nvs_handle, "int_btn_pin", &switch_config->hardware_config.int_button_pin); err += nvs_get_u8(nvs_handle, "led_lvl", (uint8_t *)&switch_config->hardware_config.led_on_level);
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_pin", &switch_config->hardware_config.int_button_pin);
nvs_get_u8(nvs_handle, "ext_btn_pin", &switch_config->hardware_config.ext_button_pin); err += nvs_get_u8(nvs_handle, "int_btn_lvl", (uint8_t *)&switch_config->hardware_config.int_button_on_level);
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_pin", &switch_config->hardware_config.ext_button_pin);
nvs_get_u8(nvs_handle, "sensor_pin", &switch_config->hardware_config.sensor_pin); err += nvs_get_u8(nvs_handle, "ext_btn_lvl", (uint8_t *)&switch_config->hardware_config.ext_button_on_level);
nvs_get_u8(nvs_handle, "sensor_type", (uint8_t *)&switch_config->hardware_config.sensor_type); 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)
{
goto SETUP_INITIAL_SETTINGS;
}
} }
void zh_save_config(const switch_config_t *switch_config) void zh_save_config(const switch_config_t *switch_config)
@ -128,6 +142,7 @@ void zh_save_config(const switch_config_t *switch_config)
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_pin", switch_config->hardware_config.sensor_pin);
nvs_set_u8(nvs_handle, "sensor_type", switch_config->hardware_config.sensor_type); 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);
} }
@ -396,7 +411,7 @@ void zh_send_sensor_config_message(const switch_config_t *switch_config)
data.device_type = ZHDT_SENSOR; data.device_type = ZHDT_SENSOR;
data.payload_type = ZHPT_CONFIG; 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.suggested_display_precision = 1;
data.payload_data.config_message.sensor_config_message.expire_after = ZH_SENSOR_STATUS_MESSAGE_FREQUENCY * 3; 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.enabled_by_default = true;
data.payload_data.config_message.sensor_config_message.force_update = 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.qos = 2;
@ -467,62 +482,55 @@ void zh_send_sensor_status_message_task(void *pvParameter)
float temperature = 0.0; float temperature = 0.0;
zh_espnow_data_t data = {0}; zh_espnow_data_t data = {0};
data.device_type = ZHDT_SENSOR; data.device_type = ZHDT_SENSOR;
data.payload_type = ZHPT_STATE;
data.payload_data.status_message.sensor_status_message.sensor_type = switch_config->hardware_config.sensor_type;
for (;;) for (;;)
{ {
uint8_t attempts = 0;
READ_SENSOR:;
esp_err_t err = ESP_OK;
switch (switch_config->hardware_config.sensor_type) switch (switch_config->hardware_config.sensor_type)
{ {
case HAST_DS18B20: case HAST_DS18B20:
ZH_DS18B20_READ: err = zh_ds18b20_read(NULL, &temperature);
switch (zh_ds18b20_read(NULL, &temperature)) if (err == ESP_OK)
{ {
case ESP_OK:
data.payload_data.status_message.sensor_status_message.temperature = temperature; data.payload_data.status_message.sensor_status_message.temperature = temperature;
data.payload_data.status_message.sensor_status_message.voltage = 3.3; // For compatibility with zh_espnow_sensor. data.payload_data.status_message.sensor_status_message.voltage = 3.3; // For future development.
break;
case ESP_FAIL:
vTaskDelay(10000 / portTICK_PERIOD_MS);
goto ZH_DS18B20_READ;
break;
case ESP_ERR_INVALID_CRC:
vTaskDelay(1000 / portTICK_PERIOD_MS);
goto ZH_DS18B20_READ;
break;
default:
break;
} }
break; break;
case HAST_DHT: case HAST_DHT:
ZH_DHT_READ: err = zh_dht_read(&humidity, &temperature);
switch (zh_dht_read(&humidity, &temperature)) if (err == ESP_OK)
{ {
case ESP_OK:
data.payload_data.status_message.sensor_status_message.humidity = humidity; 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.temperature = temperature;
data.payload_data.status_message.sensor_status_message.voltage = 3.3; // For compatibility with zh_espnow_sensor. data.payload_data.status_message.sensor_status_message.voltage = 3.3; // For future development.
break;
case ESP_ERR_INVALID_RESPONSE:
vTaskDelay(10000 / portTICK_PERIOD_MS);
goto ZH_DHT_READ;
break;
case ESP_ERR_TIMEOUT:
vTaskDelay(10000 / portTICK_PERIOD_MS);
goto ZH_DHT_READ;
break;
case ESP_ERR_INVALID_CRC:
vTaskDelay(3000 / portTICK_PERIOD_MS);
goto ZH_DHT_READ;
break;
default:
break;
} }
break; break;
default: default:
break; break;
} }
zh_send_message(switch_config->gateway_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t)); if (err == ESP_OK)
vTaskDelay(ZH_SENSOR_STATUS_MESSAGE_FREQUENCY * 1000 / portTICK_PERIOD_MS); {
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); vTaskDelete(NULL);
} }
@ -565,13 +573,30 @@ void zh_espnow_event_handler(void *arg, esp_event_base_t event_base, int32_t eve
{ {
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);
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) 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); zh_send_sensor_config_message(switch_config);
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); 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_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);
}
} }
} }
} }
@ -583,12 +608,12 @@ void zh_espnow_event_handler(void *arg, esp_event_base_t event_base, int32_t eve
switch_config->gateway_is_available = false; switch_config->gateway_is_available = false;
if (switch_config->hardware_config.relay_pin != ZH_NOT_USED) if (switch_config->hardware_config.relay_pin != ZH_NOT_USED)
{ {
vTaskDelete(switch_config->switch_attributes_message_task); vTaskSuspend(switch_config->switch_attributes_message_task);
vTaskDelete(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) 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); vTaskSuspend(switch_config->sensor_attributes_message_task);
vTaskDelete(switch_config->sensor_status_message_task); vTaskSuspend(switch_config->sensor_status_message_task);
} }
} }
} }
@ -611,10 +636,42 @@ void zh_espnow_event_handler(void *arg, esp_event_base_t event_base, int32_t eve
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_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.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);
@ -627,7 +684,6 @@ void zh_espnow_event_handler(void *arg, esp_event_base_t event_base, int32_t eve
#else #else
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->device_type = ZHDT_SWITCH;
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_send_message(switch_config->gateway_mac, (uint8_t *)data, sizeof(zh_espnow_data_t));
break; break;
@ -654,6 +710,16 @@ void zh_espnow_event_handler(void *arg, esp_event_base_t event_base, int32_t eve
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)
@ -661,6 +727,16 @@ 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_FAIL; data->payload_type = ZHPT_UPDATE_FAIL;
zh_send_message(switch_config->gateway_mac, (uint8_t *)data, sizeof(zh_espnow_data_t)); zh_send_message(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);
@ -671,6 +747,22 @@ void zh_espnow_event_handler(void *arg, esp_event_base_t event_base, int32_t eve
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:
@ -691,12 +783,12 @@ void zh_espnow_event_handler(void *arg, esp_event_base_t event_base, int32_t eve
switch_config->gateway_is_available = false; switch_config->gateway_is_available = false;
if (switch_config->hardware_config.relay_pin != ZH_NOT_USED) if (switch_config->hardware_config.relay_pin != ZH_NOT_USED)
{ {
vTaskDelete(switch_config->switch_attributes_message_task); vTaskSuspend(switch_config->switch_attributes_message_task);
vTaskDelete(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) 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); vTaskSuspend(switch_config->sensor_attributes_message_task);
vTaskDelete(switch_config->sensor_status_message_task); vTaskSuspend(switch_config->sensor_status_message_task);
} }
} }
} }
@ -712,12 +804,12 @@ void zh_espnow_event_handler(void *arg, esp_event_base_t event_base, int32_t eve
switch_config->gateway_is_available = false; switch_config->gateway_is_available = false;
if (switch_config->hardware_config.relay_pin != ZH_NOT_USED) if (switch_config->hardware_config.relay_pin != ZH_NOT_USED)
{ {
vTaskDelete(switch_config->switch_attributes_message_task); vTaskSuspend(switch_config->switch_attributes_message_task);
vTaskDelete(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) 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); vTaskSuspend(switch_config->sensor_attributes_message_task);
vTaskDelete(switch_config->sensor_status_message_task); vTaskSuspend(switch_config->sensor_status_message_task);
} }
} }
} }

View File

@ -48,8 +48,8 @@
#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_STATUS_MESSAGE_FREQUENCY 300 // // Frequency of sending a sensor status 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_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 3 // 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.
@ -60,16 +60,17 @@ typedef struct // Structure of data exchange between tasks, functions and event
{ {
struct // Storage structure of switch hardware configuration data. struct // Storage structure of switch hardware configuration data.
{ {
uint8_t relay_pin; // Relay GPIO number. uint8_t relay_pin; // Relay GPIO number.
bool relay_on_level; // Relay ON level. @note HIGH (true) / LOW (false). bool relay_on_level; // Relay ON level. @note HIGH (true) / LOW (false).
uint8_t led_pin; // Led GPIO number (if present). uint8_t led_pin; // Led GPIO number (if present).
bool led_on_level; // Led ON level (if present). @note HIGH (true) / LOW (false). bool led_on_level; // Led ON level (if present). @note HIGH (true) / LOW (false).
uint8_t int_button_pin; // Internal button GPIO number (if present). uint8_t int_button_pin; // Internal button GPIO number (if present).
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). 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. 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.
{ {
@ -77,6 +78,7 @@ typedef struct // Structure of data exchange between tasks, functions and event
} 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().
@ -159,14 +161,14 @@ void zh_send_switch_attributes_message_task(void *pvParameter);
void zh_send_switch_config_message(const switch_config_t *switch_config); void zh_send_switch_config_message(const switch_config_t *switch_config);
/** /**
* @brief Function for prepare the sensor hardware configuration message and sending it to the gateway. * @brief Function for prepare the switch hardware 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. * @param[in] switch_config Pointer to the structure of data exchange between tasks, functions and event handlers.
*/ */
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);
/** /**
* @brief Task for prepare the sensor keep alive message and sending it to the gateway. * @brief Task for prepare the switch keep alive message and sending it to the gateway.
* *
* @param[in] pvParameter Pointer to the structure of data exchange between tasks, functions and event handlers. * @param[in] pvParameter Pointer to the structure of data exchange between tasks, functions and event handlers.
*/ */

View File

@ -1 +1 @@
1.0.3 1.0.7