Initial implementation of the FSM, also cleaned up webUpdater ino file.

This commit is contained in:
Kai Lauterbach 2022-09-12 15:26:30 +02:00
parent 3cea359c49
commit b25ea99da0
5 changed files with 242 additions and 147 deletions

View file

@ -10,7 +10,7 @@
#define DELAY_LOOP_MS 50 #define DELAY_LOOP_MS 50
#define POWERSAVING_SLEEP_S 600 #define POWERSAVING_SLEEP_S 600
#define EMERGENCY_SLEEP_S 172800 // Sleep for 2 days to recover #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 WIND_SENSOR_MEAS_TIME_S 15
#define INITIAL_WEBSERVER_TIME 20 #define INITIAL_WEBSERVER_TIME 20

View file

@ -13,7 +13,6 @@
String DEVICE_NAME = "weatherstation"; String DEVICE_NAME = "weatherstation";
// Enable/Disable features // Enable/Disable features
//#define WEBUPDATER_FEATURE
#define INFLUXDB_FEATURE #define INFLUXDB_FEATURE
#define INFLUXDB_VERSION 1 // 1 or 2 #define INFLUXDB_VERSION 1 // 1 or 2
#define SERIAL_FEATURE #define SERIAL_FEATURE

View file

@ -27,7 +27,9 @@
// constant variables // constant variables
const uint8_t VALUES = 8; // see constants.h file - count of number of SENSOR_ defines 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])() = {}; float (*sensors[VALUES])() = {};
uint16_t update_sensor_cnt = 0; uint16_t update_sensor_cnt = 0;
@ -36,8 +38,26 @@ uint16_t update_windspeed_exceed_cnt = 0;
boolean validData = false; boolean validData = false;
const String wifiName = "oko-weather-" + DEVICE_NAME;
uint32_t wifi_check_interval_counter = millis();
WiFiManager wifiManager; 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) void debug(String x)
@ -47,6 +67,8 @@ void debug(String x)
#endif #endif
} }
//*************************************************************************//
void setup() void setup()
{ {
@ -73,13 +95,54 @@ void setup()
criticalBatCheck(); criticalBatCheck();
#endif #endif
wifiConnectionCheck(); wifiConnect();
debug("Connected!"); debug("Connected!");
#ifdef INFLUXDB_FEATURE #ifdef INFLUXDB_FEATURE
influxdb_begin(); influxdb_begin();
#endif #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 // Initialize and configure the sensors
#ifdef SENSOR_APDS9930 #ifdef SENSOR_APDS9930
if (sensor_apds9930_begin()) { if (sensor_apds9930_begin()) {
@ -111,47 +174,29 @@ void setup()
sensors[SENSOR_BATCHARGESTATE] = &battery_charging; sensors[SENSOR_BATCHARGESTATE] = &battery_charging;
sensors[SENSOR_ESAVEMODE] = &isEnergySavingMode; sensors[SENSOR_ESAVEMODE] = &isEnergySavingMode;
#endif #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() 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); wifiManager.setMinimumSignalQuality(WIFI_MINIMUM_SIGNAL_QUALITY);
// the time in seconds to wait for the known wifi connection // the time in seconds to wait for the known wifi connection
@ -161,7 +206,6 @@ void wifiConnectionCheck()
while (!wifiManager.autoConnect(wifiName.c_str(), "DEADBEEF")) 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 // If autoconnect to WLAN failed and no client connected, go to deep sleep
#ifdef SLEEP_IF_NO_WLAN_CONNECTION #ifdef SLEEP_IF_NO_WLAN_CONNECTION
ESP.deepSleep(POWERSAVING_SLEEP_S * 1000000, WAKE_RF_DEFAULT); ESP.deepSleep(POWERSAVING_SLEEP_S * 1000000, WAKE_RF_DEFAULT);
@ -169,6 +213,7 @@ void wifiConnectionCheck()
#endif #endif
#ifndef SLEEP_IF_NO_WLAN_CONNECTION #ifndef SLEEP_IF_NO_WLAN_CONNECTION
// sleep a few seconds and go on trying to connect // sleep a few seconds and go on trying to connect
debug("WiFi connection failed, try again in 5 seconds...");
delay(5000); delay(5000);
#endif #endif
} }
@ -191,6 +236,8 @@ void criticalBatCheck()
} }
#endif #endif
//*************************************************************************//
void loop() void loop()
{ {
@ -223,122 +270,158 @@ void loop()
} }
//*************************************************************************//
void _loop() void _loop()
{ {
switch (fsm_state)
{
case FSM_STATE_WU:
#ifdef WEBUPDATER_FEATURE #ifdef WEBUPDATER_FEATURE
if (UPDATE_WEBSERVER_INTVERVAL_S * 1000 / DELAY_LOOP_MS <= update_webserver_cnt) 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)
{ {
digitalWrite(STATUS_LED_PIN, HIGH); update_webserver_cnt = 0;
doWebUpdater();
// 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 #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 #ifdef RESET_ESP_TIME_INTERVAL
// if millis() reached interval restart ESP // if millis() reached interval restart ESP
if (RESET_ESP_TIME_INTERVAL_MS <= millis()) if (RESET_ESP_TIME_INTERVAL_MS <= millis())
{ {
debug("Resetting firmware intentionally"); debug("Resetting firmware intentionally");
// Push reset button after flashing once or do a manual power cycle to get the functionality working. // Push reset button after flashing once or do a manual power cycle to get the functionality working.
ESP.restart(); ESP.restart();
} }
#endif #endif
fsm_state = FSM_STATE_BP;
break;
case FSM_STATE_BP:
#ifndef BATTERY_POWERED #ifndef BATTERY_POWERED
if (UPDATE_SENSOR_INTERVAL_S * 1000 / DELAY_LOOP_MS > update_sensor_cnt) if (UPDATE_SENSOR_INTERVAL_S * 1000 / DELAY_LOOP_MS > update_sensor_cnt)
{ {
return; return;
} }
#endif #endif
fsm_state = FSM_STATE_WS;
break;
case FSM_STATE_WS:
#ifdef defined(BATTERY_POWERED) && defined(SENSOR_WIND) #ifdef defined(BATTERY_POWERED) && defined(SENSOR_WIND)
if (energySavingMode() == 1) { if (energySavingMode() == 1) {
// Disable expensive tasks // Disable expensive tasks
sensors[SENSOR_WINDSPEED] = 0; sensors[SENSOR_WINDSPEED] = 0;
} else { } else {
sensors[SENSOR_WINDSPEED] = &wind_speed; sensors[SENSOR_WINDSPEED] = &wind_speed;
} }
#endif #endif
fsm_state = FSM_STATE_US;
break;
update_sensor_cnt = 0; case FSM_STATE_US:
for (uint8_t i = 0; i < VALUES; i++) update_sensor_cnt = 0;
{ for (uint8_t i = 0; i < VALUES; i++)
if (sensors[i]) { {
currentSensorData[i] = sensors[i](); if (sensors[i]) {
} else { currentSensorData[i] = sensors[i]();
currentSensorData[i] = nan("no value"); } else {
} currentSensorData[i] = nan("no value");
} }
}
fsm_state = FSM_STATE_SC;
break;
case FSM_STATE_SC:
#ifdef SERIAL_FEATURE #ifdef SERIAL_FEATURE
logToSerial(currentSensorData); logToSerial(currentSensorData);
#endif #endif
fsm_state = FSM_STATE_ID;
break;
delay(100); //delay(100); // TODO warum?
case FSM_STATE_ID:
#ifdef INFLUXDB_FEATURE #ifdef INFLUXDB_FEATURE
for (uint8_t i = 0; i < 5 and validData == false; i++)
for (uint8_t i = 0; i < 5 and validData == false; i++) {
{ if (currentSensorData[i] != 0)
if (currentSensorData[i] != 0) {
{ validData = true; // at least one value is not zero, the data
validData = true; // at least one value is not zero, the data }
} }
}
if (validData == true)
if (validData == true) {
{ // send data only if valid data is available
// send data only if valid data is available pushToInfluxDB(DEVICE_NAME, currentSensorData);
pushToInfluxDB(DEVICE_NAME, currentSensorData); }
}
#endif #endif
fsm_state = FSM_STATE_SD;
break;
case FSM_STATE_SD:
#ifdef WEBUPDATER_FEATURE #ifdef WEBUPDATER_FEATURE
setSensorData(currentSensorData); setSensorData(currentSensorData);
#endif #endif
fsm_state = FSM_STATE_WU;
break;
default:
fsm_state = FSM_STATE_WU;
break;
} // close of switch
} }
void logToSerial(float sensorValues[]) void logToSerial(float sensorValues[])

View file

@ -7,6 +7,8 @@
Influxdb _influxdb(INFLUXDB_HOST, INFLUXDB_PORT); Influxdb _influxdb(INFLUXDB_HOST, INFLUXDB_PORT);
const String msg = "weather,device=" + device + " ";
void influxdb_begin() { void influxdb_begin() {
// Init variables to influxdb config - doesn't talk to database // Init variables to influxdb config - doesn't talk to database
_influxdb.opendb(INFLUXDB_DB, INFLUXDB_USER, INFLUXDB_PASS); _influxdb.opendb(INFLUXDB_DB, INFLUXDB_USER, INFLUXDB_PASS);
@ -16,7 +18,6 @@ void pushToInfluxDB(String device, float sensorValues[]) {
uint8_t tries = 0; uint8_t tries = 0;
boolean addComma = false; boolean addComma = false;
String msg = "weather,device=" + device + " ";
if (!(isnan(sensorValues[SENSOR_TEMPERATURE]))) if (!(isnan(sensorValues[SENSOR_TEMPERATURE])))
{ {
msg += "temperature=" + String(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 // wait unitl ready
do { do {

View file

@ -23,15 +23,19 @@ String _webUpdater_ip = "127.0.0.1";
String _webUpdater_dev = "unknown"; String _webUpdater_dev = "unknown";
float _webUpdater_sensValues[VALUES]; float _webUpdater_sensValues[VALUES];
String hb_ws_msg_start = "{"; const String hb_ws_msg_start = "{";
String hb_ws_msg_temp = "\"temperature\": "; const String hb_ws_msg_temp = "\"temperature\": ";
String hb_ws_msg_humi = "\"humidity\": "; const String hb_ws_msg_humi = "\"humidity\": ";
String hb_ws_msg_light = "\"lightlevel\": "; const String hb_ws_msg_light = "\"lightlevel\": ";
String hb_ws_msg_windspeed = "\"windspeed\": "; const String hb_ws_msg_windspeed = "\"windspeed\": ";
String hb_ws_msg_pressure = "\"pressure\": "; const String hb_ws_msg_pressure = "\"pressure\": ";
String hb_ws_msg_timestamp = "\"timestamp\": "; const String hb_ws_msg_timestamp = "\"timestamp\": ";
String hb_ws_msg_valid = "\"valid\": "; const String hb_ws_msg_valid = "\"valid\": ";
String hb_ws_msg_end = "}"; const String hb_ws_msg_end = "}";
#define TR_TD_START_STR "<tr><td>"
#define TR_TD_END_STR "</td></tr>"
#define TD_TD_MID_STR "</td><td>"
boolean wuValidData = false; boolean wuValidData = false;
@ -87,20 +91,22 @@ void showHTMLMain(void)
"</head><body>" "</head><body>"
"<br><a href=\"http://" + _webUpdater_ip + ":8080/update\">firmware update</a><br><br>" "<br><a href=\"http://" + _webUpdater_ip + ":8080/update\">firmware update</a><br><br>"
"<table>" "<table>"
"<tr><td>temperature</td><td>" + String(_webUpdater_sensValues[SENSOR_TEMPERATURE]) + "</td></tr>" TR_TD_START_STR + "temperature" + TD_TD_MID_STR + String(_webUpdater_sensValues[SENSOR_TEMPERATURE]) + TR_TD_END_STR
"<tr><td>humidity</td><td>" + String(_webUpdater_sensValues[SENSOR_HUMIDITY]) + "</td></tr>" TR_TD_START_STR + "humidity" + TD_TD_MID_STR + String(_webUpdater_sensValues[SENSOR_HUMIDITY]) + TR_TD_END_STR
"<tr><td>light</td><td>" + String(_webUpdater_sensValues[SENSOR_LIGHT]) + "</td></tr>" TR_TD_START_STR + "light" + TD_TD_MID_STR + String(_webUpdater_sensValues[SENSOR_LIGHT]) + TR_TD_END_STR
"<tr><td>windspeed</td><td>" + String(_webUpdater_sensValues[SENSOR_WINDSPEED]) + "</td></tr>" TR_TD_START_STR + "windspeed" + TD_TD_MID_STR + String(_webUpdater_sensValues[SENSOR_WINDSPEED]) + TR_TD_END_STR
"<tr><td>pressure</td><td>" + String(_webUpdater_sensValues[SENSOR_PRESSURE]) + "</td></tr>" TR_TD_START_STR + "pressure" + TD_TD_MID_STR + String(_webUpdater_sensValues[SENSOR_PRESSURE]) + TR_TD_END_STR
"<tr><td>batvoltage</td><td>" + String(_webUpdater_sensValues[SENSOR_BAT_VOLTAGE]) + "</td></tr>" TR_TD_START_STR + "batvoltage" + TD_TD_MID_STR + String(_webUpdater_sensValues[SENSOR_BAT_VOLTAGE]) + TR_TD_END_STR
"<tr><td>millis</td><td>" + String(millis()) + "</td></tr>" TR_TD_START_STR + "millis" + TD_TD_MID_STR + String(millis()) + TR_TD_END_STR
"<tr><td>valid</td><td>" + String(wuValidData) + "</td></tr>" 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
"</table>" "</table>"
"</body></html>"; "</body></html>";
httpServer.send(200, "text/html", message); httpServer.send(200, "text/html", message);
} }
#ifdef HOMEBRIDGE_WEBSTAT
void hb_webstat_send(void) void hb_webstat_send(void)
{ {
String msg = hb_ws_msg_start + String msg = hb_ws_msg_start +
@ -128,6 +134,7 @@ void hb_webstat_send(void)
httpServer.send(200, "text/html", msg); httpServer.send(200, "text/html", msg);
} }
#endif
void resetWifiManager() void resetWifiManager()
{ {
@ -151,6 +158,8 @@ void resetWifiManager()
ESP.restart(); ESP.restart();
} }
#ifdef DEBUG_WINDSPEED_MEASUREMENT
#ifdef SENSOR_WIND
void measureWindspeed() void measureWindspeed()
{ {
@ -168,3 +177,5 @@ void measureWindspeed()
httpServer.send(200, "text/html", message); httpServer.send(200, "text/html", message);
} }
#endif
#endif