5 Commits

Author SHA1 Message Date
56c6a76309 Version 2.2.0
Changed the frequency of sending messages.
Changed the event for the first start of tasks.
2025-02-16 19:17:03 +03:00
3ffdfae7b3 Version 2.1.0
Increase stability of operation.
2025-02-15 22:53:39 +03:00
5dd44ec825 Version 2.0.1
Fixed the error of not sending a configuration message after rebooting the gateway.
Fixed an error of the first hardware configuration saving.
2025-02-15 10:05:45 +03:00
5045741079 Removed some comments 2025-01-30 18:20:53 +03:00
897224744f Update hardware/README.md 2025-01-29 19:35:45 +03:00
5 changed files with 73 additions and 67 deletions

View File

@ -29,7 +29,7 @@
Internal button GPIO number 3 Internal button GPIO number 3
Internal button trigger level LOW Internal button trigger level LOW
External button GPIO number 14 External button GPIO number 14
External button trigger level HIGH External button trigger level LOW
Using MQTT: Using MQTT:

View File

@ -18,10 +18,6 @@ void app_main(void)
esp_wifi_start(); esp_wifi_start();
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);
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);
vTaskSuspend(switch_config->switch_attributes_message_task);
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);
vTaskSuspend(switch_config->switch_keep_alive_message_task);
#ifdef CONFIG_IDF_TARGET_ESP8266 #ifdef CONFIG_IDF_TARGET_ESP8266
esp_event_handler_register(ZH_ESPNOW, 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
@ -44,7 +40,6 @@ void zh_load_config(switch_config_t *switch_config)
uint8_t config_is_present = 0; uint8_t config_is_present = 0;
if (nvs_get_u8(nvs_handle, "present", &config_is_present) == ESP_ERR_NVS_NOT_FOUND) if (nvs_get_u8(nvs_handle, "present", &config_is_present) == ESP_ERR_NVS_NOT_FOUND)
{ {
nvs_set_u8(nvs_handle, "present", 0xFE);
nvs_close(nvs_handle); nvs_close(nvs_handle);
SETUP_INITIAL_SETTINGS: SETUP_INITIAL_SETTINGS:
#ifdef CONFIG_RELAY_USING #ifdef CONFIG_RELAY_USING
@ -110,6 +105,7 @@ void zh_save_config(const switch_config_t *switch_config)
{ {
nvs_handle_t nvs_handle = 0; nvs_handle_t nvs_handle = 0;
nvs_open("config", NVS_READWRITE, &nvs_handle); nvs_open("config", NVS_READWRITE, &nvs_handle);
nvs_set_u8(nvs_handle, "present", 0xFE);
nvs_set_u8(nvs_handle, "relay_pin", switch_config->hardware_config.relay_pin); nvs_set_u8(nvs_handle, "relay_pin", switch_config->hardware_config.relay_pin);
nvs_set_u8(nvs_handle, "relay_lvl", switch_config->hardware_config.relay_on_level); nvs_set_u8(nvs_handle, "relay_lvl", switch_config->hardware_config.relay_on_level);
nvs_set_u8(nvs_handle, "led_pin", switch_config->hardware_config.led_pin); nvs_set_u8(nvs_handle, "led_pin", switch_config->hardware_config.led_pin);
@ -129,7 +125,6 @@ void zh_load_status(switch_config_t *switch_config)
uint8_t status_is_present = 0; uint8_t status_is_present = 0;
if (nvs_get_u8(nvs_handle, "present", &status_is_present) == ESP_ERR_NVS_NOT_FOUND) if (nvs_get_u8(nvs_handle, "present", &status_is_present) == ESP_ERR_NVS_NOT_FOUND)
{ {
nvs_set_u8(nvs_handle, "present", 0xFE);
nvs_close(nvs_handle); nvs_close(nvs_handle);
zh_save_status(switch_config); zh_save_status(switch_config);
return; return;
@ -142,6 +137,7 @@ void zh_save_status(const switch_config_t *switch_config)
{ {
nvs_handle_t nvs_handle = 0; nvs_handle_t nvs_handle = 0;
nvs_open("status", NVS_READWRITE, &nvs_handle); nvs_open("status", NVS_READWRITE, &nvs_handle);
nvs_set_u8(nvs_handle, "present", 0xFE);
nvs_set_u8(nvs_handle, "relay_state", switch_config->status.status); nvs_set_u8(nvs_handle, "relay_state", switch_config->status.status);
nvs_close(nvs_handle); nvs_close(nvs_handle);
} }
@ -262,10 +258,7 @@ void zh_gpio_processing_task(void *pvParameter)
switch_config->status.status = (switch_config->status.status == HAONOFT_ON) ? HAONOFT_OFF : HAONOFT_ON; switch_config->status.status = (switch_config->status.status == HAONOFT_ON) ? HAONOFT_OFF : HAONOFT_ON;
zh_gpio_set_level(switch_config); zh_gpio_set_level(switch_config);
zh_save_status(switch_config); zh_save_status(switch_config);
if (switch_config->gateway_is_available == true)
{
zh_send_switch_status_message(switch_config); zh_send_switch_status_message(switch_config);
}
vTaskDelay(500 / portTICK_PERIOD_MS); // To prevent button contact rattling. Value is selected experimentally. vTaskDelay(500 / portTICK_PERIOD_MS); // To prevent button contact rattling. Value is selected experimentally.
switch_config->gpio_processing = false; switch_config->gpio_processing = false;
} }
@ -296,8 +289,9 @@ void zh_send_switch_attributes_message_task(void *pvParameter)
vTaskDelete(NULL); vTaskDelete(NULL);
} }
void zh_send_switch_config_message(const switch_config_t *switch_config) void zh_send_switch_config_message_task(void *pvParameter)
{ {
switch_config_t *switch_config = pvParameter;
zh_espnow_data_t data = {0}; zh_espnow_data_t data = {0};
data.device_type = ZHDT_SWITCH; data.device_type = ZHDT_SWITCH;
data.payload_type = ZHPT_CONFIG; data.payload_type = ZHPT_CONFIG;
@ -309,11 +303,17 @@ 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;
for (;;)
{
zh_espnow_send(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_CONFIG_MESSAGE_FREQUENCY * 1000 / portTICK_PERIOD_MS);
}
vTaskDelete(NULL);
} }
void zh_send_switch_hardware_config_message(const switch_config_t *switch_config) void zh_send_switch_hardware_config_message_task(void *pvParameter)
{ {
switch_config_t *switch_config = pvParameter;
zh_espnow_data_t data = {0}; zh_espnow_data_t data = {0};
data.device_type = ZHDT_SWITCH; data.device_type = ZHDT_SWITCH;
data.payload_type = ZHPT_HARDWARE; data.payload_type = ZHPT_HARDWARE;
@ -325,7 +325,12 @@ 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;
for (;;)
{
zh_espnow_send(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_HARDWARE_CONFIG_MESSAGE_FREQUENCY * 1000 / portTICK_PERIOD_MS);
}
vTaskDelete(NULL);
} }
void zh_send_switch_keep_alive_message_task(void *pvParameter) void zh_send_switch_keep_alive_message_task(void *pvParameter)
@ -344,6 +349,21 @@ void zh_send_switch_keep_alive_message_task(void *pvParameter)
vTaskDelete(NULL); vTaskDelete(NULL);
} }
void zh_send_switch_status_message_task(void *pvParameter)
{
switch_config_t *switch_config = pvParameter;
zh_espnow_data_t data = {0};
data.device_type = ZHDT_SWITCH;
data.payload_type = ZHPT_STATE;
for (;;)
{
data.payload_data.status_message.switch_status_message.status = switch_config->status.status;
zh_espnow_send(switch_config->gateway_mac, (uint8_t *)&data, sizeof(zh_espnow_data_t));
vTaskDelay(ZH_SWITCH_STATUS_MESSAGE_FREQUENCY * 1000 / portTICK_PERIOD_MS);
}
vTaskDelete(NULL);
}
void zh_send_switch_status_message(const switch_config_t *switch_config) void zh_send_switch_status_message(const switch_config_t *switch_config)
{ {
zh_espnow_data_t data = {0}; zh_espnow_data_t data = {0};
@ -371,24 +391,15 @@ void zh_espnow_event_handler(void *arg, esp_event_base_t event_base, int32_t eve
switch (data->payload_type) switch (data->payload_type)
{ {
case ZHPT_KEEP_ALIVE: case ZHPT_KEEP_ALIVE:
if (data->payload_data.keep_alive_message.online_status == ZH_ONLINE)
{
memcpy(switch_config->gateway_mac, recv_data->mac_addr, 6); memcpy(switch_config->gateway_mac, recv_data->mac_addr, 6);
if (switch_config->gateway_is_available == false) if (is_first_boot == false)
{ {
switch_config->gateway_is_available = true; is_first_boot = true;
zh_send_switch_hardware_config_message(switch_config); xTaskCreatePinnedToCore(&zh_send_switch_attributes_message_task, "switch_attributes_message_task", ZH_MESSAGE_STACK_SIZE, switch_config, ZH_MESSAGE_TASK_PRIORITY, NULL, tskNO_AFFINITY);
zh_send_switch_config_message(switch_config); xTaskCreatePinnedToCore(&zh_send_switch_keep_alive_message_task, "switch_keep_alive_message_task", ZH_MESSAGE_STACK_SIZE, switch_config, ZH_MESSAGE_TASK_PRIORITY, NULL, tskNO_AFFINITY);
zh_send_switch_status_message(switch_config); xTaskCreatePinnedToCore(&zh_send_switch_config_message_task, "switch_config_message_task", ZH_MESSAGE_STACK_SIZE, switch_config, ZH_MESSAGE_TASK_PRIORITY, NULL, tskNO_AFFINITY);
vTaskResume(switch_config->switch_attributes_message_task); xTaskCreatePinnedToCore(&zh_send_switch_hardware_config_message_task, "switch_hardware_config_message_task", ZH_MESSAGE_STACK_SIZE, switch_config, ZH_MESSAGE_TASK_PRIORITY, NULL, tskNO_AFFINITY);
vTaskResume(switch_config->switch_keep_alive_message_task); xTaskCreatePinnedToCore(&zh_send_switch_status_message_task, "switch_status_message_task", ZH_MESSAGE_STACK_SIZE, switch_config, ZH_MESSAGE_TASK_PRIORITY, NULL, tskNO_AFFINITY);
}
}
else
{
switch_config->gateway_is_available = false;
vTaskSuspend(switch_config->switch_attributes_message_task);
vTaskSuspend(switch_config->switch_keep_alive_message_task);
} }
break; break;
case ZHPT_SET: case ZHPT_SET:
@ -477,14 +488,7 @@ void zh_espnow_event_handler(void *arg, esp_event_base_t event_base, int32_t eve
ZH_ESPNOW_EVENT_HANDLER_EXIT: ZH_ESPNOW_EVENT_HANDLER_EXIT:
heap_caps_free(recv_data->data); heap_caps_free(recv_data->data);
break; break;
case ZH_ESPNOW_ON_SEND_EVENT:; case ZH_ESPNOW_ON_SEND_EVENT:
zh_espnow_event_on_send_t *send_data = event_data;
if (send_data->status == ZH_ESPNOW_SEND_FAIL && switch_config->gateway_is_available == true)
{
switch_config->gateway_is_available = false;
vTaskSuspend(switch_config->switch_attributes_message_task);
vTaskSuspend(switch_config->switch_keep_alive_message_task);
}
break; break;
default: default:
break; break;

View File

@ -13,25 +13,18 @@
#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
@ -44,12 +37,17 @@
#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_SWITCH_HARDWARE_CONFIG_MESSAGE_FREQUENCY 60 // Frequency of sending a switch hardware config message to the gateway (in seconds).
#define ZH_SWITCH_CONFIG_MESSAGE_FREQUENCY 60 // Frequency of sending a switch config message to the gateway (in seconds).
#define ZH_SWITCH_STATUS_MESSAGE_FREQUENCY 60 // Frequency of sending a switch status message to the gateway (in seconds).
#define ZH_GPIO_TASK_PRIORITY 10 // 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 5 // 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.
static bool is_first_boot = false;
typedef struct // Structure of data exchange between tasks, functions and event handlers. typedef struct // Structure of data exchange between tasks, functions and event handlers.
{ {
struct // Storage structure of switch hardware configuration data. struct // Storage structure of switch hardware configuration data.
@ -68,10 +66,7 @@ typedef struct // Structure of data exchange between tasks, functions and event
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). 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.
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_keep_alive_message_task; // Unique task handle for zh_send_switch_keep_alive_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.
@ -137,23 +132,23 @@ void zh_gpio_processing_task(void *pvParameter);
/** /**
* @brief Task for prepare the switch attributes message and sending it to the gateway. * @brief Task for prepare the switch attributes message and sending it to the gateway.
* *
* @param[in,out] pvParameter Pointer to structure of data exchange between tasks, functions and event handlers. * @param[in] pvParameter Pointer to structure of data exchange between tasks, functions and event handlers.
*/ */
void zh_send_switch_attributes_message_task(void *pvParameter); void zh_send_switch_attributes_message_task(void *pvParameter);
/** /**
* @brief Function for prepare the switch configuration message and sending it to the gateway. * @brief Task for prepare the switch 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] pvParameter Pointer to the structure of data exchange between tasks, functions and event handlers.
*/ */
void zh_send_switch_config_message(const switch_config_t *switch_config); void zh_send_switch_config_message_task(void *pvParameter);
/** /**
* @brief Function for prepare the switch hardware configuration message and sending it to the gateway. * @brief Task 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] pvParameter 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_task(void *pvParameter);
/** /**
* @brief Task for prepare the switch keep alive message and sending it to the gateway. * @brief Task for prepare the switch keep alive message and sending it to the gateway.
@ -162,6 +157,13 @@ void zh_send_switch_hardware_config_message(const switch_config_t *switch_config
*/ */
void zh_send_switch_keep_alive_message_task(void *pvParameter); void zh_send_switch_keep_alive_message_task(void *pvParameter);
/**
* @brief Task for prepare the switch 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_switch_status_message_task(void *pvParameter);
/** /**
* @brief Function for prepare the switch status message and sending it to the gateway. * @brief Function for prepare the switch status message and sending it to the gateway.
* *

View File

@ -1 +1 @@
2.0.0 2.2.0