From b25ea99da0a6e86e058ef5b6d1f53c81a0d107d0 Mon Sep 17 00:00:00 2001 From: Kai Lauterbach Date: Mon, 12 Sep 2022 15:26:30 +0200 Subject: [PATCH] Initial implementation of the FSM, also cleaned up webUpdater ino file. --- firmware/config.h | 2 +- firmware/config_user.h.example | 1 - firmware/firmware.ino | 335 ++++++++++++++++++++------------- firmware/influxdb.ino | 6 +- firmware/webUpdater.ino | 45 +++-- 5 files changed, 242 insertions(+), 147 deletions(-) diff --git a/firmware/config.h b/firmware/config.h index 1ecdf35..fa7e5ec 100644 --- a/firmware/config.h +++ b/firmware/config.h @@ -10,7 +10,7 @@ #define DELAY_LOOP_MS 50 #define POWERSAVING_SLEEP_S 600 #define EMERGENCY_SLEEP_S 172800 // Sleep for 2 days to recover -#define RESET_ESP_TIME_INTERVAL_MS (60*60*3*1000) // (60*60*6*1000) // reset every 3 hours +#define RESET_ESP_TIME_INTERVAL_MS (60*60*12*1000) // reset every 12 hours #define WIND_SENSOR_MEAS_TIME_S 15 #define INITIAL_WEBSERVER_TIME 20 diff --git a/firmware/config_user.h.example b/firmware/config_user.h.example index b81c72f..bf48669 100755 --- a/firmware/config_user.h.example +++ b/firmware/config_user.h.example @@ -13,7 +13,6 @@ String DEVICE_NAME = "weatherstation"; // Enable/Disable features -//#define WEBUPDATER_FEATURE #define INFLUXDB_FEATURE #define INFLUXDB_VERSION 1 // 1 or 2 #define SERIAL_FEATURE diff --git a/firmware/firmware.ino b/firmware/firmware.ino index fbc636a..789103c 100644 --- a/firmware/firmware.ino +++ b/firmware/firmware.ino @@ -27,7 +27,9 @@ // constant variables const uint8_t VALUES = 8; // see constants.h file - count of number of SENSOR_ defines -float currentSensorData[VALUES] = {nanf("no value"), nanf("no value"), nanf("no value"), nanf("no value"), nanf("no value"), nanf("no value"), nanf("no value"), nanf("no value")}; +float currentSensorData[VALUES] = { nanf("no value"), nanf("no value"), nanf("no value"), + nanf("no value"), nanf("no value"), nanf("no value"), + nanf("no value"), nanf("no value") }; float (*sensors[VALUES])() = {}; uint16_t update_sensor_cnt = 0; @@ -36,8 +38,26 @@ uint16_t update_windspeed_exceed_cnt = 0; boolean validData = false; +const String wifiName = "oko-weather-" + DEVICE_NAME; + +uint32_t wifi_check_interval_counter = millis(); + WiFiManager wifiManager; +typedef enum fsm_states_et { + FSM_STATE_WU, + FSM_STATE_WSE, + FSM_STATE_RS, + FSM_STATE_BP, + FSM_STATE_WS, + FSM_STATE_US, + FSM_STATE_SC, + FSM_STATE_ID, + FSM_STATE_SD +} t_fsm_states; + +t_fsm_states fsm_state = FSM_STATE_WU; + //*************************************************************************// void debug(String x) @@ -47,6 +67,8 @@ void debug(String x) #endif } +//*************************************************************************// + void setup() { @@ -73,13 +95,54 @@ void setup() criticalBatCheck(); #endif - wifiConnectionCheck(); + wifiConnect(); debug("Connected!"); #ifdef INFLUXDB_FEATURE influxdb_begin(); #endif + initSensors(); + +#ifdef WEBUPDATER_FEATURE +#ifndef BATTERY_POWERED + setupWebUpdater(DEVICE_NAME, WiFi.localIP().toString()); +#endif +#endif + + //It's magic! leave in + delay(100); + +#ifdef BATTERY_POWERED + debug("battery powered"); + _loop(); + + digitalWrite(STATUS_LED_PIN, LOW); + + criticalBatCheck(); + + WiFi.mode(WIFI_OFF); + WiFi.forceSleepBegin(); + + debug("deep sleep"); + + // the ESP.deepSleep requires microseconds as input, after the + // sleep the system will run into the setup routine + ESP.deepSleep(POWERSAVING_SLEEP_S * 1000000, WAKE_RF_DEFAULT); + delay(100); +#endif + +#ifdef ENABLE_WATCHDOG + // Enable the internal watchdog + ESP.wdtEnable(WATCHDOG_TIMEOUT_MS); +#endif + +} + +//*************************************************************************// + +void initSensors() +{ // Initialize and configure the sensors #ifdef SENSOR_APDS9930 if (sensor_apds9930_begin()) { @@ -111,47 +174,29 @@ void setup() sensors[SENSOR_BATCHARGESTATE] = &battery_charging; sensors[SENSOR_ESAVEMODE] = &isEnergySavingMode; #endif - -#ifdef WEBUPDATER_FEATURE -#ifndef BATTERY_POWERED - setupWebUpdater(DEVICE_NAME, WiFi.localIP().toString()); -#endif -#endif - - //It's magic! leave in - delay(100); - -#ifdef BATTERY_POWERED - debug("battery powered"); - _loop(); - - digitalWrite(STATUS_LED_PIN, LOW); - - criticalBatCheck(); - - WiFi.mode(WIFI_OFF); - WiFi.forceSleepBegin(); - - debug("deep sleep"); - - // the ESP.deepSleep requires microseconds as input, after the sleep the system will run into the setup routine - ESP.deepSleep(POWERSAVING_SLEEP_S * 1000000, WAKE_RF_DEFAULT); - delay(100); -#endif - -#ifdef ENABLE_WATCHDOG - // Enable the internal watchdog - ESP.wdtEnable(WATCHDOG_TIMEOUT_MS); -#endif - } //*************************************************************************// void wifiConnectionCheck() { - // Establish WiFi connection - String wifiName = "oko-weather-" + DEVICE_NAME; + + if (millis() - wifi_check_interval_counter < WIFI_CHECK_INVERVAL_MS) + { + // if check interval is not exceeded abort check + return; + } + + wifi_check_interval_counter = millis(); + + wifiConnect(); + +} + +void wifiConnect() +{ + + // Establish WiFi connection if not already applied wifiManager.setMinimumSignalQuality(WIFI_MINIMUM_SIGNAL_QUALITY); // the time in seconds to wait for the known wifi connection @@ -161,7 +206,6 @@ void wifiConnectionCheck() while (!wifiManager.autoConnect(wifiName.c_str(), "DEADBEEF")) { - debug("WiFi connection failed, try again in 5 seconds..."); // If autoconnect to WLAN failed and no client connected, go to deep sleep #ifdef SLEEP_IF_NO_WLAN_CONNECTION ESP.deepSleep(POWERSAVING_SLEEP_S * 1000000, WAKE_RF_DEFAULT); @@ -169,6 +213,7 @@ void wifiConnectionCheck() #endif #ifndef SLEEP_IF_NO_WLAN_CONNECTION // sleep a few seconds and go on trying to connect + debug("WiFi connection failed, try again in 5 seconds..."); delay(5000); #endif } @@ -191,6 +236,8 @@ void criticalBatCheck() } #endif +//*************************************************************************// + void loop() { @@ -223,122 +270,158 @@ void loop() } +//*************************************************************************// + void _loop() { + switch (fsm_state) + { + + case FSM_STATE_WU: #ifdef WEBUPDATER_FEATURE - if (UPDATE_WEBSERVER_INTVERVAL_S * 1000 / DELAY_LOOP_MS <= update_webserver_cnt) - { - update_webserver_cnt = 0; - doWebUpdater(); - } -#endif - -#ifdef HTTP_CALL_ON_WINDSPEED_EXCEED - if (HTTP_CALL_ON_WINDSPEED_INTERVAL_S * 1000 / DELAY_LOOP_MS <= update_windspeed_exceed_cnt) - { - debug("Reading wind sensor because of exceed call functionality"); - if (sensors[SENSOR_WINDSPEED]) - { - // read from windspeed sensorSTATUS_LED_PIN - digitalWrite(STATUS_LED_PIN, HIGH); - currentSensorData[SENSOR_WINDSPEED] = sensors[SENSOR_WINDSPEED](); - digitalWrite(STATUS_LED_PIN, LOW); - - if (currentSensorData[SENSOR_WINDSPEED] >= HTTP_CALL_ON_WINDSPEED_EXCEED_MPS) + if (UPDATE_WEBSERVER_INTVERVAL_S * 1000 / DELAY_LOOP_MS <= update_webserver_cnt) { - digitalWrite(STATUS_LED_PIN, HIGH); - - // call the url HTTP_CALL_ON_WINDSPEED_URL - WiFiClient client; - HTTPClient http; - - http.begin(client, String(HTTP_CALL_ON_WINDSPEED_URL).c_str()); - // Send HTTP GET request - int httpResponseCode = http.GET(); - - if (httpResponseCode > 0) { - String response = http.getString(); -#ifdef DEBUG - Serial.println("http response code: " + String(httpResponseCode) + " = " + response); -#endif - // TODO handle response - } - - http.end(); - debug("Called windspeed exceed callout"); - digitalWrite(STATUS_LED_PIN, LOW); + update_webserver_cnt = 0; + doWebUpdater(); } - } else { - currentSensorData[SENSOR_WINDSPEED] = nan("no value"); - } - update_windspeed_exceed_cnt = 0; - } #endif + fsm_state = FSM_STATE_WSE; + break; + case FSM_STATE_WSE: +#ifdef HTTP_CALL_ON_WINDSPEED_EXCEED + if (HTTP_CALL_ON_WINDSPEED_INTERVAL_S * 1000 / DELAY_LOOP_MS <= update_windspeed_exceed_cnt) + { + debug("Reading wind sensor because of exceed call functionality"); + if (sensors[SENSOR_WINDSPEED]) + { + // read from windspeed sensorSTATUS_LED_PIN + digitalWrite(STATUS_LED_PIN, HIGH); + currentSensorData[SENSOR_WINDSPEED] = sensors[SENSOR_WINDSPEED](); + digitalWrite(STATUS_LED_PIN, LOW); + + if (currentSensorData[SENSOR_WINDSPEED] >= HTTP_CALL_ON_WINDSPEED_EXCEED_MPS) + { + digitalWrite(STATUS_LED_PIN, HIGH); + + // call the url HTTP_CALL_ON_WINDSPEED_URL + WiFiClient client; + HTTPClient http; + + http.begin(client, String(HTTP_CALL_ON_WINDSPEED_URL).c_str()); + // Send HTTP GET request + int httpResponseCode = http.GET(); + + if (httpResponseCode > 0) { + String response = http.getString(); +#ifdef DEBUG + Serial.println("http response code: " + String(httpResponseCode) + " = " + response); +#endif + // TODO handle response + } + + http.end(); + debug("Called windspeed exceed callout"); + digitalWrite(STATUS_LED_PIN, LOW); + } + } else { + currentSensorData[SENSOR_WINDSPEED] = nan("no value"); + } + update_windspeed_exceed_cnt = 0; + } +#endif + fsm_state = FSM_STATE_RS; + break; + + case FSM_STATE_RS: #ifdef RESET_ESP_TIME_INTERVAL - // if millis() reached interval restart ESP - if (RESET_ESP_TIME_INTERVAL_MS <= millis()) - { - debug("Resetting firmware intentionally"); - // Push reset button after flashing once or do a manual power cycle to get the functionality working. - ESP.restart(); - } + // if millis() reached interval restart ESP + if (RESET_ESP_TIME_INTERVAL_MS <= millis()) + { + debug("Resetting firmware intentionally"); + // Push reset button after flashing once or do a manual power cycle to get the functionality working. + ESP.restart(); + } #endif + fsm_state = FSM_STATE_BP; + break; + case FSM_STATE_BP: #ifndef BATTERY_POWERED - if (UPDATE_SENSOR_INTERVAL_S * 1000 / DELAY_LOOP_MS > update_sensor_cnt) - { - return; - } + if (UPDATE_SENSOR_INTERVAL_S * 1000 / DELAY_LOOP_MS > update_sensor_cnt) + { + return; + } #endif + fsm_state = FSM_STATE_WS; + break; + case FSM_STATE_WS: #ifdef defined(BATTERY_POWERED) && defined(SENSOR_WIND) - if (energySavingMode() == 1) { - // Disable expensive tasks - sensors[SENSOR_WINDSPEED] = 0; - } else { - sensors[SENSOR_WINDSPEED] = &wind_speed; - } + if (energySavingMode() == 1) { + // Disable expensive tasks + sensors[SENSOR_WINDSPEED] = 0; + } else { + sensors[SENSOR_WINDSPEED] = &wind_speed; + } #endif + fsm_state = FSM_STATE_US; + break; - update_sensor_cnt = 0; - for (uint8_t i = 0; i < VALUES; i++) - { - if (sensors[i]) { - currentSensorData[i] = sensors[i](); - } else { - currentSensorData[i] = nan("no value"); - } - } + case FSM_STATE_US: + update_sensor_cnt = 0; + for (uint8_t i = 0; i < VALUES; i++) + { + if (sensors[i]) { + currentSensorData[i] = sensors[i](); + } else { + currentSensorData[i] = nan("no value"); + } + } + fsm_state = FSM_STATE_SC; + break; + case FSM_STATE_SC: #ifdef SERIAL_FEATURE - logToSerial(currentSensorData); + logToSerial(currentSensorData); #endif + fsm_state = FSM_STATE_ID; + break; - delay(100); + //delay(100); // TODO warum? + case FSM_STATE_ID: #ifdef INFLUXDB_FEATURE - - for (uint8_t i = 0; i < 5 and validData == false; i++) - { - if (currentSensorData[i] != 0) - { - validData = true; // at least one value is not zero, the data - } - } - - if (validData == true) - { - // send data only if valid data is available - pushToInfluxDB(DEVICE_NAME, currentSensorData); - } + for (uint8_t i = 0; i < 5 and validData == false; i++) + { + if (currentSensorData[i] != 0) + { + validData = true; // at least one value is not zero, the data + } + } + + if (validData == true) + { + // send data only if valid data is available + pushToInfluxDB(DEVICE_NAME, currentSensorData); + } #endif + fsm_state = FSM_STATE_SD; + break; + case FSM_STATE_SD: #ifdef WEBUPDATER_FEATURE - setSensorData(currentSensorData); + setSensorData(currentSensorData); #endif + fsm_state = FSM_STATE_WU; + break; + default: + fsm_state = FSM_STATE_WU; + break; + + } // close of switch } void logToSerial(float sensorValues[]) diff --git a/firmware/influxdb.ino b/firmware/influxdb.ino index 0e0b881..524d798 100644 --- a/firmware/influxdb.ino +++ b/firmware/influxdb.ino @@ -7,6 +7,8 @@ Influxdb _influxdb(INFLUXDB_HOST, INFLUXDB_PORT); +const String msg = "weather,device=" + device + " "; + void influxdb_begin() { // Init variables to influxdb config - doesn't talk to database _influxdb.opendb(INFLUXDB_DB, INFLUXDB_USER, INFLUXDB_PASS); @@ -16,7 +18,6 @@ void pushToInfluxDB(String device, float sensorValues[]) { uint8_t tries = 0; boolean addComma = false; - String msg = "weather,device=" + device + " "; if (!(isnan(sensorValues[SENSOR_TEMPERATURE]))) { msg += "temperature=" + String(sensorValues[SENSOR_TEMPERATURE]); @@ -172,7 +173,8 @@ void pushToInfluxDB(String device, float sensorValues[]) { } -void _writePoint() { +void _writePoint() +{ // wait unitl ready do { diff --git a/firmware/webUpdater.ino b/firmware/webUpdater.ino index 25af4b7..9060e1b 100644 --- a/firmware/webUpdater.ino +++ b/firmware/webUpdater.ino @@ -23,15 +23,19 @@ String _webUpdater_ip = "127.0.0.1"; String _webUpdater_dev = "unknown"; float _webUpdater_sensValues[VALUES]; -String hb_ws_msg_start = "{"; -String hb_ws_msg_temp = "\"temperature\": "; -String hb_ws_msg_humi = "\"humidity\": "; -String hb_ws_msg_light = "\"lightlevel\": "; -String hb_ws_msg_windspeed = "\"windspeed\": "; -String hb_ws_msg_pressure = "\"pressure\": "; -String hb_ws_msg_timestamp = "\"timestamp\": "; -String hb_ws_msg_valid = "\"valid\": "; -String hb_ws_msg_end = "}"; +const String hb_ws_msg_start = "{"; +const String hb_ws_msg_temp = "\"temperature\": "; +const String hb_ws_msg_humi = "\"humidity\": "; +const String hb_ws_msg_light = "\"lightlevel\": "; +const String hb_ws_msg_windspeed = "\"windspeed\": "; +const String hb_ws_msg_pressure = "\"pressure\": "; +const String hb_ws_msg_timestamp = "\"timestamp\": "; +const String hb_ws_msg_valid = "\"valid\": "; +const String hb_ws_msg_end = "}"; + +#define TR_TD_START_STR "" +#define TR_TD_END_STR "" +#define TD_TD_MID_STR "" boolean wuValidData = false; @@ -87,20 +91,22 @@ void showHTMLMain(void) "" "
firmware update

" "" -"" -"" -"" -"" -"" -"" -"" -"" +TR_TD_START_STR + "temperature" + TD_TD_MID_STR + String(_webUpdater_sensValues[SENSOR_TEMPERATURE]) + TR_TD_END_STR +TR_TD_START_STR + "humidity" + TD_TD_MID_STR + String(_webUpdater_sensValues[SENSOR_HUMIDITY]) + TR_TD_END_STR +TR_TD_START_STR + "light" + TD_TD_MID_STR + String(_webUpdater_sensValues[SENSOR_LIGHT]) + TR_TD_END_STR +TR_TD_START_STR + "windspeed" + TD_TD_MID_STR + String(_webUpdater_sensValues[SENSOR_WINDSPEED]) + TR_TD_END_STR +TR_TD_START_STR + "pressure" + TD_TD_MID_STR + String(_webUpdater_sensValues[SENSOR_PRESSURE]) + TR_TD_END_STR +TR_TD_START_STR + "batvoltage" + TD_TD_MID_STR + String(_webUpdater_sensValues[SENSOR_BAT_VOLTAGE]) + TR_TD_END_STR +TR_TD_START_STR + "millis" + TD_TD_MID_STR + String(millis()) + TR_TD_END_STR +TR_TD_START_STR + "valid" + TD_TD_MID_STR + String(wuValidData) + TR_TD_END_STR +TR_TD_START_STR + "wifi rssi" + TD_TD_MID_STR + WiFi.RSSI() + TR_TD_END_STR "
temperature" + String(_webUpdater_sensValues[SENSOR_TEMPERATURE]) + "
humidity" + String(_webUpdater_sensValues[SENSOR_HUMIDITY]) + "
light" + String(_webUpdater_sensValues[SENSOR_LIGHT]) + "
windspeed" + String(_webUpdater_sensValues[SENSOR_WINDSPEED]) + "
pressure" + String(_webUpdater_sensValues[SENSOR_PRESSURE]) + "
batvoltage" + String(_webUpdater_sensValues[SENSOR_BAT_VOLTAGE]) + "
millis" + String(millis()) + "
valid" + String(wuValidData) + "
" ""; httpServer.send(200, "text/html", message); } +#ifdef HOMEBRIDGE_WEBSTAT void hb_webstat_send(void) { String msg = hb_ws_msg_start + @@ -128,6 +134,7 @@ void hb_webstat_send(void) httpServer.send(200, "text/html", msg); } +#endif void resetWifiManager() { @@ -151,6 +158,8 @@ void resetWifiManager() ESP.restart(); } +#ifdef DEBUG_WINDSPEED_MEASUREMENT +#ifdef SENSOR_WIND void measureWindspeed() { @@ -168,3 +177,5 @@ void measureWindspeed() httpServer.send(200, "text/html", message); } +#endif +#endif