// 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])() = {}; uint8_t sensor_value[] = { SENSOR_TEMPERATURE, SENSOR_HUMIDITY, SENSOR_LIGHT, SENSOR_WINDSPEED, SENSOR_PRESSURE, SENSOR_BAT_VOLTAGE, SENSOR_ESAVEMODE, SENSOR_BATCHARGESTATE }; uint32_t update_sensor_cnt = 0; uint32_t update_webserver_cnt = 0; uint32_t update_windspeed_exceed_cnt = 0; uint32_t wifi_check_interval_counter = 0; const String wifiName = "oko-weather-" + DEVICE_NAME; WiFiManager wifiManager; uint8_t fsm_state = FSM_STATE_WU; uint8_t sensor_cnt = 0; boolean validData = false; //*************************************************************************// void debug(String x) { #ifdef DEBUG Serial.println(x); #endif #ifdef USE_LOGGER logdata(String(millis()) + ":" + 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 ((wifi_check_interval_counter + WIFI_CHECK_INTERVAL_MS) > millis()) { // if check interval is not exceeded abort check return; } wifi_check_interval_counter = millis(); if (WiFi.status() == WL_CONNECTED) { // if we are connected return; } debug("no connection or time to check " + String(WiFi.status() == WL_CONNECTED)); 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")) { #ifdef SLEEP_IF_NO_WLAN_CONNECTION // If autoconnect to WLAN failed and no client connected, go to deep sleep 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 #ifdef BATTERY_POWERED delay(50); return; #endif // call sub loop function _loop(); // Needed to give WIFI time to function properly delay(DELAY_LOOP_MS); } //*************************************************************************// void _loop() { switch (fsm_state) { case FSM_STATE_WU: //debug("web updater call if required"); #ifdef WEBUPDATER_FEATURE if ((update_webserver_cnt + (UPDATE_WEBSERVER_INTVERVAL_S * 1000)) <= millis()) { //debug("web updater call"); update_webserver_cnt = millis(); doWebUpdater(); } #endif fsm_state = FSM_STATE_WSE; break; case FSM_STATE_WSE: debug("wind speed exceeded check if required"); #ifdef HTTP_CALL_ON_WINDSPEED_EXCEED if ((update_windspeed_exceed_cnt + (HTTP_CALL_ON_WINDSPEED_INTERVAL_S * 1000)) <= millis()) { debug("reading wind sensor exceed"); update_windspeed_exceed_cnt = millis(); readWindSpeedExceed(); } #endif fsm_state = FSM_STATE_RS; break; case FSM_STATE_RS: //debug("reset time check if required"); #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_WC; break; case FSM_STATE_WC: wifiConnectionCheck(); fsm_state = FSM_STATE_WS; break; case FSM_STATE_WS: //debug("disable measure of wind speed if required"); #ifdef defined(BATTERY_POWERED) && defined(SENSOR_WIND) if (energySavingMode() == 1) { // Disable expensive tasks sensors[SENSOR_WINDSPEED] = 0; //debug("read of wind sensor because of low battery disabled"); } else { sensors[SENSOR_WINDSPEED] = &wind_speed; //debug("read of wind sensor because of high battery enabled"); } #endif sensor_cnt = 0; fsm_state = FSM_STATE_US; break; case FSM_STATE_US: //debug("read sensor data check"); if ((update_sensor_cnt + (UPDATE_SENSOR_INTERVAL_S * 1000)) <= millis()) { debug("read sensor data " + String(sensor_cnt)); if (sensors[sensor_cnt]) { debug("sensors[sensor_value[" + String(sensor_cnt) + " ]]=" + String((int)sensors[sensor_value[sensor_cnt]]) + ":" + String(sensor_value[sensor_cnt])); currentSensorData[sensor_cnt] = sensors[sensor_value[sensor_cnt]](); //currentSensorData[sensor_cnt] = sensor_cnt; } else { debug("sensors[sensor_value[" + String(sensor_cnt) + "]]=nan"); currentSensorData[sensor_cnt] = nan("no value"); } if (sensor_cnt < VALUES) { sensor_cnt++; fsm_state = FSM_STATE_US; // jump to same state again, more sensors to read } else { update_sensor_cnt = millis(); sensor_cnt = 0; fsm_state = FSM_STATE_SC; // next state } } else { debug("skip read sensor data"); fsm_state = FSM_STATE_WU; // no new data, reset FSM } break; case FSM_STATE_SC: debug("log to serial if required"); #ifdef SERIAL_FEATURE logToSerial(currentSensorData); #endif fsm_state = FSM_STATE_ID; break; case FSM_STATE_ID: debug("send data to influxdb if required"); #ifdef INFLUXDB_FEATURE for (uint8_t i = 0; i < 5 and validData == false; i++) { if (currentSensorData[i] != 0) { validData = true; } } 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: debug("set sensor data in webupdater if required"); #ifdef WEBUPDATER_FEATURE setSensorData(currentSensorData); #endif fsm_state = FSM_STATE_WU; break; default: fsm_state = FSM_STATE_WU; break; } // close of switch //delay(100); // TODO warum hier ein delay? //debug("FSM state = " + String(fsm_state)); /*if (fsm_state == FSM_STATE_WU) { debug("----------"); }*/ } //*************************************************************************// void readWindSpeedExceed() { 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(); debug("http response code: " + String(httpResponseCode) + " = " + response); // TODO handle response } http.end(); debug("Called windspeed exceed callout"); digitalWrite(STATUS_LED_PIN, LOW); } #ifdef WEBUPDATER_FEATURE setSensorData(currentSensorData); #endif } else { currentSensorData[SENSOR_WINDSPEED] = nan("no value"); } } //*************************************************************************// 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])); } //*************************************************************************//