Version 1.0.0
Initial version.
This commit is contained in:
		
							
								
								
									
										3
									
								
								main/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								main/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| idf_build_get_property(project_dir PROJECT_DIR) | ||||
| idf_component_register(SRCS "zh_espnow_open_sensor.c" | ||||
|                     INCLUDE_DIRS ".") | ||||
							
								
								
									
										15
									
								
								main/Kconfig.projbuild
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								main/Kconfig.projbuild
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| menu "ZH ESP-NOW Open Sensor Configuration" | ||||
|  | ||||
| 	choice SENSOR_TYPE | ||||
| 		prompt "Sensor type" | ||||
| 		help | ||||
| 			Sensor type. | ||||
| 		default SENSOR_TYPE_WINDOW | ||||
| 		config SENSOR_TYPE_WINDOW | ||||
| 			bool "WINDOW" | ||||
| 		config SENSOR_TYPE_DOOR | ||||
| 			bool "DOOR" | ||||
| 			 | ||||
| 	endchoice | ||||
|  | ||||
| endmenu  | ||||
							
								
								
									
										346
									
								
								main/zh_espnow_open_sensor.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										346
									
								
								main/zh_espnow_open_sensor.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,346 @@ | ||||
| #include "stdio.h" | ||||
| #include "string.h" | ||||
| #include "nvs_flash.h" | ||||
| #include "esp_netif.h" | ||||
| #include "esp_event.h" | ||||
| #include "driver/uart.h" | ||||
| #include "esp_timer.h" | ||||
| #include "esp_ota_ops.h" | ||||
| #include "zh_espnow.h" | ||||
| #include "zh_config.h" | ||||
|  | ||||
| #define ZH_UART_TASK_PRIORITY 6 | ||||
| #define ZH_UART_STACK_SIZE 2048 | ||||
| #define ZH_UART_BUFF_SIZE 1024 | ||||
| #define ZH_UART_QUEUE_SIZE 10 | ||||
| #define ZH_UART_NUM 0 | ||||
|  | ||||
| static uint8_t s_sensor_type = HAST_NONE; | ||||
| static uint8_t s_open_status = HAONOFT_NONE; | ||||
| static uint8_t s_battery_status = HAONOFT_NONE; | ||||
|  | ||||
| static uint8_t s_gateway_mac[6] = {0}; | ||||
| static bool s_gateway_is_available = false; | ||||
|  | ||||
| static const esp_partition_t *s_update_partition = NULL; | ||||
| static esp_ota_handle_t s_update_handle = 0; | ||||
| static uint16_t s_ota_message_part_number = 0; | ||||
|  | ||||
| static QueueHandle_t s_zh_uart_queue = {0}; | ||||
|  | ||||
| static const char s_initial_message[] = {0x55, 0xAA, 0x00, 0x01, 0x00, 0x00, 0x00}; | ||||
| static const char s_connected_message[] = {0x55, 0xAA, 0x00, 0x02, 0x00, 0x01, 0x04, 0x06}; | ||||
| static const char s_setting_message[] = {0x55, 0xAA, 0x00, 0x03, 0x00, 0x00, 0x02}; | ||||
| static const char s_confirmation_message[] = {0x55, 0xAA, 0x00, 0x08, 0x00, 0x01, 0x00, 0x08}; | ||||
|  | ||||
| static void s_zh_uart_processing_task(void *pvParameter); | ||||
|  | ||||
| static void s_zh_load_config(void); | ||||
| static void s_zh_save_config(void); | ||||
| static void s_zh_load_status(void); | ||||
| static void s_zh_save_status(void); | ||||
|  | ||||
| static void s_zh_send_sensor_attributes_message(void); | ||||
| static void s_zh_send_sensor_config_message(void); | ||||
| static void s_zh_send_sensor_status_message(void); | ||||
|  | ||||
| static void s_zh_espnow_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data); | ||||
|  | ||||
| void app_main(void) | ||||
| { | ||||
| #if CONFIG_SENSOR_TYPE_WINDOW | ||||
|     s_sensor_type = HAST_WINDOW; | ||||
| #elif CONFIG_SENSOR_TYPE_DOOR | ||||
|     s_sensor_type = HAST_DOOR; | ||||
| #endif | ||||
|     const esp_partition_t *running = esp_ota_get_running_partition(); | ||||
|     esp_ota_img_states_t ota_state = {0}; | ||||
|     esp_ota_get_state_partition(running, &ota_state); | ||||
|     nvs_flash_init(); | ||||
|     esp_netif_init(); | ||||
|     esp_event_loop_create_default(); | ||||
|     s_zh_load_config(); | ||||
|     s_zh_load_status(); | ||||
|     wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT(); | ||||
|     esp_wifi_init(&wifi_init_config); | ||||
|     esp_wifi_set_mode(WIFI_MODE_STA); | ||||
|     esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_11B); | ||||
|     zh_espnow_init_config_t zh_espnow_init_config = ZH_ESPNOW_INIT_CONFIG_DEFAULT(); | ||||
|     zh_espnow_init(&zh_espnow_init_config); | ||||
|     esp_event_handler_instance_register(ZH_ESPNOW, ESP_EVENT_ANY_ID, &s_zh_espnow_event_handler, NULL, NULL); | ||||
|     xTaskCreatePinnedToCore(&s_zh_uart_processing_task, "s_zh_uart_processing_tack", ZH_UART_STACK_SIZE, NULL, ZH_UART_TASK_PRIORITY, NULL, tskNO_AFFINITY); | ||||
|     s_zh_send_sensor_config_message(); | ||||
|     s_zh_send_sensor_attributes_message(); | ||||
|     if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) | ||||
|     { | ||||
|         vTaskDelay(100 / portTICK_PERIOD_MS); | ||||
|         esp_ota_mark_app_valid_cancel_rollback(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void s_zh_uart_processing_task(void *pvParameter) | ||||
| { | ||||
|     uart_config_t uart_config = { | ||||
|         .baud_rate = 9600, | ||||
|         .data_bits = UART_DATA_8_BITS, | ||||
|         .parity = UART_PARITY_DISABLE, | ||||
|         .stop_bits = UART_STOP_BITS_1, | ||||
|         .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, | ||||
|         .source_clk = UART_SCLK_DEFAULT, | ||||
|     }; | ||||
|     uart_driver_install(ZH_UART_NUM, ZH_UART_BUFF_SIZE, ZH_UART_BUFF_SIZE, ZH_UART_QUEUE_SIZE, &s_zh_uart_queue, 0); | ||||
|     uart_param_config(ZH_UART_NUM, &uart_config); | ||||
|     uart_set_pin(ZH_UART_NUM, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); | ||||
|     uint8_t *data = (uint8_t *)calloc(1, ZH_UART_BUFF_SIZE); | ||||
|     uart_event_t event = {0}; | ||||
|     uart_write_bytes(ZH_UART_NUM, &s_initial_message, sizeof(s_initial_message)); | ||||
|     for (;;) | ||||
|     { | ||||
|         if (xQueueReceive(s_zh_uart_queue, (void *)&event, (TickType_t)portMAX_DELAY)) | ||||
|         { | ||||
|             switch (event.type) | ||||
|             { | ||||
|             case UART_DATA: | ||||
|                 uart_read_bytes(ZH_UART_NUM, data, event.size, portMAX_DELAY); | ||||
|                 if (data[0] == 0x55 && data[3] == 0x01) // MCU system information. | ||||
|                 { | ||||
|                     uart_write_bytes(ZH_UART_NUM, &s_connected_message, sizeof(s_connected_message)); | ||||
|                 } | ||||
|                 if (data[0] == 0x55 && data[3] == 0x03) // Message for switching to setting mode. | ||||
|                 { | ||||
|                     uart_write_bytes(ZH_UART_NUM, &s_setting_message, sizeof(s_setting_message)); | ||||
|                 } | ||||
|                 if (data[0] == 0x55 && data[3] == 0x08) // Sensor status message. | ||||
|                 { | ||||
|                     if (data[7] == 0x01) // Battery status. | ||||
|                     { | ||||
|                         if (data[17] == 0x02 || data[17] == 0x01) | ||||
|                         { | ||||
|                             s_battery_status = HAONOFT_HIGH; | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
|                             s_battery_status = HAONOFT_LOW; | ||||
|                         } | ||||
|                         s_zh_save_status(); | ||||
|                         s_zh_send_sensor_status_message(); | ||||
|                         uart_write_bytes(ZH_UART_NUM, &s_confirmation_message, sizeof(s_confirmation_message)); | ||||
|                     } | ||||
|                     if (data[7] == 0x02) // Sensor position. | ||||
|                     { | ||||
|                         if (data[17] == 0x01) | ||||
|                         { | ||||
|                             s_open_status = HAONOFT_OPEN; | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
|                             s_open_status = HAONOFT_CLOSE; | ||||
|                         } | ||||
|                         s_zh_save_status(); | ||||
|                         s_zh_send_sensor_status_message(); | ||||
|                         uart_write_bytes(ZH_UART_NUM, &s_confirmation_message, sizeof(s_confirmation_message)); | ||||
|                     } | ||||
|                 } | ||||
|                 break; | ||||
|             default: | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     free(data); | ||||
|     vTaskDelete(NULL); | ||||
| } | ||||
|  | ||||
| static void s_zh_load_config(void) | ||||
| { | ||||
|     nvs_handle_t nvs_handle = 0; | ||||
|     nvs_open("config", NVS_READWRITE, &nvs_handle); | ||||
|     uint8_t config_is_present = 0; | ||||
|     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); | ||||
|         s_zh_save_config(); | ||||
|         return; | ||||
|     } | ||||
|     nvs_get_u8(nvs_handle, "sensor_type", &s_sensor_type); | ||||
|     nvs_close(nvs_handle); | ||||
| } | ||||
|  | ||||
| static void s_zh_save_config(void) | ||||
| { | ||||
|     nvs_handle_t nvs_handle = 0; | ||||
|     nvs_open("config", NVS_READWRITE, &nvs_handle); | ||||
|     nvs_set_u8(nvs_handle, "sensor_type", s_sensor_type); | ||||
|     nvs_close(nvs_handle); | ||||
| } | ||||
|  | ||||
| static void s_zh_load_status(void) | ||||
| { | ||||
|     nvs_handle_t nvs_handle = 0; | ||||
|     nvs_open("status", NVS_READWRITE, &nvs_handle); | ||||
|     uint8_t status_is_present = 0; | ||||
|     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); | ||||
|         s_zh_save_status(); | ||||
|         return; | ||||
|     } | ||||
|     nvs_get_u8(nvs_handle, "open_state", &s_open_status); | ||||
|     nvs_get_u8(nvs_handle, "battery_state", &s_battery_status); | ||||
|     nvs_close(nvs_handle); | ||||
| } | ||||
|  | ||||
| static void s_zh_save_status(void) | ||||
| { | ||||
|     nvs_handle_t nvs_handle = 0; | ||||
|     nvs_open("status", NVS_READWRITE, &nvs_handle); | ||||
|     nvs_set_u8(nvs_handle, "open_state", s_open_status); | ||||
|     nvs_set_u8(nvs_handle, "battery_state", s_battery_status); | ||||
|     nvs_close(nvs_handle); | ||||
| } | ||||
|  | ||||
| static void s_zh_send_sensor_attributes_message(void) | ||||
| { | ||||
|     const esp_app_desc_t *app_info = esp_app_get_description(); | ||||
|     zh_attributes_message_t attributes_message = {0}; | ||||
|     attributes_message.chip_type = HACHT_ESP32; | ||||
|     strcpy(attributes_message.flash_size, CONFIG_ESPTOOLPY_FLASHSIZE); | ||||
|     attributes_message.cpu_frequency = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ; | ||||
|     attributes_message.reset_reason = (uint8_t)esp_reset_reason(); | ||||
|     strcpy(attributes_message.app_name, app_info->project_name); | ||||
|     strcpy(attributes_message.app_version, app_info->version); | ||||
|     zh_espnow_data_t data = {0}; | ||||
|     data.device_type = ZHDT_BINARY_SENSOR; | ||||
|     data.payload_type = ZHPT_ATTRIBUTES; | ||||
|     attributes_message.heap_size = esp_get_free_heap_size(); | ||||
|     attributes_message.min_heap_size = esp_get_minimum_free_heap_size(); | ||||
|     attributes_message.uptime = esp_timer_get_time() / 1000000; | ||||
|     data.payload_data = (zh_payload_data_t)attributes_message; | ||||
|     zh_espnow_send(NULL, (uint8_t *)&data, sizeof(zh_espnow_data_t)); | ||||
| } | ||||
|  | ||||
| static void s_zh_send_sensor_config_message(void) | ||||
| { | ||||
|     zh_binary_sensor_config_message_t binary_sensor_config_message = {0}; | ||||
|     binary_sensor_config_message.unique_id = 1; | ||||
|     binary_sensor_config_message.binary_sensor_device_class = (s_sensor_type == HAST_WINDOW) ? HABSDC_WINDOW : HABSDC_DOOR; | ||||
|     binary_sensor_config_message.payload_on = HAONOFT_OPEN; | ||||
|     binary_sensor_config_message.payload_off = HAONOFT_CLOSE; | ||||
|     binary_sensor_config_message.enabled_by_default = true; | ||||
|     binary_sensor_config_message.force_update = true; | ||||
|     binary_sensor_config_message.qos = 2; | ||||
|     binary_sensor_config_message.retain = true; | ||||
|     zh_config_message_t config_message = {0}; | ||||
|     config_message = (zh_config_message_t)binary_sensor_config_message; | ||||
|     zh_espnow_data_t data = {0}; | ||||
|     data.device_type = ZHDT_BINARY_SENSOR; | ||||
|     data.payload_type = ZHPT_CONFIG; | ||||
|     data.payload_data = (zh_payload_data_t)config_message; | ||||
|     zh_espnow_send(NULL, (uint8_t *)&data, sizeof(zh_espnow_data_t)); | ||||
|     binary_sensor_config_message.unique_id = 2; | ||||
|     binary_sensor_config_message.binary_sensor_device_class = HABSDC_BATTERY; | ||||
|     binary_sensor_config_message.payload_on = HAONOFT_LOW; | ||||
|     binary_sensor_config_message.payload_off = HAONOFT_HIGH; | ||||
|     config_message = (zh_config_message_t)binary_sensor_config_message; | ||||
|     data.payload_data = (zh_payload_data_t)config_message; | ||||
|     zh_espnow_send(NULL, (uint8_t *)&data, sizeof(zh_espnow_data_t)); | ||||
| } | ||||
|  | ||||
| static void s_zh_send_sensor_status_message(void) | ||||
| { | ||||
|     zh_binary_sensor_status_message_t binary_sensor_status_message = {0}; | ||||
|     binary_sensor_status_message.sensor_type = s_sensor_type; | ||||
|     binary_sensor_status_message.open = s_open_status; | ||||
|     binary_sensor_status_message.battery = s_battery_status; | ||||
|     zh_status_message_t status_message = {0}; | ||||
|     status_message = (zh_status_message_t)binary_sensor_status_message; | ||||
|     zh_espnow_data_t data = {0}; | ||||
|     data.device_type = ZHDT_BINARY_SENSOR; | ||||
|     data.payload_type = ZHPT_STATE; | ||||
|     data.payload_data = (zh_payload_data_t)status_message; | ||||
|     zh_espnow_send(NULL, (uint8_t *)&data, sizeof(zh_espnow_data_t)); | ||||
| } | ||||
|  | ||||
| static void s_zh_espnow_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) | ||||
| { | ||||
|     const esp_app_desc_t *app_info = esp_app_get_description(); | ||||
|     zh_espnow_data_t data_in = {0}; | ||||
|     zh_espnow_data_t data_out = {0}; | ||||
|     zh_espnow_ota_message_t espnow_ota_message = {0}; | ||||
|     data_out.device_type = ZHDT_BINARY_SENSOR; | ||||
|     espnow_ota_message.chip_type = HACHT_ESP32; | ||||
|     data_out.payload_data = (zh_payload_data_t)espnow_ota_message; | ||||
|     switch (event_id) | ||||
|     { | ||||
|     case ZH_ESPNOW_ON_RECV_EVENT:; | ||||
|         zh_espnow_event_on_recv_t *recv_data = event_data; | ||||
|         if (recv_data->data_len != sizeof(zh_espnow_data_t)) | ||||
|         { | ||||
|             goto ZH_ESPNOW_EVENT_HANDLER_EXIT; | ||||
|         } | ||||
|         memcpy(&data_in, recv_data->data, recv_data->data_len); | ||||
|         switch (data_in.device_type) | ||||
|         { | ||||
|         case ZHDT_GATEWAY: | ||||
|             if (s_gateway_is_available == false) | ||||
|             { | ||||
|                 s_gateway_is_available = true; | ||||
|                 memcpy(s_gateway_mac, recv_data->mac_addr, 6); | ||||
|             } | ||||
|             switch (data_in.payload_type) | ||||
|             { | ||||
|             case ZHPT_UPDATE: | ||||
|                 s_update_partition = esp_ota_get_next_update_partition(NULL); | ||||
|                 strcpy(espnow_ota_message.app_name, app_info->project_name); | ||||
|                 strcpy(espnow_ota_message.app_version, app_info->version); | ||||
|                 data_out.payload_type = ZHPT_UPDATE; | ||||
|                 data_out.payload_data = (zh_payload_data_t)espnow_ota_message; | ||||
|                 zh_espnow_send(s_gateway_mac, (uint8_t *)&data_out, sizeof(zh_espnow_data_t)); | ||||
|                 break; | ||||
|             case ZHPT_UPDATE_BEGIN: | ||||
|                 esp_ota_begin(s_update_partition, OTA_SIZE_UNKNOWN, &s_update_handle); | ||||
|                 s_ota_message_part_number = 1; | ||||
|                 break; | ||||
|             case ZHPT_UPDATE_PROGRESS: | ||||
|                 if (s_ota_message_part_number == data_in.payload_data.espnow_ota_message.part) | ||||
|                 { | ||||
|                     ++s_ota_message_part_number; | ||||
|                     esp_ota_write(s_update_handle, (const void *)data_in.payload_data.espnow_ota_message.data, data_in.payload_data.espnow_ota_message.data_len); | ||||
|                 } | ||||
|                 data_out.payload_type = ZHPT_UPDATE_PROGRESS; | ||||
|                 zh_espnow_send(s_gateway_mac, (uint8_t *)&data_out, sizeof(zh_espnow_data_t)); | ||||
|                 break; | ||||
|             case ZHPT_UPDATE_ERROR: | ||||
|                 esp_ota_end(s_update_handle); | ||||
|                 break; | ||||
|             case ZHPT_UPDATE_END: | ||||
|                 if (esp_ota_end(s_update_handle) != ESP_OK) | ||||
|                 { | ||||
|                     data_out.payload_type = ZHPT_UPDATE_FAIL; | ||||
|                     zh_espnow_send(s_gateway_mac, (uint8_t *)&data_out, sizeof(zh_espnow_data_t)); | ||||
|                     break; | ||||
|                 } | ||||
|                 esp_ota_set_boot_partition(s_update_partition); | ||||
|                 data_out.payload_type = ZHPT_UPDATE_SUCCESS; | ||||
|                 zh_espnow_send(s_gateway_mac, (uint8_t *)&data_out, sizeof(zh_espnow_data_t)); | ||||
|                 vTaskDelay(1000 / portTICK_PERIOD_MS); | ||||
|                 esp_restart(); | ||||
|                 break; | ||||
|             default: | ||||
|                 break; | ||||
|             } | ||||
|             break; | ||||
|         default: | ||||
|             break; | ||||
|         } | ||||
|     ZH_ESPNOW_EVENT_HANDLER_EXIT: | ||||
|         free(recv_data->data); | ||||
|         break; | ||||
|     case ZH_ESPNOW_ON_SEND_EVENT: | ||||
|         break; | ||||
|     default: | ||||
|         break; | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user