main/co2meter.c

Tue, 03 Oct 2023 17:24:06 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Tue, 03 Oct 2023 17:24:06 +0200
changeset 77
15dc572a7fcb
parent 74
34da2d2b12d5
child 78
e03d729aecb8
permissions
-rw-r--r--

Version 0.3.0. Backported network code from experimental roaming project. Will now connect after reset to the strongest AP. Id the signal level drops below -67, extra scans are done to see for a better AP. Nothing is done yet. Removed config.conf file, all info is taken from the project menu and live tests. Better log the board type and send it via json mqtt. Send bssid and current channel too.

/**
 * @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 bool				_wifi_ScanDone;
extern int8_t				_wifi_RSSI;
extern int				count_pub;			///< Published MQTT messages in transit
extern uint32_t				AlarmTimer;			///< Alarm timer
extern uint32_t				err_connect;			///< Connect error counter

char					hostname[32];
char					uuid[37];


/**
 * @brief Main program entry
 */
void app_main()
{
    esp_err_t           ret;

    Main_Loop1 = ML1_INIT;
    app_desc = esp_app_get_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 || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        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
     */
//    unlink("/spiffs/config.conf");
//    read_config();
    read_units();
    vTaskDelay(500 / portTICK_PERIOD_MS);

    uint8_t mac_addr[8] = {0};
    // Set the configured hostname for the dhcp client.
    esp_efuse_mac_get_default(mac_addr);
    sprintf(hostname, "co2meter-%02x%02x%02x", mac_addr[3], mac_addr[4], mac_addr[5]);
    sprintf(uuid, "c0ffeeee-dead-beef-cafe-%02x%02x%02x%02x%02x%02x", mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);

    /*
     * 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);

    int wait = 150;
    while (wait) {
	vTaskDelay(100 / portTICK_PERIOD_MS);
	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");
	}
    }

    /*
     * Main application loop.
     */
    while (1) {

	ESP_LOGI(TAG, "Entered Main loop");

	/* Measure process */
	while (1) {
	    switch (Main_Loop1) {
		case ML1_INIT:
		    Main_Loop1 = ML1_CONNECT;
		    request_ds18b20();
		    request_adc();
		    AlarmTimer = 30 * 100;
		    if (! ready_WiFi()) { /* If WiFi was lost, try a new connection */
			ESP_LOGI(TAG, "Try WiFi restore");
			request_WiFi();
			err_connect++;
		    }
		    ESP_LOGI(TAG, "Loop => ML1_CONNECT");
		    break;

		case ML1_CONNECT:
                    if (ready_WiFi()) {
                        Main_Loop1 = ML1_MQTT_CONNECT;
			user_refresh();
			if (! ready_mqtt())
			    connect_mqtt(true);
		    }
		    ESP_LOGI(TAG, "Loop => ML1_MQTT_CONNECT");
                    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:%lu scale:%3lu mbar:%4d alm: %lu 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,
					(double)(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();
			ESP_LOGI(TAG, "Loop => ML1_MQTT_WAITCON");
		    }
		    break;

		case ML1_WAITCON:
		    if (ready_mqtt()) {
			Main_Loop1 = ML1_SEND;
			ESP_LOGI(TAG, "Loop => ML1_SEND");
		    }
		    break;

		case ML1_SEND:
		    publishNode();
		    publishUnits();
		    publishLogs();
		    Main_Loop1 = ML1_WAITACK;
		    ESP_LOGI(TAG, "Loop => ML1_WAITACK");
		    break;

		case ML1_WAITACK:
		    if (count_pub == 0) { // Wait until all published messages are sent.
			status_WiFi();
			ESP_LOGD(TAG, "Main loop: Done, user busy: %s", user_busy() ? "true":"false");
                        Main_Loop1 = ML1_STATUS;
                        user_refresh();
			ESP_LOGI(TAG, "Loop => ML1_STATUS");
		    }
		    break;

		case ML1_STATUS:
                    /*
                     * If rssi is too low, scan for beter AP.
                     */
                    if (_wifi_RSSI < CONFIG_ESP_WIFI_ROAMING_LEVEL) {
                        scan_WiFi();
                        Main_Loop1 = ML1_SCAN;
                        ESP_LOGI(TAG, "Loop => ML1_SCAN");
                    } else {
                        Main_Loop1 = ML1_DONE;
                        ESP_LOGI(TAG, "Loop => ML1_DONE");
                    }
                    break;

		case ML1_SCAN:
                    if (_wifi_ScanDone == true) {
                        Main_Loop1 = ML1_DONE;
                        ESP_LOGI(TAG, "Loop => ML1_DONE");
                    }
                    break;

		case ML1_DONE:
		    /* Wait here until the timer resets the loop */
		    if (AlarmTimer == 0) {
                        Main_Loop1 = ML1_INIT;
                        ESP_LOGI(TAG, "Loop => ML1_INIT");
                    }
		    break;
	    }
	    vTaskDelay(10 / portTICK_PERIOD_MS);
	    if (AlarmTimer > 0)
                AlarmTimer--;
	}

	Main_Loop1 = ML1_INIT;
    }
}

mercurial