From: jweigele Date: Mon, 11 Mar 2024 16:17:29 +0000 (-0700) Subject: Comments and cleanup X-Git-Url: http://git.hexthepla.net/?a=commitdiff_plain;h=63d9da6a319f6b8ee49bb3cdae196a738a1ad9bb;p=esp32projects Comments and cleanup --- diff --git a/aqi/CMakeLists.txt b/aqi/CMakeLists.txt index 7a069db..79fb737 100644 --- a/aqi/CMakeLists.txt +++ b/aqi/CMakeLists.txt @@ -1,11 +1,13 @@ # The following lines of boilerplate have to be in your project's CMakeLists # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) + if (CONFIG_WIFI_ENABLED) set(EXTRA_COMPONENT_DIRS components/esp32-wifi-manager ) else() set(EXTRA_COMPONENT_DIRS ) endif() + include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(aqi) diff --git a/aqi/main/aqi.c b/aqi/main/aqi.c index 148f068..35a88a1 100644 --- a/aqi/main/aqi.c +++ b/aqi/main/aqi.c @@ -1,17 +1,3 @@ -/* - * 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 "nvs_flash.h" #include "esp_log.h" #include "freertos/FreeRTOS.h" @@ -30,6 +16,7 @@ typedef struct aqi_data_s { #ifdef CONFIG_PWM_ENABLED #include "driver/ledc.h" +// everything uses the same timer, just with diff duty cycles #define LEDC_TIMER LEDC_TIMER_0 #define LEDC_MODE LEDC_LOW_SPEED_MODE #define R1_CHANNEL LEDC_CHANNEL_0 @@ -38,10 +25,13 @@ typedef struct aqi_data_s { #define G2_CHANNEL LEDC_CHANNEL_3 #define B1_CHANNEL LEDC_CHANNEL_4 #define B2_CHANNEL LEDC_CHANNEL_5 -#define LEDC_FREQUENCY (1250) // Frequency in Hertz. Set frequency at 20 kHz +// initial PWM frequency in hz +#define LEDC_FREQUENCY (1250) +// scales the brightness to match so that the total duty % is roughly == the target double pwm_target = CONFIG_PWM_TARGET_PERCENT/100.0; +// this is a buffer with length that we'll reuse to ship PWM values between tasks typedef struct pwm_data_s { uint8_t msg[1024]; int len; @@ -49,8 +39,9 @@ typedef struct pwm_data_s { #endif +// overall report data structure, contains all the variables we'll parse and send to mqtt typedef struct report_data_s { -#ifdef CONFIG_UART_ENABLED +#ifdef CONFIG_UART_ENABLED uint16_t pm10; uint16_t pm25; float aqi; @@ -66,20 +57,23 @@ typedef struct report_data_s { uint32_t uptime; SemaphoreHandle_t mutex; } report_data_t; +// end report data + static temperature_sensor_handle_t temp_handle; static QueueHandle_t event_queue; static QueueHandle_t send_queue; static QueueHandle_t version_queue; +// holds version information static esp_app_desc_t app_desc; + +// mac address and ext address identification 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}; @@ -100,8 +94,6 @@ static int tempbuffer[TEMPBUFFERSIZE]; static int tempbufferindex = 0; static OW ow; -//= {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - #endif #ifdef CONFIG_LED_ENABLED @@ -134,10 +126,12 @@ static uint8_t ot_mac[6]; static uint8_t otExt[8]; #endif #endif +#ifdef CONFIG_UART_ENABLED static aqi_data_t cur_pm = { .pm10 = 0, .pm25 = 0 }; +#endif static report_data_t report_data; @@ -159,11 +153,14 @@ void handleNetifStateChanged(uint32_t aFlags, void *aContext) switch (changedRole) { + // we've attached to the openthread network, either becoming a leader, router, or child case OT_DEVICE_ROLE_LEADER: case OT_DEVICE_ROLE_ROUTER: case OT_DEVICE_ROLE_CHILD: ESP_LOGI(TAG, "valid role, setting netif_connected"); netif_connected = true; + // we may have transitioned from e.g. child -> router so it's quite possible + // our connection is already up, don't reconnect if we already have once if (mqtt_connected == false ){ ESP_LOGI(TAG, "CONNECTING to mqtt here!"); init_connected = true; @@ -172,6 +169,7 @@ void handleNetifStateChanged(uint32_t aFlags, void *aContext) } break; + // detached from openthread, set everything off so we don't keep trying to send case OT_DEVICE_ROLE_DETACHED: case OT_DEVICE_ROLE_DISABLED: netif_connected = false; @@ -182,6 +180,7 @@ void handleNetifStateChanged(uint32_t aFlags, void *aContext) } } +// helper functions for parsing hex from menuconfig int hex_digit_to_int(char hex) { if ('A' <= hex && hex <= 'F') { return 10 + hex - 'A'; @@ -215,25 +214,17 @@ size_t hex_string_to_binary(const char *hex_string, uint8_t *buf, size_t buf_siz } -/** - * Override default network settings, such as panid, so the devices can join a - network - */ +// take all openthread information set in menuconfig and configure the interface appropriately +// this is pretty much boilerplate variable setting void setNetworkConfiguration(otInstance *instance) { otOperationalDataset dataset; memset(&dataset, 0, sizeof(otOperationalDataset)); - - uint16_t network_name_len = strlen(CONFIG_OPENTHREAD_NETWORK_NAME); assert(network_name_len <= OT_NETWORK_NAME_MAX_SIZE); - /*if (otDatasetCreateNewNetwork(instance, &dataset) != OT_ERROR_NONE) { - ESP_LOGE(TAG, "Failed to create OpenThread network dataset."); - abort(); - }*/ dataset.mChannel = CONFIG_OPENTHREAD_NETWORK_CHANNEL; dataset.mComponents.mIsChannelPresent = true; dataset.mPanId = CONFIG_OPENTHREAD_NETWORK_PANID; @@ -259,6 +250,7 @@ void setNetworkConfiguration(otInstance *instance) } dataset.mComponents.mIsPskcPresent = true; otIp6Address prefix; + // uses helper functions above to parse the binary from hex string given in menuconfig otIp6AddressFromString(CONFIG_OPENTHREAD_MESH_LOCAL_PREFIX, &prefix); memcpy(dataset.mMeshLocalPrefix.m8, prefix.mFields.m8, sizeof(prefix.mFields.m8)); dataset.mComponents.mIsMeshLocalPrefixPresent = true; @@ -299,14 +291,12 @@ static void create_config_network(otInstance *instance) abort(); } - /* Register Thread state change handler */ + // register state change handler (attached to network, became router, etc.) otSetStateChangedCallback(instance, handleNetifStateChanged, instance); - //ESP_ERROR_CHECK(esp_openthread_auto_start(NULL)); - - /* Override default network credentials */ setNetworkConfiguration(instance); + // save the ext address for later usage memcpy(otExt, otLinkGetExtendedAddress(instance), 8); sprintf(ext_string, "%02x%02x%02x%02x%02x%02x%02x%02x", @@ -318,6 +308,8 @@ static void create_config_network(otInstance *instance) /* Start the Thread stack (CLI cmd > thread start) */ otThreadSetEnabled(instance, true); } + +// setup openthread netif and attach to it static esp_netif_t *init_openthread_netif(const esp_openthread_platform_config_t *config) { esp_netif_config_t cfg = ESP_NETIF_DEFAULT_OPENTHREAD(); @@ -372,7 +364,7 @@ static void ot_task_worker(void *aContext) threadInstance = esp_openthread_get_instance(); create_config_network(threadInstance); - //esp_err_t err_netif = esp_netif_get_mac(openthread_netif, ot_mac); + // save mac addy for later usage 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]); @@ -382,6 +374,8 @@ static void ot_task_worker(void *aContext) esp_openthread_lock_release(); esp_err_t err = esp_openthread_launch_mainloop(); + + // should not reach here in normal operation ESP_LOGE(TAG, "Error somewhere in openthread loop %s.", esp_err_to_name(err)); // Clean up @@ -431,7 +425,7 @@ void erase_data_hook(void){ #endif ESP_LOGW(TAG, "would erase flash here!!!"); ESP_ERROR_CHECK(nvs_flash_erase_partition(CONFIG_NVS_OT_PARTITION)); -#ifdef CONFIG_WIFI_ENABLED +#ifdef CONFIG_WIFI_ENABLED // 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); @@ -513,18 +507,14 @@ void init_tempbuffer(){ } } +// fetches temperature from any attached ds18b20 devices +// returns as value * 100 (so that we can get 2 decimal places by later /100 +// without dealing with float nonsense now) static short get_temp(){ if (ow_reset (&ow)) { - //puts ("slave(s) present"); - - // scan bus for slaves + // scan bus for devices uint64_t romcode[MAXDEVS]; int num_devs = ow_romsearch (&ow, romcode, MAXDEVS, OW_SEARCH_ROM); - /*printf("Found %d devices\n", num_devs); - for (int i = 0; i < num_devs; i += 1) { - printf("\t%d: 0x%llx\n", i, romcode[i]); - } - putchar ('\n');*/ // get temperature readings if (num_devs > 0) { @@ -613,6 +603,7 @@ void init_pmbuffer(){ } } +// hardcoded given the aqi device we expect to find void init_uart(void) { const uart_config_t uart_config = { .baud_rate = 9600, @@ -628,6 +619,9 @@ void init_uart(void) { uart_set_pin(UART_NUM_1, UART_TX_GPIO, UART_RX_GPIO, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); } +// this task sends identifying information over mqtt, sleeps an hour, then repeats +// +// if it doesn't go out for some reason it's just stored in a queue until it is fetched 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) ); @@ -644,6 +638,7 @@ static void version_task(void* discard){ cJSON_AddStringToObject(root, "location", CONFIG_LOCATION); char *mqtt_string = cJSON_Print(root); xQueueSend(version_queue, &mqtt_string, portMAX_DELAY); + // reclaim memory on json object here, assumed that other side handles string cJSON_Delete(root); // wait an hour, then send again @@ -652,6 +647,7 @@ static void version_task(void* discard){ } +// handles the basic reporting of both version and sensor information over mqtt static void send_task(void* discard){ char* mqtt_string = ""; //NULL; @@ -666,11 +662,11 @@ static void send_task(void* discard){ free(mqtt_string); } } - // receive an event we need to deal with from elsewhere, right now just reconnect related + // sensor information queue -> send on mqtt if (xQueueReceive(send_queue, &mqtt_string, portMAX_DELAY )){ last_sent = true; - //ESP_LOGW(TAG, "received a string in send loop! %s", mqtt_string); ESP_LOGI(TAG, "sending mqtt_string:\n%s",mqtt_string); + // need to be both connected to a network and also connected to mqtt to send successfully if (netif_connected == true && mqtt_connected == true){ int msg_id = esp_mqtt_client_publish(mqtt_client, "esp32/sensor_info", mqtt_string, 0, 1, 0); ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id); @@ -680,6 +676,8 @@ static void send_task(void* discard){ free(mqtt_string); } // and loop around immediately if we just sent something, otherwise sleep a bit + // + // helps when the queue has backed up faster than our delay loop accounts for if (last_sent == true) { last_sent = false; } else { @@ -710,10 +708,13 @@ static void send_report_motion(bool motion){ } #endif // CONFIG_MOTION_ENABLED -static void send_report_wifi(report_data_t report_data){ +// this parses all currently enabled sensor data and puts it in a json object, +// converts to string, and dumps it on the mqtt queue for sending on sensor_info +static void send_report_summary(report_data_t report_data){ + // enforce access while making changes xSemaphoreTake(report_data.mutex, portMAX_DELAY); - ESP_LOGI(TAG, "send_report_wifi was called!"); + ESP_LOGI(TAG, "send_report_summary was called!"); cJSON *root; root = cJSON_CreateObject(); cJSON_AddStringToObject(root, "location", CONFIG_LOCATION); @@ -722,6 +723,7 @@ static void send_report_wifi(report_data_t report_data){ cJSON_AddNumberToObject(root, "pm25", ((float)report_data.pm25/100)); cJSON_AddNumberToObject(root, "aqi", report_data.aqi); #endif + // both set as we go through the normal loop, "nice to have" information on device operation cJSON_AddNumberToObject(root, "uptime", report_data.uptime); cJSON_AddNumberToObject(root, "internal", report_data.internal_temperature); #ifdef CONFIG_TEMP_ENABLED @@ -737,15 +739,19 @@ static void send_report_wifi(report_data_t report_data){ #endif char *mqtt_string = cJSON_Print(root); + // drop on the send queue xQueueSend(send_queue, &mqtt_string, portMAX_DELAY); + // free memory from json object, assume other end of the queue frees the string cJSON_Delete(root); + // done making modifications xSemaphoreGive(report_data.mutex); } #endif // wifi or ot enabled +// defined by AQI device, simply adhering to that spec here bool verify_checksum(uint8_t* data){ int total = 0; @@ -758,6 +764,7 @@ bool verify_checksum(uint8_t* data){ return data[30] == check_high && data[31] == check_low; } +// again, this protocol is defined by aqi device aqi_data_t get_average_pm25(uint8_t* data, int data_size){ int pm10_total = 0; int pm25_total = 0; @@ -807,6 +814,7 @@ aqi_data_t get_average_pm25(uint8_t* data, int data_size){ #ifdef CONFIG_PWM_ENABLED +// correct brightness levels so that colors remain roughly in proportion double gamma_correct(double led_value){ // just took this from the pico python script // believe it came from a website formula @@ -819,6 +827,7 @@ double gamma_correct(double led_value){ return retval; } +// not called in normal operation, useful for debugging PWM though int change_pwm_freq(int freq){ int duty_res = ledc_find_suitable_duty_resolution(32000000, freq); ESP_LOGI(TAG, "changing freq to %d", freq); @@ -853,19 +862,18 @@ static void pwm_task(void* discard){ int duty_res = ledc_find_suitable_duty_resolution(32000000, LEDC_FREQUENCY); ESP_LOGI(TAG, "max duty res for PWM is %d", duty_res); - // initialize PWM hardware - // Prepare and then apply the LEDC PWM timer configuration + // initialize PWM timer ledc_timer_config_t ledc_timer = { .speed_mode = LEDC_MODE, .timer_num = LEDC_TIMER, .duty_resolution = duty_res, - .freq_hz = LEDC_FREQUENCY, // Set output frequency at 5 kHz + .freq_hz = LEDC_FREQUENCY, .clk_cfg = LEDC_SLOW_CLK_XTAL }; ESP_LOGI(TAG, "configuring ledc timer"); ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer)); - // Prepare and then apply the LEDC PWM channel configuration + // Prepare and then apply the base LEDC PWM channel configuration ledc_channel_config_t ledc_channel = { .speed_mode = LEDC_MODE, .channel = LEDC_CHANNEL_0, @@ -877,6 +885,7 @@ static void pwm_task(void* discard){ }; + // for all channels, if GPIO pin is defined (!= -1) set params appropriately if (CONFIG_PWM_R1_GPIO != -1){ ledc_channel.channel = R1_CHANNEL; ledc_channel.gpio_num = CONFIG_PWM_R1_GPIO; @@ -922,8 +931,7 @@ static void pwm_task(void* discard){ - //create a queue to handle gpio event from isr - // 1kb, should be enough for parsing? + //create a queue to handle pwm events, assuming 10 is enough to process from mqtt before it backs up too much pwm_queue = xQueueCreate(10, sizeof(pwm_data_t)); pwm_data_t recv; ESP_LOGI(TAG, "waiting for pwm events"); @@ -942,9 +950,13 @@ static void pwm_task(void* discard){ int blue_duty_int; double total; for(;;) { + // just a JSON string hot off of mqtt, we need to parse the values from it if(xQueueReceive(pwm_queue, &recv, portMAX_DELAY)) { ESP_LOGI(TAG, "received PWM data string %s len %d", recv.msg, recv.len); current_pwm = cJSON_ParseWithLength(&recv.msg, recv.len); + // quick note: we don't free anything here because we're simply reusing the same pwm_data_t buffer to send ourselves + // data over and over. this might get messy if getting multiple values in a short period or something, but so far no issues + // with concurrency. if (cJSON_IsObject(current_pwm)){ // used to adjust scaling with pwm_target total = 0.0; @@ -952,12 +964,14 @@ static void pwm_task(void* discard){ red_duty_float = 0; green_duty_float = 0; blue_duty_float = 0; + // not changed in normal operation, used for debugging PWM brightness target_json = cJSON_GetObjectItemCaseSensitive(current_pwm, "target"); if (cJSON_IsNumber(target_json)){ ESP_LOGI(TAG, "parsed target float %f", target_json->valuedouble); pwm_target = target_json->valuedouble; } + // not changed in normal operation, used for changing PWM frequency on the fly freq_json = cJSON_GetObjectItemCaseSensitive(current_pwm, "freq"); if (cJSON_IsNumber(freq_json)){ ESP_LOGI(TAG, "parsed target int %d", freq_json->valueint); @@ -966,18 +980,23 @@ static void pwm_task(void* discard){ + // red duty cycle as a float red_json = cJSON_GetObjectItemCaseSensitive(current_pwm, "red"); if (cJSON_IsNumber(red_json)){ ESP_LOGI(TAG, "parsed red float %f", red_json->valuedouble); red_duty_float = red_json->valuedouble; total += red_duty_float; } + + // green duty cycle as a float green_json = cJSON_GetObjectItemCaseSensitive(current_pwm, "green"); if (cJSON_IsNumber(green_json)){ ESP_LOGI(TAG, "parsed green float %f", green_json->valuedouble); green_duty_float = green_json->valuedouble; total += green_duty_float; } + + // blue duty cycle as a float blue_json = cJSON_GetObjectItemCaseSensitive(current_pwm, "blue"); if (cJSON_IsNumber(blue_json)){ ESP_LOGI(TAG, "parsed blue float %f", blue_json->valuedouble); @@ -986,8 +1005,6 @@ static void pwm_task(void* discard){ } - - // gamma correct and scale if needed (i.e. if any color is active) if (total > 0){ red_duty_float = gamma_correct(red_duty_float*(pwm_target/total)); @@ -995,11 +1012,14 @@ static void pwm_task(void* discard){ blue_duty_float = gamma_correct(blue_duty_float*(pwm_target/total)); } + // scale the float to the appropriate duty resolution we're using locally red_duty_int = (int)(red_duty_float*(pow(2,duty_res))); green_duty_int = (int)(green_duty_float*(pow(2,duty_res))); blue_duty_int = (int)(blue_duty_float*(pow(2,duty_res))); + // set all active PWM channels appropriately + ESP_LOGI(TAG, "red duty float calculated as %02f, int %d", red_duty_float, red_duty_int); if (CONFIG_PWM_R1_GPIO != -1){ @@ -1049,6 +1069,7 @@ static void pwm_task(void* discard){ ESP_LOGE(TAG, "failed to parse json successfully!"); } + // free json object cJSON_Delete(current_pwm); } } @@ -1058,15 +1079,20 @@ static void pwm_task(void* discard){ #endif #if defined(CONFIG_MOTION_FIRST_ENABLED) || defined(CONFIG_MOTION_SECOND_ENABLED) +// this is the interrupt handler so it needs to be _FAST_ and not blocking +// we just make it dump a thing on the queue and return, do the processing elsewhere static void IRAM_ATTR gpio_isr_handler(void* arg) { uint32_t gpio_num = (uint32_t) arg; xQueueSendFromISR(motion_queue, &gpio_num, NULL); } +// this rechecks to verify that our GPIO has been set for at least some time (to rule out blips) +// if not enabled, just a pass-through "true" static void check_motion(void* discard){ uint32_t io_num; for(;;) { + // block until something changes if(xQueueReceive(check_queue, &io_num, portMAX_DELAY)) { #ifdef CONFIG_MOTION_RECHECK // check after this much time @@ -1092,15 +1118,21 @@ static void check_motion(void* discard){ } +// we do all our motion GPIO interrupt processing in this loop, +// to the point where we've enqueued motion events for mqtt to send static void motion_task(void* discard){ + //create queues to handle motion events + motion_queue = xQueueCreate(100, sizeof(uint32_t)); + check_queue = xQueueCreate(100, sizeof(uint32_t)); //zero-initialize the config structure. gpio_config_t io_conf = {}; - //interrupt of rising edge + // GPIO interrupt on either rising or falling edge io_conf.intr_type = GPIO_INTR_ANYEDGE; - //bit mask of the pins, use GPIO4/5 here + // bit mask of the pins, set to nothing at the start io_conf.pin_bit_mask = 0; + // now, bring in any enabled pins (<< # according to esp32 mask definitions) #ifdef CONFIG_MOTION_FIRST_ENABLED io_conf.pin_bit_mask |= (1ULL << CONFIG_MOTION_FIRST_PIN); ESP_LOGI(TAG, "first motion bitmask now %"PRIu64, io_conf.pin_bit_mask); @@ -1112,36 +1144,30 @@ static void motion_task(void* discard){ //set as input mode io_conf.mode = GPIO_MODE_INPUT; - //enable pull-down mode + // enable pull-down mode (we are using "big" PIR sensors which require pull-down) io_conf.pull_down_en = 1; io_conf.pull_up_en = 0; + // hysteresis separates the thresholds for high/low so we don't have a lot of toggling in between io_conf.hys_ctrl_mode = GPIO_HYS_SOFT_ENABLE; gpio_config(&io_conf); - //change gpio interrupt type for one pin -#ifdef CONFIG_MOTION_FIRST_ENABLED + //change gpio interrupt type for enabled pins +#ifdef CONFIG_MOTION_FIRST_ENABLED ESP_ERROR_CHECK(gpio_set_intr_type(CONFIG_MOTION_FIRST_PIN, GPIO_INTR_ANYEDGE)); -#endif -#ifdef CONFIG_MOTION_SECOND_ENABLED +#endif +#ifdef CONFIG_MOTION_SECOND_ENABLED ESP_ERROR_CHECK(gpio_set_intr_type(CONFIG_MOTION_SECOND_PIN, GPIO_INTR_ANYEDGE)); #endif - //create a queue to handle gpio event from isr - 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 ESP_ERROR_CHECK(gpio_install_isr_service(ESP_INTR_FLAG_LOWMED)); //hook isr handler for specific gpio pin -#ifdef CONFIG_MOTION_FIRST_ENABLED +#ifdef CONFIG_MOTION_FIRST_ENABLED esp_err_t firstret = gpio_isr_handler_add(CONFIG_MOTION_FIRST_PIN, gpio_isr_handler, (void*) CONFIG_MOTION_FIRST_PIN); ESP_LOGE(TAG, "return for isr handler add (first) is %s", esp_err_to_name(firstret)); #endif -#ifdef CONFIG_MOTION_SECOND_ENABLED +#ifdef CONFIG_MOTION_SECOND_ENABLED esp_err_t secondret = gpio_isr_handler_add(CONFIG_MOTION_SECOND_PIN, gpio_isr_handler, (void*) CONFIG_MOTION_SECOND_PIN); ESP_LOGE(TAG, "return for isr handler add (second) is %s", esp_err_to_name(secondret)); #endif @@ -1151,10 +1177,16 @@ static void motion_task(void* discard){ uint32_t io_num; ESP_LOGI(TAG, "waiting for motion events"); for(;;) { + // block forever on interrupt GPIO events if(xQueueReceive(motion_queue, &io_num, portMAX_DELAY)) { + // if we got here, something changed, fetch the current level of the given pin int pin_value = gpio_get_level(io_num); ESP_LOGI(TAG, "GPIO[%"PRIu32"] intr, val: %d\n", io_num, pin_value); - uint32_t squelch_uptime; + // prev_motion is just an attempt to filter out "events" where the pin value doesn't change + // + // sending on queue with portMAX_DELAY is a choice - if we've somehow filled things up with quick toggles this WILL + // block, but probably better than dropping events on the floor?? really don't want to be in that situation + // to begin with switch (io_num) { case CONFIG_MOTION_FIRST_PIN: prev_motion[0] = motion_pins[0]; @@ -1191,15 +1223,17 @@ short temp_avg = 0; init_temp(); #endif +#ifdef CONFIG_UART_ENABLED uint16_t set_pm10; uint16_t set_pm25; + float cur_aqi_pm25 = 0.0; + float cur_aqi_pm10 = 0.0; + int length = 0; + uint8_t* data = (uint8_t*) malloc(RX_BUF_SIZE+1); +#endif int64_t cur_uptime = 0; int64_t next_sleep_uptime = 0; int64_t remaining_time = 0; - uint8_t* data = (uint8_t*) malloc(RX_BUF_SIZE+1); - int length = 0; - float cur_aqi_pm25 = 0.0; - float cur_aqi_pm10 = 0.0; #if defined(CONFIG_WIFI_ENABLED) || defined(CONFIG_OT_ENABLED) esp_mqtt_client_handle_t queue_item; #endif @@ -1292,8 +1326,8 @@ short temp_avg = 0; #if defined(CONFIG_WIFI_ENABLED) || defined(CONFIG_OT_ENABLED) - // one BIG report for wifi - send_report_wifi(report_data); + // one BIG report + send_report_summary(report_data); #endif cur_uptime = esp_timer_get_time(); @@ -1343,7 +1377,9 @@ short temp_avg = 0; } // only called if we break out of the loop somehow (right now, never) +#ifdef CONFIG_UART_ENABLED free(data); +#endif } #if defined(CONFIG_WIFI_ENABLED) || defined(CONFIG_OT_ENABLED) @@ -1415,12 +1451,15 @@ static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_ ESP_LOGI(TAG, "MQTT_EVENT_DATA"); printf("TOPIC=%.*s\r\n", event->topic_len, event->topic); #ifdef CONFIG_PWM_ENABLED + // the only topic we're subscribed to is for PWM so send the buffer along for processing I guess pwm_data_t sendpwm; - pwm_data_t* sendpwm_ptr = &sendpwm; //malloc(sizeof(pwm_data_t)); + pwm_data_t* sendpwm_ptr = &sendpwm; + // clear buffer memset(sendpwm_ptr, 0, 1024); + // copy from mqtt memcpy(sendpwm_ptr->msg, event->data, event->data_len); sendpwm_ptr->len = event->data_len; - printf("sendpwm msg: %s\nlen: %d\n", sendpwm_ptr->msg, sendpwm_ptr->len); + // dump on the queue for further processing (parse JSON and set PWM hardware) xQueueSend(pwm_queue, sendpwm_ptr, portMAX_DELAY); #endif @@ -1450,18 +1489,44 @@ static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_ } } +#ifdef CONFIG_OT_ENABLED +void print_addresses(){ + + esp_openthread_lock_acquire(portMAX_DELAY); + + const otNetifAddress *address; + char string[OT_IP6_ADDRESS_STRING_SIZE]; + + address = otIp6GetUnicastAddresses(threadInstance); + + while (address){ + otIp6AddressToString(&address->mAddress, string, sizeof(string)); + + ESP_LOGI(TAG, "IP6 addr: %s", string); + address = address->mNext; + } + esp_openthread_lock_release(); + +} +#endif + void init_mqtt(){ ESP_LOGI(TAG, "attempting to connect to MQTT"); mqtt_client = NULL; char mqtt_id[64]; #ifdef CONFIG_OT_ENABLED + // print ipv6 addresses if we're using openthread + print_addresses(); + // includes the ext address in the id sprintf(mqtt_id, "ESP32_%02x%02x%02x%02x%02x%02x_%02x%02x%02x%02x%02x%02x%02x%02x", ot_mac[0], ot_mac[1], ot_mac[2], ot_mac[3], ot_mac[4], ot_mac[5], otExt[0], otExt[1], otExt[2], otExt[3], otExt[4], otExt[5], otExt[6], otExt[7]); // sprintf(mqtt_id, "ESP32_%012x", ot_mac[0]); #else + // just uses something generic until I figure out the api for more sprintf(mqtt_id, "ESP32_wifi"); #endif + // verification is assumed to be disabled in menuconfig if needed (which I do lol) esp_mqtt_client_config_t mqtt_cfg = { .broker = { .address.uri = CONFIG_BROKER_URL, @@ -1486,9 +1551,7 @@ void init_mqtt(){ #ifdef CONFIG_WIFI_ENABLED // wifi connection nuked callbak -// wifi connection ok callback void wifi_connection_bad(void* pvParameter){ - //ip_event_got_ip_t* param = (ip_event_got_ip_t*)pvParameter; ESP_LOGW(TAG, "wifi connection got dropped! just gonna set stuff down and hope for the best"); netif_connected = false; init_connected = false; @@ -1508,7 +1571,6 @@ void wifi_connection_ok(void* pvParameter){ ESP_LOGI(TAG, "I have a connection and my IP is %s!", str_ip); - //xQueueSend(tx_task_queue, &tx_action, portMAX_DELAY); init_mqtt(); } @@ -1531,24 +1593,15 @@ void app_main(void) 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)); -#endif*/ - ESP_ERROR_CHECK(nvs_flash_init()); // temp monitoring temp_handle = NULL; + // this gives us the smallest error of all ranges per esp32 docs (<1C) temperature_sensor_config_t temp_sensor = TEMPERATURE_SENSOR_CONFIG_DEFAULT(-10, 80); - /* { - .range_min = 20, - .range_max = 100, - .temperature_sensor_clk_src_t = - };*/ ESP_ERROR_CHECK(temperature_sensor_install(&temp_sensor, &temp_handle)); // ESP_ERROR_CHECK(temperature_sensor_enable(temp_handle)); - // Create mutex before starting tasks report_data.mutex = xSemaphoreCreateMutex(); #if defined(CONFIG_WIFI_ENABLED) || defined(CONFIG_OT_ENABLED) @@ -1557,10 +1610,6 @@ void app_main(void) //indicator light #ifdef CONFIG_INDICATOR_ENABLED light_driver_init(LIGHT_DEFAULT_OFF); -#endif - - -#ifdef CONFIG_INDICATOR_ENABLED adjust_color_lookup_brightness(AQI_INDICATOR_BRIGHTNESS); #endif #ifdef CONFIG_UART_ENABLED @@ -1573,8 +1622,6 @@ void app_main(void) #ifdef CONFIG_LED_ENABLED init_led(); - //i2c_init(); - //runit(); #endif #ifdef CONFIG_PWM_ENABLED @@ -1582,6 +1629,8 @@ void app_main(void) xTaskCreate(pwm_task, "pwm_task", 4096, NULL, 2, NULL); #endif #ifdef CONFIG_OT_ENABLED + // not sure we really need 4, it was 3 before and seemed to work + // but doesn't hurt really esp_vfs_eventfd_config_t eventfd_config = { .max_fds = 4, }; @@ -1594,8 +1643,7 @@ void app_main(void) xTaskCreate(ot_task_worker, "ot_power_save_main", 4096, NULL, 5, NULL); #endif #ifdef CONFIG_WIFI_ENABLED -// ESP_ERROR_CHECK(esp_tls_set_global_ca_store(ca_cert, strlen((char*)ca_cert))); - /* start the wifi manager */ + // start the wifi manager wifi_manager_start(); wifi_manager_set_callback(WM_EVENT_STA_GOT_IP, &wifi_connection_ok); diff --git a/aqi/main/aqi.h b/aqi/main/aqi.h index 9998152..2070309 100644 --- a/aqi/main/aqi.h +++ b/aqi/main/aqi.h @@ -29,6 +29,7 @@ #include "openthread/thread.h" #include "openthread/thread_ftd.h" +#include "openthread/ip6.h" #define CONFIG_OPENTHREAD_NETWORK_POLLPERIOD_TIME 3000 // okay this isn't really defined here, you need to find it in the openthread source :(