Sat, 14 Mar 2020 13:07:02 +0100
Version 0.2.2 Changed to use a permanent network and WiFi connection. Removed three mainloop stages. Removed MQTT sequence counter that was not used. Update WiFi rssi status during eacht measure cycle. Changed FreeRTOS schedulng to 500 Hz.
/** * @file co2meter.c * @brief co2meter project. */ #include "config.h" static const char *TAG = "co2meter"; const esp_app_desc_t *app_desc = NULL; ///< Application description int Main_Loop1 = ML1_INIT; ///< Loop 1 init int num_sensors = 0; ///< Detected DS18B20 sensors static TaskHandle_t xTaskDS18B20 = NULL; static TaskHandle_t xTaskADC = NULL; static TaskHandle_t xTaskWifi = NULL; static TaskHandle_t xTaskMQTT = NULL; static TaskHandle_t xTaskUser = NULL; extern unit_t units[3]; ///< Pressure test units extern SemaphoreHandle_t xSemaphoreUnits; ///< Units lock semaphore extern DS18B20_State *ds18b20_state; ///< DS18B20 state extern SemaphoreHandle_t xSemaphoreDS18B20; ///< DS18B20 lock semaphore extern ADC_State *adc_state; ///< ADC state extern SemaphoreHandle_t xSemaphoreADC; ///< ADC lock semaphore extern SemaphoreHandle_t xSemaphoreWiFi; extern WIFI_State *wifi_state; ///< WiFi state extern EventGroupHandle_t xEventGroupUser; extern int count_pub; ///< Published MQTT messages in transit void app_main() { esp_err_t ret; Main_Loop1 = ML1_INIT; app_desc = esp_ota_get_app_description(); /* * event handler and event group for the user interface */ xEventGroupUser = xEventGroupCreate(); user_cold(); /* * Initialize NVS */ ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES) { ESP_ERROR_CHECK(nvs_flash_erase()); ret = nvs_flash_init(); } ESP_ERROR_CHECK(ret); /* * Setup SPIFFS filesystem */ ESP_LOGI(TAG, "Initializing SPIFFS"); esp_vfs_spiffs_conf_t conf = { .base_path = "/spiffs", .partition_label = NULL, .max_files = 5, .format_if_mount_failed = true }; /* * Use settings defined above to initialize and mount SPIFFS filesystem. * Note: esp_vfs_spiffs_register is an all-in-one convenience function. */ ret = esp_vfs_spiffs_register(&conf); if (ret != ESP_OK) { if (ret == ESP_FAIL) { ESP_LOGE(TAG, "Failed to mount or format filesystem"); } else if (ret == ESP_ERR_NOT_FOUND) { ESP_LOGE(TAG, "Failed to find SPIFFS partition"); } else { ESP_LOGE(TAG, "Failed to initialize SPIFFS (%d)", ret); } return; // Stop application. } size_t total = 0, used = 0; ret = esp_spiffs_info(NULL, &total, &used); if (ret != ESP_OK) { ESP_LOGE(TAG, "Failed to get SPIFFS partition information"); return; // Stop application. } else { ESP_LOGI(TAG, "Partition size: %d, used: %d - %d%%", total, used, (used * 100) / total); } // Just to debug, list the /spiffs filesystem. #if 0 DIR *dir = opendir("/spiffs"); struct dirent* de = readdir(dir); while (de) { if (de->d_type == DT_REG) { printf("F "); } if (de->d_type == DT_DIR) { printf("D "); } printf("%s\n", de->d_name); de = readdir(dir); } closedir(dir); #endif /* * Read or create configuration */ read_config(); read_units(); /* * Create FreeRTOS tasks */ xSemaphoreDS18B20 = xSemaphoreCreateMutex(); xSemaphoreADC = xSemaphoreCreateMutex(); xSemaphoreUnits = xSemaphoreCreateMutex(); xTaskCreate(&task_user, "task_user", 4096, NULL,10, &xTaskUser); xTaskCreate(&task_ds18b20, "task_ds18b20", 2560, NULL, 8, &xTaskDS18B20); xTaskCreate(&task_adc, "task_adc", 2560, NULL, 8, &xTaskADC); esp_log_level_set("MQTT_CLIENT", ESP_LOG_ERROR); xTaskCreate(&task_mqtt, "task_mqtt", 4096, NULL, 5, &xTaskMQTT); esp_log_level_set("wifi", ESP_LOG_ERROR); xTaskCreate(&task_wifi, "task_wifi", 4096, NULL, 3, &xTaskWifi); vTaskDelay(10 / portTICK_PERIOD_MS); int wait = 150; while (wait) { if (ready_WiFi()) { ESP_LOGI(TAG, "Online in %.1f seconds", (150 - wait) / 10.0); wait = 0; } else { wait--; if (wait < 1) ESP_LOGE(TAG, "Timeout network connection"); } vTaskDelay(100 / portTICK_PERIOD_MS); } /* * Main application loop. */ while (1) { ESP_LOGI(TAG, "Entered Main loop"); /* Measure process */ while (1) { switch (Main_Loop1) { case ML1_INIT: status_WiFi(); Main_Loop1 = ML1_CONNECT; request_ds18b20(); request_adc(); break; case ML1_CONNECT: if (ready_WiFi()) { Main_Loop1 = ML1_MQTT_CONNECT; user_refresh(); if (! ready_mqtt()) connect_mqtt(true); } break; case ML1_MQTT_CONNECT: if (ready_ds18b20() && ready_adc()) { Main_Loop1 = ML1_WAITCON; uint32_t temp[DS18B20_MAX]; int state[DS18B20_MAX], i; char rom_code[DS18B20_MAX][17]; for (i = 0; i < DS18B20_MAX; i++) { temp[i] = 0; state[i] = 0; rom_code[i][0] = '\0'; } /* Copy results from all connected DS18B20 sensors */ num_sensors = 0; if (xSemaphoreTake(xSemaphoreDS18B20, 10) == pdTRUE) { num_sensors = ds18b20_state->num_sensors; for (i = 0; i < num_sensors; i++) { temp[i] = (ds18b20_state->sensor[i].temperature * 1000); state[i] = (ds18b20_state->sensor[i].error == 0) ? 0:1; strncpy(rom_code[i], ds18b20_state->sensor[i].rom_code, 17); rom_code[i][16] = '\0'; } xSemaphoreGive(xSemaphoreDS18B20); } else { ESP_LOGE(TAG, "ML1_MQTT_CONNECT DS18B20 lock error"); } /* Copy measured data and calculate results */ for (i = 0; i < 3; i++) { if (xSemaphoreTake(xSemaphoreUnits, 25) == pdTRUE) { /* Search configured temperature sensor for this unit */ for (int j = 0; j < num_sensors; j++) { if (strcmp(rom_code[j], units[i].temperature_rom_code) == 0) { units[i].temperature = temp[j]; units[i].temperature_state = state[j]; units[i].alarm = 0; if (state[j]) units[i].alarm |= ALARM_SYS_TEMPERATURE & ALARM_UNIT_TEMPERATURE; break; } } /* Get the ADC results */ if (xSemaphoreTake(xSemaphoreADC, 10) == pdTRUE) { units[i].pressure_state = adc_state->Pressure[i].error; units[i].pressure_channel = adc_state->Pressure[i].channel; units[i].pressure_voltage = adc_state->Pressure[i].voltage; if (units[i].pressure_state || units[i].pressure_voltage < 80) units[i].alarm |= ALARM_UNIT_PRESSURE; int P = (units[i].pressure_voltage / (adc_state->Batt_voltage / 1000) - units[i].pressure_zero) * 14; // in bar if (P < 0) P = 0; units[i].pressure = P; ESP_LOGI(TAG, "%d vb:%.3f vp:%.3f zero:%d scale:%3d mbar:%4d alm: %d t:%6.3f %s", i, adc_state->Batt_voltage / 1000.0, units[i].pressure_voltage / 1000.0, units[i].pressure_zero, units[i].pressure_voltage / (adc_state->Batt_voltage / 1000) - units[i].pressure_zero, P, units[i].alarm, units[i].temperature / 1000.0, units[i].temperature_rom_code); xSemaphoreGive(xSemaphoreADC); } else { ESP_LOGE(TAG, "ML1_MQTT_CONNECT ADC[%d] lock error", i); } xSemaphoreGive(xSemaphoreUnits); } else { ESP_LOGE(TAG, "ML1_MQTT_CONNECT units[%d] lock error", i); } } if (xSemaphoreTake(xSemaphoreUnits, 25) == pdTRUE) { write_units(); xSemaphoreGive(xSemaphoreUnits); } else { ESP_LOGE(TAG, "ML1_MQTT_CONNECT write_units lock error"); } user_refresh(); } break; case ML1_WAITCON: if (ready_mqtt()) Main_Loop1 = ML1_SEND; break; case ML1_SEND: publishNode(); publishUnits(); publishLogs(); Main_Loop1 = ML1_WAITACK; break; case ML1_WAITACK: if (count_pub == 0) { // Wait until all published messages are sent. ESP_LOGI(TAG, "Main loop: Done, user busy: %s", user_busy() ? "true":"false"); Main_Loop1 = ML1_DONE; user_refresh(); } break; case ML1_DONE: /* Wait here until the timer resets the loop */ break; } vTaskDelay(10 / portTICK_PERIOD_MS); } Main_Loop1 = ML1_INIT; } }