From: jweigele Date: Mon, 17 Jul 2023 18:57:21 +0000 (-0700) Subject: Uptime reporting, bugfixes in zigbee erase, and optional router caps X-Git-Url: http://git.hexthepla.net/?a=commitdiff_plain;h=7f8a2ac852bc2c7b4860ed43557d4c0edd6867ac;p=esp32projects Uptime reporting, bugfixes in zigbee erase, and optional router caps --- diff --git a/aqi/main/aqi.c b/aqi/main/aqi.c index 3a71a89..43c4514 100644 --- a/aqi/main/aqi.c +++ b/aqi/main/aqi.c @@ -19,13 +19,6 @@ #include "ha/esp_zigbee_ha_standard.h" #include "aqi.h" -/** - * @note Make sure set idf.py menuconfig in zigbee component as zigbee end device! -*/ -#if !defined ZB_ED_ROLE -#error Define ZB_ED_ROLE in idf.py menuconfig to compile light (End Device) source code. -#endif - typedef struct aqi_data_s { float pm10; float pm25; @@ -33,6 +26,9 @@ typedef struct aqi_data_s { static QueueHandle_t event_queue; +// for tracking and reporting device uptime +static uint32_t device_uptime_seconds = 0; + #ifdef CONFIG_TEMP_ENABLED static int tempbuffer[TEMPBUFFERSIZE]; @@ -78,6 +74,46 @@ static aqi_data_t pmbuffer[PMBUFFERSIZE]; static int pmbufferindex = 0; +// this function checks for signal on a designated "reset" pin, +// then erases both data partitions, sets the LED to indicate success, +// and reboots after a delay +void erase_data_hook(void){ + ESP_LOGI(TAG, "checking pin %d for erase status", CONFIG_GPIO_ERASE_PIN); + gpio_set_pull_mode(CONFIG_GPIO_ERASE_PIN, GPIO_PULLDOWN_ONLY); + gpio_set_direction(CONFIG_GPIO_ERASE_PIN, GPIO_MODE_INPUT); + int erase_status = gpio_get_level(CONFIG_GPIO_ERASE_PIN); + if (erase_status == 1){ + // we gotta have high priority for our blinking +#ifdef CONFIG_INDICATOR_ENABLED + xTaskCreate(blink_that_shit, "blink_that_shit", 2048, NULL, 9, NULL); +#endif + ESP_LOGW(TAG, "would erase flash here!!!"); + // we don't want to erase a factory partition since it also contains the apps + if (strcmp(CONFIG_NVS_WIFI_PARTITION, "factory") != 0){ + ESP_LOGW(TAG, "erasing wifi partition at %s", CONFIG_NVS_WIFI_PARTITION); + ESP_ERROR_CHECK(nvs_flash_erase_partition(CONFIG_NVS_WIFI_PARTITION)); + } else { + ESP_LOGW(TAG, "cannot erase wifi partition because it's the same as the app partition :("); + // make it blink worse + way_too_funky = true; + } + +#ifdef CONFIG_ZIG_ENABLED + // we call the zigbee code directly so this needs no check + ESP_LOGW(TAG, "erasing zigbee settings by calling function"); + esp_zb_factory_reset(); +#endif + ESP_LOGI(TAG, "waiting 10 seconds then restarting"); + // if you didn't have zigbee running, this takes care of the restart + vTaskDelay( pdMS_TO_TICKS(10000) ); + esp_restart(); + } else { + ESP_LOGI(TAG, "erase pin not set, continuing boot"); + } +} + + + #ifdef CONFIG_ZIG_ENABLED typedef struct zdo_info_ctx_s { uint8_t endpoint; @@ -276,6 +312,7 @@ static void send_report_wifi(uint16_t pm10, uint16_t pm25, float aqi, uint16_t t cJSON_AddNumberToObject(root, "pm10", ((float)pm10/100)); cJSON_AddNumberToObject(root, "pm25", ((float)pm25/100)); cJSON_AddNumberToObject(root, "aqi", aqi); + cJSON_AddNumberToObject(root, "uptime", device_uptime_seconds); #ifdef CONFIG_TEMP_ENABLED cJSON_AddNumberToObject(root, "temperature", ((float)temperature/100)); #endif @@ -391,7 +428,7 @@ static void monitoring_task(void* discard) int length = 0; #ifdef CONFIG_WIFI_ENABLED esp_mqtt_client_handle_t queue_item; -#endif +#endif for(;;){ #ifdef CONFIG_WIFI_ENABLED @@ -404,6 +441,10 @@ static void monitoring_task(void* discard) ESP_LOGI(TAG, "free heap: %"PRIu32, esp_get_free_heap_size()); + // first things first (function gives microseconds, just convert to seconds) + // 32 bits is enough for >50 years and zigbee stack gets mad if we use more bits + device_uptime_seconds = (uint32_t)(esp_timer_get_time()/1000000); + // aqi fetch/calculation/report ESP_ERROR_CHECK(uart_get_buffered_data_len(UART_NUM_1, (size_t*)&length)); const int rxBytes = uart_read_bytes(UART_NUM_1, data, length, 100); @@ -429,6 +470,10 @@ static void monitoring_task(void* discard) PM25MEASURED, &set_pm25, false); send_report_zig(PM10CLUSTER, PM10MEASURED); send_report_zig(PM25CLUSTER, PM25MEASURED); + // reasonable place to do it since this is the one universal measurement block for zigbee + esp_zb_zcl_set_attribute_val(HA_ESP_ENDPOINT, UPTIMECLUSTER, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, + UPTIMEID, &device_uptime_seconds, false); + send_report_zig(UPTIMECLUSTER, UPTIMEID); } #endif } else { @@ -548,6 +593,12 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) static void esp_zb_task(void *pvParameters) { + if (ZB_TYPE == ESP_ZB_DEVICE_TYPE_ROUTER){ + ESP_LOGI(TAG, "entered esp_zb_task, zb_type is router"); + } else { + ESP_LOGI(TAG, "entered esp_zb_task, zb_type is end device"); + } + /* initialize Zigbee stack with Zigbee end-device config */ esp_zb_cfg_t zb_nwk_cfg = ESP_ZB_ZED_CONFIG(); esp_zb_init(&zb_nwk_cfg); @@ -568,6 +619,10 @@ static void esp_zb_task(void *pvParameters) /* identify cluster create with fully customized */ esp_zb_attribute_list_t *esp_zb_identify_cluster = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_IDENTIFY); + + esp_zb_attribute_list_t *esp_zb_uptime_cluster = esp_zb_zcl_attr_list_create(UPTIMECLUSTER); + ESP_ERROR_CHECK(esp_zb_custom_cluster_add_custom_attr(esp_zb_uptime_cluster, UPTIMEID, ESP_ZB_ZCL_ATTR_TYPE_U32, ESP_ZB_ZCL_ATTR_ACCESS_READ_ONLY | ESP_ZB_ZCL_ATTR_ACCESS_REPORTING, &device_uptime_seconds)); + uint16_t initial_pm10 = 0; uint16_t initial_pm25 = 0; @@ -575,12 +630,12 @@ static void esp_zb_task(void *pvParameters) esp_zb_attribute_list_t *esp_zb_pm25_cluster = esp_zb_zcl_attr_list_create(PM25CLUSTER); ESP_ERROR_CHECK(esp_zb_custom_cluster_add_custom_attr(esp_zb_pm25_cluster, PM25MEASURED, ESP_ZB_ZCL_ATTR_TYPE_U16, ESP_ZB_ZCL_ATTR_ACCESS_READ_ONLY | ESP_ZB_ZCL_ATTR_ACCESS_REPORTING, &initial_pm25)); ESP_ERROR_CHECK(esp_zb_custom_cluster_add_custom_attr(esp_zb_pm25_cluster, PM10MEASURED, ESP_ZB_ZCL_ATTR_TYPE_U16, ESP_ZB_ZCL_ATTR_ACCESS_READ_ONLY | ESP_ZB_ZCL_ATTR_ACCESS_REPORTING, &initial_pm10)); - /* create cluster lists for this endpoint */ esp_zb_cluster_list_t *esp_zb_cluster_list = esp_zb_zcl_cluster_list_create(); esp_zb_cluster_list_add_basic_cluster(esp_zb_cluster_list, esp_zb_basic_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); esp_zb_cluster_list_add_identify_cluster(esp_zb_cluster_list, esp_zb_identify_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); + #ifdef CONFIG_TEMP_ENABLED short min_temp = MIN_TEMP_VALUE; short max_temp = MAX_TEMP_VALUE; @@ -593,7 +648,8 @@ static void esp_zb_task(void *pvParameters) esp_zb_cluster_list_add_temperature_meas_cluster(esp_zb_cluster_list, esp_zb_temp_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE); #endif - + + ESP_ERROR_CHECK(esp_zb_cluster_list_add_custom_cluster(esp_zb_cluster_list, esp_zb_uptime_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE)); ESP_ERROR_CHECK(esp_zb_cluster_list_add_custom_cluster(esp_zb_cluster_list, esp_zb_pm25_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE)); @@ -603,6 +659,7 @@ static void esp_zb_task(void *pvParameters) esp_zb_device_register(esp_zb_ep_list); ESP_ERROR_CHECK(esp_zb_start(false)); + erase_data_hook(); //ESP_ERROR_CHECK(esp_zb_secur_ic_set(ESP_ZB_IC_TYPE_128, (uint8_t*)curic)); ESP_LOGI(TAG, "main loop begin"); @@ -774,40 +831,6 @@ void blink_that_shit_funkay(void* discard){ } } -// this function checks for signal on a designated "reset" pin, -// then erases both data partitions, sets the LED to indicate success, -// and reboots after a delay -void erase_data_hook(void){ - gpio_set_pull_mode(CONFIG_GPIO_ERASE_PIN, GPIO_PULLDOWN_ONLY); - gpio_set_direction(CONFIG_GPIO_ERASE_PIN, GPIO_MODE_INPUT); - int erase_status = gpio_get_level(CONFIG_GPIO_ERASE_PIN); - if (erase_status == 1){ - // we gotta have high priority for our blinking - xTaskCreate(blink_that_shit, "blink_that_shit", 2048, NULL, 9, NULL); - ESP_LOGW(TAG, "would erase flash here!!!"); - // we don't want to erase a factory partition since it also contains the apps - if (strcmp(CONFIG_NVS_WIFI_PARTITION, "factory") != 0){ - ESP_LOGW(TAG, "erasing wifi partition at %s", CONFIG_NVS_WIFI_PARTITION); - ESP_ERROR_CHECK(nvs_flash_erase_partition(CONFIG_NVS_WIFI_PARTITION)); - } else { - ESP_LOGE(TAG, "cannot erase wifi partition because it's the same as the app partition :("); - // make it blink worse - way_too_funky = true; - } - -#ifdef CONFIG_ZIG_ENABLED - // we call the zigbee code directly so this needs no check - esp_zb_factory_reset(); -#endif - // if you didn't have zigbee running, this takes care of the restart - vTaskDelay( pdMS_TO_TICKS(10000) ); - esp_restart(); - } else { - ESP_LOGI(TAG, "erase pin not set, continuing boot"); - } -} - - #ifdef CONFIG_INDICATOR_ENABLED // simple and cheap, just nerfs the total color values in the lookup table once at boot void adjust_color_lookup_brightness(float multiplier){ @@ -829,9 +852,13 @@ void app_main(void) light_driver_init(LIGHT_DEFAULT_OFF); #endif - +// if it's zigbee enabled, we need to actually start zb +// before calling this (added directly in task later) +#ifndef CONFIG_ZIG_ENABLED + ESP_LOGI(TAG, "no zigbee, calling erase hook early"); // check for erasing data partitions erase_data_hook(); +#endif #ifdef CONFIG_INDICATOR_ENABLED adjust_color_lookup_brightness(AQI_INDICATOR_BRIGHTNESS); diff --git a/aqi/main/aqi.h b/aqi/main/aqi.h index 44c1db8..9f06232 100644 --- a/aqi/main/aqi.h +++ b/aqi/main/aqi.h @@ -1,16 +1,4 @@ -/* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: CC0-1.0 - * - * Zigbee HA_color_dimmable_light Example - * - * This example code is in the Public Domain (or CC0 licensed, at your option.) - * - * Unless required by applicable law or agreed to in writing, this - * software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. - */ +#include "esp_timer.h" #ifdef CONFIG_ZIG_ENABLED #include "esp_zigbee_core.h" @@ -84,8 +72,9 @@ static const char *TAG = "aqi"; #define PM10MEASURED 0x0000 #define PM25MEASURED 0x0001 -#define TEMP_REPORT 0x1 -#define PM25_REPORT 0x2 +#define UPTIMECLUSTER 0xFFFD +#define UPTIMEID 0x0000 + #endif @@ -131,15 +120,27 @@ static void mqtt_reinit(); /* Zigbee configuration */ #define INSTALLCODE_POLICY_ENABLE false /* enable the install code policy for security */ #define ED_AGING_TIMEOUT ESP_ZB_ED_AGING_TIMEOUT_64MIN -#define ED_KEEP_ALIVE 3000 /* 3000 millisecond */ -#define HA_ESP_ENDPOINT 1 -#define ESP_ZB_PRIMARY_CHANNEL_MASK ESP_ZB_TRANSCEIVER_ALL_CHANNELS_MASK /* Zigbee primary channel mask use in the example */ -//specifically search channel 15, which is what I'm on -//#define ESP_ZB_PRIMARY_CHANNEL_MASK 1l<<15 +// router or endpoint + + +// auto chooses the correct configuration based upon your menuconfig selection +#ifdef CONFIG_ZB_ZCZR +#define ZB_TYPE ESP_ZB_DEVICE_TYPE_ROUTER +#define MAX_CHILDREN 10 +#define ESP_ZB_ZED_CONFIG() \ + { \ + .esp_zb_role = ZB_TYPE, \ + .install_code_policy = INSTALLCODE_POLICY_ENABLE, \ + .nwk_cfg.zczr_cfg = { \ + .max_children = MAX_CHILDREN, \ + }, \ + } +#elif CONFIG_ZB_ED +#define ZB_TYPE ESP_ZB_DEVICE_TYPE_ED #define ESP_ZB_ZED_CONFIG() \ { \ - .esp_zb_role = ESP_ZB_DEVICE_TYPE_ED, \ + .esp_zb_role = ZB_TYPE, \ .install_code_policy = INSTALLCODE_POLICY_ENABLE, \ .nwk_cfg.zed_cfg = { \ .ed_timeout = ED_AGING_TIMEOUT, \ @@ -147,6 +148,14 @@ static void mqtt_reinit(); }, \ } +#endif + +#define ED_KEEP_ALIVE 3000 /* 3000 millisecond */ +#define HA_ESP_ENDPOINT 1 +#define ESP_ZB_PRIMARY_CHANNEL_MASK ESP_ZB_TRANSCEIVER_ALL_CHANNELS_MASK /* Zigbee primary channel mask use in the example */ +//specifically search channel 15, which is what I'm on +//#define ESP_ZB_PRIMARY_CHANNEL_MASK 1l<<15 + #define ESP_ZB_DEFAULT_RADIO_CONFIG() \ { \ .radio_mode = RADIO_MODE_NATIVE, \ diff --git a/aqi/sdkconfig b/aqi/sdkconfig index 789b746..c66ebfd 100644 --- a/aqi/sdkconfig +++ b/aqi/sdkconfig @@ -1637,7 +1637,7 @@ CONFIG_ZIG_ENABLED=y # CONFIG_INDICATOR_ENABLED is not set CONFIG_BROKER_URL="mqtts://esp32:sensorauth@rabbitmq.hexthepla.net" CONFIG_LOCATION="ESP32 babyyy" -CONFIG_GPIO_ERASE_PIN=14 +CONFIG_GPIO_ERASE_PIN=25 # end of AQI Program Configuration # @@ -1669,8 +1669,8 @@ CONFIG_DEFAULT_AP_BEACON_INTERVAL=100 # Zigbee # CONFIG_ZB_ENABLED=y -# CONFIG_ZB_ZCZR is not set -CONFIG_ZB_ZED=y +CONFIG_ZB_ZCZR=y +# CONFIG_ZB_ZED is not set # CONFIG_ZB_RCP is not set CONFIG_ZB_RADIO_NATIVE=y # CONFIG_ZB_RADIO_MACSPLIT_UART is not set