// Standard ESP8266 libs from project folder #include #include #include #include #include #include #include // WiFiClient #include // WiFiManager from bib manager // Project includes #include "constants.h" #include "config.h" #include "config_user.h" //*************************************************************************// // check if some settings are correct #ifdef HTTP_CALL_ON_WINDSPEED_EXCEED #if (HTTP_CALL_ON_WINDSPEED_INTERVAL_S < WIND_SENSOR_MEAS_TIME_S) #error "HTTP_CALL_ON_WINDSPEED_INTERVAL_S < WIND_SENSOR_MEAS_TIME_S" #endif #endif //*************************************************************************// // 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 (*sensors[VALUES])() = {}; uint16_t update_sensor_cnt = 0; uint16_t update_webserver_cnt = 0; 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) { #ifdef DEBUG Serial.println(x); #endif } //*************************************************************************// void setup() { #if defined(DEBUG) || defined(SERIAL_FEATURE) Serial.begin(115200); #endif // Pin settings pinMode(BAT_CHARGED_PIN, INPUT); pinMode(BAT_CHARGING_PIN, INPUT); pinMode(STATUS_LED_PIN, OUTPUT); pinMode(ANEMOMETER_PIN, INPUT_PULLUP); pinMode(A0, INPUT); digitalWrite(STATUS_LED_PIN, LOW); #ifndef BAT_PINS_D34 debug("D5 D6 used as battery pins"); #else debug("D3 D4 used as battery pins"); #endif #ifdef BATTERY_POWERED criticalBatCheck(); #endif 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()) { sensors[SENSOR_LIGHT] = &apds9930_light; } #endif #ifdef SENSOR_APDS9960 if (sensor_apds9960_begin()) { sensors[SENSOR_LIGHT] = &apds9960_light; } #endif #ifdef SENSOR_BME280 //Temperature + pressure if (sensor_bme280_begin(BME_ADDRESS)) { sensors[SENSOR_TEMPERATURE] = &bme280_temperature; sensors[SENSOR_HUMIDITY] = &bme280_humidity; sensors[SENSOR_PRESSURE] = &bme280_pressure; } #endif #ifdef SENSOR_WIND sensors[SENSOR_WINDSPEED] = &wind_speed; #endif #ifdef SENSOR_BATTERY sensors[SENSOR_BAT_VOLTAGE] = &battery_voltage; sensors[SENSOR_BATCHARGESTATE] = &battery_charging; sensors[SENSOR_ESAVEMODE] = &isEnergySavingMode; #endif } //*************************************************************************// void wifiConnectionCheck() { 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 wifiManager.setConnectTimeout(WIFI_AUTOCONNECT_TIMEOUT_S); // the time in seconds to wait for the user to configure the device wifiManager.setTimeout(WIFI_CONFIG_PORTAL_TIMEOUT_S); while (!wifiManager.autoConnect(wifiName.c_str(), "DEADBEEF")) { // 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); delay(100); #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 } } //*************************************************************************// #ifdef BATTERY_POWERED void criticalBatCheck() { float volt = battery_voltage(); if (volt <= BAT_EMERGENCY_DEEPSLEEP_VOLTAGE) { debug("Bat Voltage: " + String(volt) + " V"); debug("Low battery, going into deep sleep."); // Casting to an unsigned int, so it fits into the integer range ESP.deepSleep(1U * EMERGENCY_SLEEP_S * 1000000); // battery low, shutting down delay(100); } } #endif //*************************************************************************// void loop() { #ifdef ENABLE_WATCHDOG ESP.wdtFeed(); #endif wifiConnectionCheck(); #ifdef BATTERY_POWERED delay(50); return; #endif // call sub loop function _loop(); // Needed to give WIFI time to function properly delay(DELAY_LOOP_MS); update_sensor_cnt++; #ifdef WEBUPDATER_FEATURE update_webserver_cnt++; #endif #ifdef HTTP_CALL_ON_WINDSPEED_EXCEED update_windspeed_exceed_cnt++; #endif } //*************************************************************************// 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 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(); } #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; } #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; } #endif fsm_state = FSM_STATE_US; break; 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); #endif fsm_state = FSM_STATE_ID; break; //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); } #endif fsm_state = FSM_STATE_SD; break; case FSM_STATE_SD: #ifdef WEBUPDATER_FEATURE setSensorData(currentSensorData); #endif fsm_state = FSM_STATE_WU; break; default: fsm_state = FSM_STATE_WU; break; } // close of switch debug("FSM state = "+fsm_state); } void logToSerial(float sensorValues[]) { Serial.println(""); Serial.println("Current readings:"); Serial.println("Temperature: " + String(sensorValues[SENSOR_TEMPERATURE]) + " °C"); Serial.println("Humidity: " + String(sensorValues[SENSOR_HUMIDITY]) + " %"); Serial.println("Light: " + String(sensorValues[SENSOR_LIGHT]) + " Lux"); Serial.println("Windspeed: " + String(sensorValues[SENSOR_WINDSPEED]) + " km/h"); Serial.println("Pressure: " + String(sensorValues[SENSOR_PRESSURE]) + " hPa"); Serial.println("Bat Voltage: " + String(sensorValues[SENSOR_BAT_VOLTAGE]) + " V"); Serial.println("Bat charge state: " + String(sensorValues[SENSOR_BATCHARGESTATE])); Serial.println("Energy saving: " + String(sensorValues[SENSOR_ESAVEMODE])); }