Weather station

This project measures the temperature, humidity, atmosferic pressure (and much more... ) and display then on a web page.

Weather station

Things used in this project

 

Hardware components

HARDWARE LIST
1 SparkFun Atmospheric Sensor Breakout - BME280
1 DFRobot Monochrome 0.91”128x32 I2C OLED Display with Chip Pad
1 5 mm LED: Red
1 Pushbutton Switch, Momentary
1 Through Hole Resistor, 56 ohm
1 Breadboard (generic)
1 Jumper wires (generic)
1 Arduino Nano 33 IoT

Software apps and online services

 

Arduino IDE

Story

 

Hello this project uses a arduino nano 33 IOT, a BME280 and an i2c oled display. After power up, the software connects to a wifi access point and request an IP address by DHCP. Upon successfull connection, the display shows the affected IP address on the display. When connecting to the displayed IP address with a web browser, the parameter mesured from the BME280 apear on the scren and are refreshed every 5 seconds. The embbeded WebServer supports several connections and can be accessed over internet by bridging or by forwarding the appropriate port

Schematics

 

Weather station sketch

icon meteo_serveur_ycDFJFa6II.zip 7KB Download(0)

Code

 

Weather station software

C/C++

CODE
#include <Wire.h>
#include <WiFiNINA.h>
#include <EnvironmentCalculations.h>
#include <BME280I2C.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
#define SCREEN_ADDRESS 0x3C
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)

#define SECRET_SSID "YOUR SSID"   //Your SSID
#define SECRET_PASS "YOUR PASSWORD"  //Your password

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID;        // your network SSID (name)
char pass[] = SECRET_PASS;    // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0;  // your network key index number (needed only for WEP)
float referencePressure = 1018.6;  // hPa local QFF (official meteor-station reading)
float outdoorTemp = 4.7;           // C  measured local outdoor temp.
float barometerAltitude = 1650.3;  // meters ... map readings + barometer position
BME280I2C::Settings settings(
   BME280::OSR_X1,
   BME280::OSR_X1,
   BME280::OSR_X1,
   BME280::Mode_Forced,
   BME280::StandbyTime_1000ms,
   BME280::Filter_16,
   BME280::SpiEnable_False,
   BME280I2C::I2CAddr_0x76
);

BME280I2C bme(settings);

int status = WL_IDLE_STATUS;

WiFiServer server(80);

void setup() {
   Serial.begin(9600);
   
   pinMode(LED_BUILTIN, OUTPUT);

  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) { // Address 0x3C for 128x32
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }

  display.display();// Show initial display buffer contents on the screen --
  // the library initializes this with an Adafruit splash screen.
  display.clearDisplay();  // Clear the buffer

  String fv = WiFi.firmwareVersion();
  if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
    Serial.println("Please upgrade the firmware");
  }

  // attempt to connect to WiFi network:
  while (status != WL_CONNECTED) {

    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);
  }
    if(status = WL_CONNECTED){
      digitalWrite(LED_BUILTIN, HIGH);
       display.setTextSize(1);             // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE);        // Draw white text
  display.setCursor(0,0);
      display.println("connected!");
      display.display();
    }
    else{
    }
  
  server.begin();
  printWifiStatus();  // you're connected now, so print out the status:

   Wire.begin();

  while(!bme.begin())
  {
    Serial.print("Could not find BME280 sensor!");
    delay(100);
  }

  switch(bme.chipModel())
  {
     case BME280::ChipModel_BME280:
       Serial.println("Found BME280 sensor! Success.");
       break;
     case BME280::ChipModel_BMP280:
       Serial.println("Found BMP280 sensor! No Humidity available.");
       break;
     default:
       Serial.println("Found UNKNOWN sensor! Error!");
  }
}

void loop() {
  
  float temp(NAN), hum(NAN), pres(NAN);

   BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
   BME280::PresUnit presUnit(BME280::PresUnit_hPa);
   
  WiFiClient client = server.available();
  if (client) {
    Serial.println("new client");
    boolean currentLineIsBlank = true;// an HTTP request ends with a blank line
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the HTTP request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          // send a standard HTTP response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the response
          client.println("Refresh: 5");  // refresh the page automatically every 5 sec
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");
          client.println("<head>");
          client.print("<title>WEATHER STATION</title>");// Your title on the tab
          client.println("</head>");
          client.print("<body>");
          client.print("<h1><center>WEATHER STATION</center></h1>");//Your title
          client.print("</body>");
          client.print("</html>");

bme.read(pres, temp, hum, tempUnit, presUnit);
   client.print("<center>");
   client.print("<h2><p>Temp: ");
   client.print(temp);
   client.print("&#176"+ String(tempUnit == BME280::TempUnit_Celsius ? "C" :"F"));
   client.println("<br />");
   client.print("\t\tHumidity: ");
   client.print(hum);
   client.print("% RH");
   client.println("<br />");
   client.print("\t\tPressure: ");
   client.print(pres);
   client.print(String(presUnit == BME280::PresUnit_hPa ? "hPa" : "Pa")); // expected hPa and Pa only
   client.println("<br />");
   EnvironmentCalculations::AltitudeUnit envAltUnit  =  EnvironmentCalculations::AltitudeUnit_Meters;
   EnvironmentCalculations::TempUnit     envTempUnit =  EnvironmentCalculations::TempUnit_Celsius;

   /// To get correct local altitude/height (QNE) the reference Pressure
   ///    should be taken from meteorologic messages (QNH or QFF)
   float altitude = EnvironmentCalculations::Altitude(pres, envAltUnit, referencePressure, outdoorTemp, envTempUnit);

   float dewPoint = EnvironmentCalculations::DewPoint(temp, hum, envTempUnit);

   /// To get correct seaLevel pressure (QNH, QFF)
   ///    the altitude value should be independent on measured pressure.
   /// It is necessary to use fixed altitude point e.g. the altitude of barometer read in a map
   float seaLevel = EnvironmentCalculations::EquivalentSeaLevelPressure(barometerAltitude, temp, pres, envAltUnit, envTempUnit);

   float absHum = EnvironmentCalculations::AbsoluteHumidity(temp, hum, envTempUnit);

   client.print("\t\tAltitude: ");
   client.print(altitude);
   client.print((envAltUnit == EnvironmentCalculations::AltitudeUnit_Meters ? "m" : "ft"));
   client.println("<br />");
   client.print("\t\tDew point: ");
   client.print(dewPoint);
   client.print("&#176"+ String(envTempUnit == EnvironmentCalculations::TempUnit_Celsius ? "C" :"F"));
   client.println("<br />");
   client.print("\t\tEquivalent Sea Level Pressure: ");
   client.print(seaLevel);
   client.print(String( presUnit == BME280::PresUnit_hPa ? "hPa" :"Pa")); // expected hPa and Pa only
   client.println("<br />");

   client.print("\t\tHeat Index: ");
   float heatIndex = EnvironmentCalculations::HeatIndex(temp, hum, envTempUnit);
   client.print(heatIndex);
   client.print("&#176"+ String(envTempUnit == EnvironmentCalculations::TempUnit_Celsius ? "C" :"F"));
   client.println("<br />");
   client.print("\t\tAbsolute Humidity: ");
   client.println(absHum);
   client.print("%");
             
          client.println("<br />");
          client.println("</html>");
          client.print("<style>body{background-color: White ;}");// You can choose your backround-color
          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        } else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
    Serial.println("client disconnected");
  }
}

void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your board's IP address:
  IPAddress ip = WiFi.localIP();
  display.setTextSize(1);             // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE);        // Draw white text
  display.setCursor(0,10);
  display.print("IP Address: \n");
  display.println(ip);
  display.display();
  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

The article was first published in hackster, October 30, 2022

cr: https://www.hackster.io/nante/weather-station-4dcefc

author: nante

License
All Rights
Reserved
licensBg
0