// Arduino WiFi Barometer as HTTP server - V5.5 / 2018-03-18 // For ESP8266 and BMP280 sensor // Copyright 2018 Pavel Janko, www.fancon.cz // MIT license, http://opensource.org/licenses/MIT // Tested with ARDUINO IDE 1.8.5, Arduino-ESP8266 2.4.1 // // Properties: // - WiFi Protected Setup with PBC ready // - mDNS responder for connect by name // - HTTP BASIC authentication // - WiFi auto reconnect with restart // - Supports simply OTA from browser with password // (with at least 1MB of memory for OTA) // - Improved barometric formula // - Minimal and maximal pressure // - Dynamic trend of pressure in interval three hours // // Added libraries: // Adafruit Unified Sensor by Adafruit 1.0.2 // Adafruit BMP280 Library by Adafruit 1.0.2 // After flash from serial restart the device !!! // // Connection : // ESP8266-12 ------------------------------------------ // Vcc -> Power 3.3V // GND -> Power GND // CH_PD -> Vcc // RESET -> resistor 10Kohms to Vcc and switch to GND // GPIO0 -> resistor 10Kohms to Vcc and switch with // serial resistor around 330ohms to GND // GPIO2 -> resistor 10Kohms to Vcc // GPIO13 -> LED with serial resistor around 330ohms to GND // GPIO15 -> resistor 10Kohms to GND // Vcc -> Vcc BMP280 // GND -> GND BMP280 // GPIO4 -> SDA BMP280 // GPIO5 -> SCL BMP280 // -------------------------------------------------------- // // How to: // For local altitude correction, set LOCALALTUD in meters // // To connect to an access point, hold down the button (switch on GPIO0) for about // three seconds (LED on GPIO13 is lit permanently) and activate WPS // (Wi-Fi Protected Setup) with PBC (Push Button Configuration) on your Access point. // // For mDNS install Bonjour to your Windows - https://support.apple.com/bonjour // or Avahi for your Linux - https://www.avahi.org/ // mDNS name is defined as "barometer" below here. Just enter http://barometer.local // into the browser. But in my case, mDNS is sometimes // slower than a direct IP address. // // For web authentication set #define WWWAUTHENTI true and // your WWWUSERNAME and WWWPASSWORD below only. // // For OTA activation set OTAUSER, OTAPASSWORD and then in operation // write to browser address row http://barometer.local/firmware and upload your *.bin // file. // Default users and passwords are all "admin" // // |--------------------------------------------------------------------| // | Display | Value | // |--------------------------------------------------------------------| // | red marks | Maximum and minimum measured pressure | // | yellow mark | The difference between the yellow mark | // | | on the scale and pointer show trend of | // | | pressure in interval three hours. | // | olive green dot | Standard atmospheric pressure 1013.25 hPa | // |--------------------------------------------------------------------| // // |--------------------------------------------------------------------| // | Button - GPIO0 | LED - GPIO13| Action | // |--------------------------------------------------------------------| // | short press | ON or OFF | --- | // | long press > 3sec. | ON | wait for WPS from Access point | // | --- | flashes 4Hz | connection to WiFi | // | before power on | --- | flash mode | // |--------------------------------------------------------------------| // #include #include #include #include #include #include #include #include #define LOCALALTUD 208.0 // [m] Set your local altitude in meters #define INSIDE true // true = sensor inside, false = sensor outdoor #define STDTEMP 15.0 // [Celsius] Standard temperature #define STDPRESSURE 1013.25 // [hPa] Standard atmosferic pressure #define LENGTH 18 // length of string with old pressure data #define WWWPAGEREFR 30 // [s] Web page refresh time [s] #define WWWAUTHENTI false // Set true for web authentication #define WWWUSERNAME "admin" // Set www user name #define WWWPASSWORD "admin" // Set www user password #define OTAUSER "admin" // Set OTA user #define OTAPASSWORD "admin" // Set OTA password #define OTAPATH "/firmware"// Set path for update #define MDNSNAME "barometer"// Set local mDNS name #define SERVERPORT 80 // Server port #define ROUNDING 1 #define BUTTONPIN 0 // GPIO0 button pin #define LEDPIN 13 // GPIO13 LED #define SDAI2CPIN 4 // GPIO4 I2C SDA bus #define SCLI2CPIN 5 // GPIO5 I2C SCL bus #define BMP280ADDR 0x76 // Set BMP280 I2C address #define BUTTONTIME 0.25 // [s] Periodic time for button read #define SENSORTIME 10.0 // [s] Periodic time for sensor read #define WIFITIME 10.0 // [s] Periodic time for WiFi test #define TRENDTIME 600.0 // [s] Periodic time for calculation of trend bool ButtonFlag = false; bool SensorFlag = false; bool WifiFlag = false; bool TrendFlag = false; bool LedState = false; // LED off char ButtonCount = 0; float MaxPress = 95700.0; float MinPress = 106300.0; float SeaPressure; float Temperature; float Trend; float PointerAngle; float TrendAngle; float StdPssAngle; float MaxAngle; float MinAngle; float OldPressure[LENGTH]; ESP8266WebServer HttpServer(SERVERPORT); ESP8266HTTPUpdateServer httpUpdater; Ticker ButtonTick; // Preparing for periodic button reading Ticker SensorTick; // preparing for periodic sensor reading Ticker WifiTick; // preparing for periodic test WiFi connection Ticker TrendTick; // preparing for periodic trend calculation Adafruit_BMP280 bmp280; //----------------------------------------------------------------- void setup(void) { //Serial.begin(115200); WiFi.begin(); // Disable this line only if you can not use WPS //WiFi.persistent(false);// Enable this three lines only if you can not use WPS //WiFi.mode(WIFI_STA); // -"- //WiFi.begin(YourSSID,YourPassword); // -"- Wire.begin(SDAI2CPIN, SCLI2CPIN); bmp280.begin(BMP280ADDR); pinMode(BUTTONPIN, INPUT); pinMode(LEDPIN, OUTPUT); //Serial.println('\n'); /* wait for WiFi connect */ while (WiFi.status() != WL_CONNECTED) { GetButton(); delay(250); LedSet(!LedState); //Serial.print("."); } LedSet(false); //LED OFF //Serial.println('\n'); //Serial.print("Connected to "); //Serial.println(WiFi.SSID()); //Serial.print("IP address: "); //Serial.println(WiFi.localIP()); /* prepare first data for trend calculation */ for (int i = 0; i < LENGTH; i++)TrendCalc(); /* position of the standard pressure indicator */ StdPssAngle = (30.0 + (STDPRESSURE - 960.0) * 3.0); /* set interupt timer */ ButtonTick.attach(BUTTONTIME, ButtonFlagSet); SensorTick.attach(SENSORTIME, SensorFlagSet); WifiTick.attach(WIFITIME, WifiFlagSet); TrendTick.attach(TRENDTIME, TrendFlagSet); httpUpdater.setup(&HttpServer, OTAPATH, OTAUSER, OTAPASSWORD); MDNS.begin(MDNSNAME); HttpServer.on("/", HTTP_GET, ModifySendPage); HttpServer.onNotFound(handleNotFound); HttpServer.begin(); //Serial.println("HTTP server started"); } //----------------------------------------------------------------- void loop(void) { HttpServer.handleClient(); // Listen for HTTP requests from clients if (ButtonFlag) GetButton(); // Periodic serve button if (SensorFlag) SensorRead(); // Periodic sensor reading if (WifiFlag) WifiTest(); // Periodic test WiFi connection if (TrendFlag) TrendCalc(); // Periodic save trend data }//----------------------------------------------------------------- void ModifySendPage(void) { if (WWWAUTHENTI == true) { /* request for www user/password from client */ if (!HttpServer.authenticate(WWWUSERNAME, WWWPASSWORD)) return HttpServer.requestAuthentication(); } SendPage(); } void SendPage(void) { String buff = "\n"; buff += "Barometer\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "\n"; buff += "970\n"; buff += "980\n"; buff += "990\n"; buff += "1000\n"; buff += "1010\n"; buff += "1020\n"; buff += "1030\n"; buff += "1040\n"; buff += "1050\n"; buff += "hPa\n"; buff += "" + String(SeaPressure / 100, ROUNDING) + "\n"; buff += "hPa\n"; buff += "" + String(Temperature, ROUNDING) + "\n"; buff += "C\n"; /* grade marker */ buff += "\n"; /* mark of standard pressure */ buff += "\n"; /* minimum mark */ buff += "\n"; /* maximum mark */ buff += "\n"; /* trend mark */ buff += "\n"; buff += "\n"; HttpServer.send(200, "text/html", buff); } /* Send HTTP status 404 Not Found */ void handleNotFound(void) { HttpServer.send(404, "text/plain", "404: Not found"); } /* Read button on GPIO0*/ void GetButton(void) { /* short press butoon to change state of LED */ if (digitalRead(BUTTONPIN) == false ) ++ButtonCount; if (digitalRead(BUTTONPIN) == true && ButtonCount > 1 && ButtonCount < 12 ) { LedSet(!LedState); // change LED ButtonCount = 0; } /* long press button - WPS mode */ if (ButtonCount > 12) { LedSet(!LedState); // LED change ButtonTick.detach(); // Stop Tickers SensorTick.detach(); WifiTick.detach(); TrendTick.detach(); /* Wait for release button */ while (!digitalRead(BUTTONPIN))yield(); delay(100); StartWpsWaiting(); } if (digitalRead(BUTTONPIN) == true ) ButtonCount = 0; ButtonFlag = false; } /* Service Wi-Fi Protected Setup with Push Button Configuration */ void StartWpsWaiting(void) { WiFi.persistent(false); WiFi.mode(WIFI_STA); bool RafHo = false; String HowDelka = ""; /* Wait for access point WPS */ //Serial.println(""); //Serial.println("Wait for WPS"); do { RafHo = WiFi.beginWPSConfig(); //Serial.print("*"); HowDelka = WiFi.SSID(); } while (RafHo == false || HowDelka.length() == 0); //Serial.println(""); //Serial.println(WiFi.SSID()); //Serial.println(WiFi.psk()); delay(500); ESP.restart(); } /* If disconnected WiFi then restart */ void WifiTest(void) { if (WiFi.status() != WL_CONNECTED)ESP.restart(); WifiFlag = false; } void SensorRead(void) { Temperature = bmp280.readTemperature(); float Pressure = bmp280.readPressure(); if (INSIDE) { SeaPressure = Pressure / pow(1.0 - 0.0065 * LOCALALTUD / (STDTEMP + 273.15), 5.255); // as BOSCH formula } else { SeaPressure = Pressure / pow(1.0 - 0.0065 * LOCALALTUD / (Temperature + 273.15), 5.255); // ICAO formula } if (SeaPressure > MaxPress)MaxPress = SeaPressure; if (SeaPressure < MinPress)MinPress = SeaPressure; //Serial.println('\n'); //Serial.print("Temperature = "); //Serial.print(Temperature); //Serial.println(" *C"); //Serial.print("Pressure = "); //Serial.print(Pressure); //Serial.println(" Pa"); //Serial.print("At Sea Pressure = "); //Serial.print(SeaPressure); //Serial.println(" Pa"); //Serial.println("MaxPress"); //Serial.println(MaxPress); //Serial.println("MinPress"); //Serial.println(MinPress); //Serial.println("Trend"); //Serial.println(Trend); PointerAngle = (30.0 + (SeaPressure / 100.0 - 960.0) * 3.0); MaxAngle = (30.0 + (MaxPress / 100.0 - 960.0) * 3.0); MinAngle = (30.0 + (MinPress / 100.0 - 960.0) * 3.0); TrendAngle = (30.0 + (Trend / 100.0 - 960.0) * 3.0); SensorFlag = false; } void TrendCalc(void) { delay(10); SensorRead(); OldPressure[LENGTH - 1] = SeaPressure; for (int i = 0; i < (LENGTH - 1); i++) { OldPressure[i] = OldPressure[i + 1]; } Trend = OldPressure[0]; TrendFlag = false; } /* set LED */ void LedSet(bool SetLedState) { LedState = SetLedState; digitalWrite(LEDPIN, LedState); } void ButtonFlagSet(void) { ButtonFlag = true; } void SensorFlagSet(void) { SensorFlag = true; } void WifiFlagSet(void) { WifiFlag = true; } void TrendFlagSet(void) { TrendFlag = true; }