main/co2meter.c

Fri, 08 Nov 2019 22:40:15 +0100

author
Michiel Broek <mbroek@mbse.eu>
date
Fri, 08 Nov 2019 22:40:15 +0100
changeset 26
8a3696620c0a
parent 24
64078aa15512
child 28
6d825e2962e4
permissions
-rw-r--r--

Increaded stacksize for the user process. Implemented the network update using the proven brewboard code. Reverted the lock release and display sendbuffer lines to the previous code. The networks status screen uses the wifi lock.

/**
 * @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
bool                            	System_TimeOk = false;          ///< System time status
time_t                          	now;                            ///< Current time
struct tm                       	timeinfo;                       ///< Current time structure
char                            	strftime_buf[64];               ///< Time buffer
static RTC_DATA_ATTR struct timeval	sleep_enter_time;
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 WIFI_State			*wifi_state;			///< WiFi state
extern EventGroupHandle_t		xEventGroupUser;
extern int				count_pub;			///< Published MQTT messages in transit




void app_main()
{
    struct timeval	now;
    gettimeofday(&now, NULL);
    int			sleep_time_ms = (now.tv_sec - sleep_enter_time.tv_sec) * 1000 + (now.tv_usec - sleep_enter_time.tv_usec) / 1000;
    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();

    switch (esp_sleep_get_wakeup_cause()) {
        case ESP_SLEEP_WAKEUP_EXT1: {
	    ESP_LOGI(TAG, "Starting from deep sleep, Rotary switch pressed");
	    user_wakeup();
            break;
        }
        case ESP_SLEEP_WAKEUP_TIMER: {
	    ESP_LOGI(TAG, "Starting from deep sleep, timer wakeup after %dms", sleep_time_ms);
            break;
        }
        case ESP_SLEEP_WAKEUP_UNDEFINED:
        default:
            ESP_LOGI(TAG, "Starting from hard reset");
	    user_cold();
    }

    const int wakeup_time_sec = 55;
    ESP_LOGI(TAG, "Enabling timer wakeup, %ds", wakeup_time_sec);
    esp_sleep_enable_timer_wakeup(wakeup_time_sec * 1000000);
    const uint64_t ext_wakeup_pin_1_mask = 1ULL << ROT_ENC_SW_GPIO;

    ESP_LOGI(TAG, "Enabling EXT1 wakeup on pin GPIO%d", ROT_ENC_SW_GPIO);
    esp_sleep_enable_ext1_wakeup(ext_wakeup_pin_1_mask, ESP_EXT1_WAKEUP_ALL_LOW);

    // Isolate GPIO12 pin from external circuits. This is needed for modules
    // which have an external pull-up resistor on GPIO12 (such as ESP32-WROVER)
    // to minimize current consumption.
//    rtc_gpio_isolate(GPIO_NUM_12);

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

//add_station((uint8_t *)"MBSE_WLR", (uint8_t *)"abcjkltuv");
//remove_station((uint8_t *)"MBSE_WLP");

    /*
     * 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("wifi", ESP_LOG_ERROR);
    xTaskCreate(&task_wifi,    "task_wifi",     4096, NULL, 3, &xTaskWifi);
    vTaskDelay(10 / portTICK_PERIOD_MS);
    esp_log_level_set("MQTT_CLIENT", ESP_LOG_ERROR);
    xTaskCreate(&task_mqtt,    "task_mqtt",     4096, NULL, 5, &xTaskMQTT);

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

	ESP_LOGI(TAG, "Entered app loop");

	/* Measure process */
	while (1) {
	    switch (Main_Loop1) {
		case ML1_INIT:
		    ESP_LOGI(TAG, "Loop timer: Init");
		    // If configured do ML1_CONNECT
		    Main_Loop1 = ML1_CONNECT;
		    requestWiFi_system(true);
		    request_ds18b20();
		    request_adc();
		    break;

		case ML1_CONNECT:
                    if (ready_WiFi()) {
                        Main_Loop1 = ML1_MQTT_CONNECT;
			user_refresh();
		    }
                    break;

		case ML1_MQTT_CONNECT:
		    if (ready_ds18b20() && ready_adc()) {
			connect_mqtt(true);
			Main_Loop1 = ML1_WAITCON;
			ESP_LOGI(TAG, "Loop timer: Wait MQTT");

			/* Get global temperature, use for all units. */
			uint32_t temp = 0;
			int state = 0;
			char rom_code[17];
			if (xSemaphoreTake(xSemaphoreDS18B20, 10) == pdTRUE) {
			    temp = (ds18b20_state->sensor[0].temperature * 1000);
			    state = (ds18b20_state->sensor[0].error == 0) ? 0:1;
			    strncpy(rom_code, ds18b20_state->sensor[0].rom_code, 17);
			    rom_code[16] = '\0';
        		    xSemaphoreGive(xSemaphoreDS18B20);
    			} else {
			    ESP_LOGE(TAG, "ML1_MQTT_CONNECT DS18B20 lock error");
			}

			/* Copy measured data and calculate results */
			for (int i = 0; i < 3; i++) {
			    if (xSemaphoreTake(xSemaphoreUnits, 25) == pdTRUE) {
			    	units[i].temperature = temp;
			    	units[i].temperature_state = state;
				units[i].alarm = 0;
				if (state)
				    units[i].alarm |= ALARM_SYS_TEMPERATURE & ALARM_UNIT_TEMPERATURE;
			    	strncpy(units[i].temperature_rom_code, rom_code, 17);

			    	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;
printf("%d volt: %d batt: %d scale: %d  mbar: %d\n", i, units[i].pressure_voltage, adc_state->Batt_voltage, 
		units[i].pressure_voltage / (adc_state->Batt_voltage / 1000) - units[i].pressure_zero, P);
// Moet die echt op 5 volt?
// Verbruik 10 mA
// Setup tijd max 2 mS
				    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:
		    ESP_LOGI(TAG, "Loop timer: Send MQTT");
		    publishNode();
		    publishUnits();
		    publishLogs();
		    Main_Loop1 = ML1_WAITACK;
		    break;

		case ML1_WAITACK:
		    if (count_pub == 0) // Wait until all published messages are sent.
			Main_Loop1 = ML1_MQTT_DISCONNECT;
		    break;

		case ML1_MQTT_DISCONNECT:
		    ESP_LOGI(TAG, "Loop timer: Disconnect MQTT");
		    connect_mqtt(false); // Doesn't really disconnect.
                    Main_Loop1 = ML1_DISCONNECT;
		    break;

		case ML1_DISCONNECT:
		    if (! ready_mqtt()) {
			ESP_LOGI(TAG, "Loop timer: WiFi off");
		    	requestWiFi_system(false);
		    	Main_Loop1 = ML1_WIFI_OFF;
		    }
		    break;

		case ML1_WIFI_OFF:
		    if (! ready_WiFi()) {
			ESP_LOGI(TAG, "Loop timer: Done %s", user_busy() ? "true":"false");
			Main_Loop1 = ML1_DONE;
			user_refresh();
		    }
		    break;

		case ML1_DONE:
		    break;
	    }

	    if (Main_Loop1 == ML1_DONE && ! user_busy())
	    	break;

	    vTaskDelay(10 / portTICK_PERIOD_MS);
	}

	ESP_LOGI(TAG, "Entering deep sleep");
    	gettimeofday(&sleep_enter_time, NULL);
	esp_deep_sleep_start();

//	ESP_LOGI(TAG, "Do nothing loop");
//	vTaskDelay(55000 / portTICK_PERIOD_MS);

	Main_Loop1 = ML1_INIT;
    }
}

mercurial