From 37c8723f8bdd2991bed0c0f66aa67af26d2dc5cb Mon Sep 17 00:00:00 2001 From: jweigele Date: Mon, 19 Feb 2024 13:39:56 -0800 Subject: [PATCH] a few moderate changes Features: * Support version string emission, once per hour to esp32/sensor_version * Set every PWM LED GPIO invididually if it's != -1 (now supports all 6 channels) Bugfix: * Never sleep negative time if you waited too long already (which since it's a uint I think just becomes very positive and sleeps almost forever) Ehh: * Some attempted changes around repolling and rechecking motion settings * Pull-down back to enabled because we're using the big PIR sensors * Hysteresis enabled to prevent spamming of the channel --- aqi/dependencies.lock | 2 +- aqi/main/aqi.c | 227 ++++++++++++++++++++++++++++++------------ aqi/main/aqi.h | 2 + aqi/sdkconfig | 20 ++-- 4 files changed, 179 insertions(+), 72 deletions(-) diff --git a/aqi/dependencies.lock b/aqi/dependencies.lock index 03a995e..fd71409 100644 --- a/aqi/dependencies.lock +++ b/aqi/dependencies.lock @@ -10,6 +10,6 @@ dependencies: source: type: idf version: 5.2.0 -manifest_hash: 9370ef27f76f2bf2bf1ebd1e72c5af82f7b264148974987baedcb874f8fab004 +manifest_hash: fe84d3cba19d4dc50bbd18a9bed2d19eaa863b4be82668f06a4725d7b974e0c1 target: esp32h2 version: 1.0.0 diff --git a/aqi/main/aqi.c b/aqi/main/aqi.c index 1be28f0..148f068 100644 --- a/aqi/main/aqi.c +++ b/aqi/main/aqi.c @@ -48,6 +48,7 @@ typedef struct pwm_data_s { } pwm_data_t; #endif + typedef struct report_data_s { #ifdef CONFIG_UART_ENABLED uint16_t pm10; @@ -69,9 +70,16 @@ typedef struct report_data_s { static temperature_sensor_handle_t temp_handle; static QueueHandle_t event_queue; static QueueHandle_t send_queue; +static QueueHandle_t version_queue; + +static esp_app_desc_t app_desc; +static char mac_string[12 + 1]; +static char ext_string[16 + 1]; #if defined(CONFIG_MOTION_FIRST_ENABLED) || defined(CONFIG_MOTION_SECOND_ENABLED) +static uint32_t squelch_time = 0; static QueueHandle_t motion_queue; +static QueueHandle_t off_queue; static QueueHandle_t check_queue; static int prev_motion[2] = {0, 0}; @@ -301,6 +309,9 @@ static void create_config_network(otInstance *instance) memcpy(otExt, otLinkGetExtendedAddress(instance), 8); + sprintf(ext_string, "%02x%02x%02x%02x%02x%02x%02x%02x", + otExt[0], otExt[1], otExt[2], otExt[3], otExt[4], otExt[5], otExt[6], otExt[7]); + /* Start the Thread network interface (CLI cmd > ifconfig up) */ otIp6SetEnabled(instance, true); @@ -363,19 +374,15 @@ static void ot_task_worker(void *aContext) //esp_err_t err_netif = esp_netif_get_mac(openthread_netif, ot_mac); esp_err_t err_netif = esp_base_mac_addr_get(ot_mac); + sprintf(mac_string, "%02x%02x%02x%02x%02x%02x", + ot_mac[0], ot_mac[1], ot_mac[2], ot_mac[3], ot_mac[4], ot_mac[5]); ESP_LOGE(TAG, "error status is %s", esp_err_to_name(err_netif)); - ESP_LOG_BUFFER_HEXDUMP(TAG, ot_mac, 6, ESP_LOG_INFO); + ESP_LOGI(TAG, "mac address is %s", mac_string); esp_openthread_lock_release(); - //while (true) { - // Run the main loop esp_err_t err = esp_openthread_launch_mainloop(); ESP_LOGE(TAG, "Error somewhere in openthread loop %s.", esp_err_to_name(err)); - // vTaskDelay( pdMS_TO_TICKS(10000) ); - - //} - // Clean up esp_netif_destroy(openthread_netif); @@ -621,11 +628,44 @@ void init_uart(void) { uart_set_pin(UART_NUM_1, UART_TX_GPIO, UART_RX_GPIO, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); } +static void version_task(void* discard){ + // give 5 seconds before starting, just to allow all network vars to be populated + vTaskDelay( pdMS_TO_TICKS(5000) ); + + for (;;){ + cJSON *root; + root = cJSON_CreateObject(); + cJSON_AddStringToObject(root, "app_version", app_desc.version); + cJSON_AddStringToObject(root, "idf_version", app_desc.idf_ver); + cJSON_AddStringToObject(root, "mac", mac_string); +#ifdef CONFIG_OT_ENABLED + cJSON_AddStringToObject(root, "ext", ext_string); +#endif + cJSON_AddStringToObject(root, "location", CONFIG_LOCATION); + char *mqtt_string = cJSON_Print(root); + xQueueSend(version_queue, &mqtt_string, portMAX_DELAY); + cJSON_Delete(root); + + // wait an hour, then send again + vTaskDelay( pdMS_TO_TICKS(3600000) ); + } +} + + static void send_task(void* discard){ char* mqtt_string = ""; //NULL; bool last_sent = false; for(;;){ + // version string queue -> send on mqtt + if (netif_connected == true && mqtt_connected == true){ + if (xQueueReceive(version_queue, &mqtt_string, 0 )){ + ESP_LOGI(TAG, "sending version string:\n%s",mqtt_string); + int msg_id = esp_mqtt_client_publish(mqtt_client, "esp32/version_info", mqtt_string, 0, 1, 0); + ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id); + free(mqtt_string); + } + } // receive an event we need to deal with from elsewhere, right now just reconnect related if (xQueueReceive(send_queue, &mqtt_string, portMAX_DELAY )){ last_sent = true; @@ -652,8 +692,11 @@ static void send_task(void* discard){ #if defined(CONFIG_WIFI_ENABLED) || defined(CONFIG_OT_ENABLED) +#if defined(CONFIG_MOTION_FIRST_ENABLED) || defined(CONFIG_MOTION_SECOND_ENABLED) static void send_report_motion(bool motion){ xSemaphoreTake(report_data.mutex, portMAX_DELAY); + report_data.motion = motion; + xSemaphoreGive(report_data.mutex); ESP_LOGI(TAG, "send_report_motion was called!"); cJSON *root; @@ -663,10 +706,9 @@ static void send_report_motion(bool motion){ char *mqtt_string = cJSON_Print(root); xQueueSend(send_queue, &mqtt_string, portMAX_DELAY); cJSON_Delete(root); - - xSemaphoreGive(report_data.mutex); } +#endif // CONFIG_MOTION_ENABLED static void send_report_wifi(report_data_t report_data){ xSemaphoreTake(report_data.mutex, portMAX_DELAY); @@ -702,7 +744,7 @@ static void send_report_wifi(report_data_t report_data){ } -#endif +#endif // wifi or ot enabled bool verify_checksum(uint8_t* data){ int total = 0; @@ -826,31 +868,57 @@ static void pwm_task(void* discard){ // Prepare and then apply the LEDC PWM channel configuration ledc_channel_config_t ledc_channel = { .speed_mode = LEDC_MODE, - .channel = R1_CHANNEL, + .channel = LEDC_CHANNEL_0, .timer_sel = LEDC_TIMER, .intr_type = LEDC_INTR_DISABLE, - .gpio_num = CONFIG_PWM_R1_GPIO, + .gpio_num = 0, .duty = 0, // Set duty to 0% .hpoint = 0 }; - ESP_LOGI(TAG, "configuring R1 PWM"); - ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel)); - ledc_channel.channel = G1_CHANNEL; - ledc_channel.gpio_num = CONFIG_PWM_G1_GPIO; + if (CONFIG_PWM_R1_GPIO != -1){ + ledc_channel.channel = R1_CHANNEL; + ledc_channel.gpio_num = CONFIG_PWM_R1_GPIO; + ESP_LOGI(TAG, "configuring R1 PWM"); + ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel)); + } - ESP_LOGI(TAG, "configuring G1 PWM"); - ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel)); + if (CONFIG_PWM_G1_GPIO != -1){ + ledc_channel.channel = G1_CHANNEL; + ledc_channel.gpio_num = CONFIG_PWM_G1_GPIO; + ESP_LOGI(TAG, "configuring G1 PWM"); + ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel)); + } - ledc_channel.channel = B1_CHANNEL; - ledc_channel.gpio_num = CONFIG_PWM_B1_GPIO; - - ESP_LOGI(TAG, "configuring B1 PWM"); - ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel)); + if (CONFIG_PWM_B1_GPIO != -1){ + ledc_channel.channel = B1_CHANNEL; + ledc_channel.gpio_num = CONFIG_PWM_B1_GPIO; + ESP_LOGI(TAG, "configuring B1 PWM"); + ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel)); + } + + + if (CONFIG_PWM_R2_GPIO != -1){ + ledc_channel.channel = R2_CHANNEL; + ledc_channel.gpio_num = CONFIG_PWM_R2_GPIO; + ESP_LOGI(TAG, "configuring R2 PWM"); + ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel)); + } + if (CONFIG_PWM_G2_GPIO != -1){ + ledc_channel.channel = G2_CHANNEL; + ledc_channel.gpio_num = CONFIG_PWM_G2_GPIO; + ESP_LOGI(TAG, "configuring G2 PWM"); + ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel)); + } - + if (CONFIG_PWM_B2_GPIO != -1){ + ledc_channel.channel = B2_CHANNEL; + ledc_channel.gpio_num = CONFIG_PWM_B2_GPIO; + ESP_LOGI(TAG, "configuring B2 PWM"); + ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel)); + } @@ -933,19 +1001,49 @@ static void pwm_task(void* discard){ ESP_LOGI(TAG, "red duty float calculated as %02f, int %d", red_duty_float, red_duty_int); - ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, R1_CHANNEL, red_duty_int)); - // Update duty to apply the new value - ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, R1_CHANNEL)); - - ESP_LOGI(TAG, "green duty floatcalculated as %02f, int %d", green_duty_float, green_duty_int); - ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, G1_CHANNEL, green_duty_int)); - // Update duty to apply the new value - ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, G1_CHANNEL)); + + if (CONFIG_PWM_R1_GPIO != -1){ + ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, R1_CHANNEL, red_duty_int)); + // Update duty to apply the new value + ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, R1_CHANNEL)); + } + + if (CONFIG_PWM_R2_GPIO != -1){ + ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, R2_CHANNEL, red_duty_int)); + // Update duty to apply the new value + ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, R2_CHANNEL)); + } + + + ESP_LOGI(TAG, "green duty float calculated as %02f, int %d", green_duty_float, green_duty_int); + + if (CONFIG_PWM_G1_GPIO != -1){ + ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, G1_CHANNEL, green_duty_int)); + // Update duty to apply the new value + ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, G1_CHANNEL)); + } + + if (CONFIG_PWM_G2_GPIO != -1){ + ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, G2_CHANNEL, green_duty_int)); + // Update duty to apply the new value + ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, G2_CHANNEL)); + } + ESP_LOGI(TAG, "blue duty float calculated as %02f, int %d", blue_duty_float, blue_duty_int); - ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, B1_CHANNEL, blue_duty_int)); - // Update duty to apply the new value - ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, B1_CHANNEL)); + + if (CONFIG_PWM_B1_GPIO != -1){ + ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, B1_CHANNEL, blue_duty_int)); + // Update duty to apply the new value + ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, B1_CHANNEL)); + } + + if (CONFIG_PWM_B2_GPIO != -1){ + ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, B2_CHANNEL, blue_duty_int)); + // Update duty to apply the new value + ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, B2_CHANNEL)); + } + } else { ESP_LOGE(TAG, "failed to parse json successfully!"); @@ -972,24 +1070,21 @@ static void check_motion(void* discard){ if(xQueueReceive(check_queue, &io_num, portMAX_DELAY)) { #ifdef CONFIG_MOTION_RECHECK // check after this much time - vTaskDelay( pdMS_TO_TICKS(MOTION_SLEEP_MS) ); + for (int i = 0; i < 300; i++){ + vTaskDelay( pdMS_TO_TICKS(10) ); + gpio_get_level(io_num); + } // recheck the GPIO to see if it's still active (i.e. not a blip) int current_value = gpio_get_level(io_num); if ( current_value == 1 ){ - xSemaphoreTake(report_data.mutex, portMAX_DELAY); - report_data.motion = true; ESP_LOGI(TAG, "recheck verified motion, on pin %"PRIu32" sending!", io_num); - xSemaphoreGive(report_data.mutex); - send_report_motion(report_data.motion); + send_report_motion(true); } else { ESP_LOGW(TAG, "recheck came back false on pin %"PRIu32", ignoring as BLIP!!", io_num); } #else - xSemaphoreTake(report_data.mutex, portMAX_DELAY); - report_data.motion = true; - xSemaphoreGive(report_data.mutex); - send_report_motion(report_data.motion); + send_report_motion(true); #endif } @@ -1018,8 +1113,9 @@ static void motion_task(void* discard){ //set as input mode io_conf.mode = GPIO_MODE_INPUT; //enable pull-down mode - io_conf.pull_down_en = 0; + io_conf.pull_down_en = 1; io_conf.pull_up_en = 0; + io_conf.hys_ctrl_mode = GPIO_HYS_SOFT_ENABLE; gpio_config(&io_conf); //change gpio interrupt type for one pin @@ -1032,8 +1128,10 @@ static void motion_task(void* discard){ //create a queue to handle gpio event from isr - motion_queue = xQueueCreate(10, sizeof(uint32_t)); - check_queue = xQueueCreate(10, sizeof(uint32_t)); + motion_queue = xQueueCreate(100, sizeof(uint32_t)); + off_queue = xQueueCreate(100, sizeof(uint32_t)); + check_queue = xQueueCreate(100, sizeof(uint32_t)); + //install gpio isr service @@ -1054,35 +1152,31 @@ static void motion_task(void* discard){ ESP_LOGI(TAG, "waiting for motion events"); for(;;) { if(xQueueReceive(motion_queue, &io_num, portMAX_DELAY)) { - // Take the mutex - xSemaphoreTake(report_data.mutex, portMAX_DELAY); int pin_value = gpio_get_level(io_num); - printf("GPIO[%"PRIu32"] intr, val: %d\n", io_num, pin_value); + ESP_LOGI(TAG, "GPIO[%"PRIu32"] intr, val: %d\n", io_num, pin_value); + uint32_t squelch_uptime; switch (io_num) { case CONFIG_MOTION_FIRST_PIN: prev_motion[0] = motion_pins[0]; motion_pins[0] = pin_value; - if ( motion_pins[0] == true && prev_motion[0] == false ){ - xQueueSend(check_queue, &io_num, portMAX_DELAY); + if ( motion_pins[0] == 1 && prev_motion[0] == 0 ){ + xQueueSend(check_queue, &io_num, portMAX_DELAY); } break; case CONFIG_MOTION_SECOND_PIN: prev_motion[1] = motion_pins[1]; motion_pins[1] = pin_value; - if ( motion_pins[1] == true && prev_motion[1] == false ){ - xQueueSend(check_queue, &io_num, portMAX_DELAY); + if ( motion_pins[1] == 1 && prev_motion[1] == 0 ){ + xQueueSend(check_queue, &io_num, portMAX_DELAY); } break; default: printf("Unable to set motion pins!\n"); } - bool motion; - if ((motion_pins[0] == 0) && (motion_pins[1] == 0)) { - motion = false; - report_data.motion = motion; + if ((motion_pins[0] == 0 && motion_pins[1] == 0) && + (prev_motion[0] == 1 || prev_motion[1] == 1 )){ + send_report_motion(false); } - xSemaphoreGive(report_data.mutex); - send_report_motion(motion); } } } @@ -1240,7 +1334,11 @@ short temp_avg = 0; #else // sleep for 10 seconds before measuring again ESP_LOGI(TAG, "sleeping for %lld ms", remaining_time/1000); - vTaskDelay( pdMS_TO_TICKS(remaining_time/1000) ); + if ( remaining_time > 0 ){ + vTaskDelay( pdMS_TO_TICKS(remaining_time/1000) ); + } else { + ESP_LOGW(TAG, "sleep time was negative so we're already behind, just looping around"); + } #endif } @@ -1429,6 +1527,9 @@ void adjust_color_lookup_brightness(float multiplier){ void app_main(void) { + app_desc = *esp_app_get_description(); + + ESP_LOGI(TAG, "Built from commit %s", app_desc.version); /*#ifdef CONFIG_LIGHT_SLEEP_ENABLED ESP_ERROR_CHECK(esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON)); @@ -1501,11 +1602,15 @@ void app_main(void) wifi_manager_set_callback(WM_EVENT_STA_DISCONNECTED, &wifi_connection_bad); #endif send_queue = xQueueCreate(5, sizeof(char*)); + version_queue = xQueueCreate(5, sizeof(char*)); xTaskCreate(send_task, "send_task", 4096, NULL, 2, NULL); + xTaskCreate(version_task, "version_task", 4096, NULL, 2, NULL); + #if defined(CONFIG_MOTION_FIRST_ENABLED) || defined(CONFIG_MOTION_SECOND_ENABLED) ESP_LOGI(TAG, "installing motion task"); xTaskCreate(motion_task, "motion_task", 4096, NULL, 2, NULL); #endif xTaskCreate(monitoring_task, "monitoring_task", 4096, NULL, 1, NULL); + } diff --git a/aqi/main/aqi.h b/aqi/main/aqi.h index 2768831..9998152 100644 --- a/aqi/main/aqi.h +++ b/aqi/main/aqi.h @@ -23,6 +23,7 @@ #include "esp_openthread.h" #include "esp_openthread_netif_glue.h" #include "esp_openthread_lock.h" +#include "esp_app_desc.h" #include "esp_vfs_eventfd.h" #include "openthread/logging.h" #include "openthread/thread.h" @@ -125,6 +126,7 @@ static const char *TAG = "aqi"; // ten second loop #define SLEEP_MS 10000 +#define SQUELCH_MS 5000 diff --git a/aqi/sdkconfig b/aqi/sdkconfig index b3c3b66..2638ac3 100644 --- a/aqi/sdkconfig +++ b/aqi/sdkconfig @@ -1817,7 +1817,7 @@ CONFIG_WIFI_PROV_STA_ALL_CHANNEL_SCAN=y # # AQI Program Configuration # -# CONFIG_TEMP_ENABLED is not set +CONFIG_TEMP_ENABLED=y CONFIG_TEMP_PIN=2 # CONFIG_EEPY_DEVICE is not set # CONFIG_LIGHT_SLEEP_ENABLED is not set @@ -1826,23 +1826,23 @@ CONFIG_TEMP_PIN=2 # CONFIG_WIFI_ENABLED is not set CONFIG_OT_ENABLED=y # CONFIG_LED_ENABLED is not set -# CONFIG_MOTION_FIRST_ENABLED is not set -CONFIG_MOTION_FIRST_PIN=25 +CONFIG_MOTION_FIRST_ENABLED=y +CONFIG_MOTION_FIRST_PIN=14 # CONFIG_MOTION_SECOND_ENABLED is not set -CONFIG_MOTION_SECOND_PIN=10 +CONFIG_MOTION_SECOND_PIN=4 # CONFIG_MOTION_RECHECK is not set # CONFIG_PWM_ENABLED is not set CONFIG_PWM_TOPIC="esp32/pwm/stairway" CONFIG_PWM_TARGET_PERCENT=50 -CONFIG_PWM_R1_GPIO=0 -CONFIG_PWM_G1_GPIO=14 +CONFIG_PWM_R1_GPIO=1 +CONFIG_PWM_G1_GPIO=0 CONFIG_PWM_B1_GPIO=13 -CONFIG_PWM_R2_GPIO=-1 -CONFIG_PWM_G2_GPIO=-1 -CONFIG_PWM_B2_GPIO=-1 +CONFIG_PWM_R2_GPIO=12 +CONFIG_PWM_G2_GPIO=14 +CONFIG_PWM_B2_GPIO=4 # CONFIG_INDICATOR_ENABLED is not set CONFIG_BROKER_URL="mqtts://esp32:sensorauth@rabbitmq" -CONFIG_LOCATION="Test Solder 2" +CONFIG_LOCATION="Upstairs Bedroom" CONFIG_GPIO_ERASE_PIN=5 # end of AQI Program Configuration -- 2.30.2