Skip to content
  • MySensors
  • OpenHardware.io
  • Categories
  • Recent
  • Tags
  • Popular
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Brand Logo
  1. Home
  2. My Project
  3. BMP280 + I2C

BMP280 + I2C

Scheduled Pinned Locked Moved My Project
11 Posts 5 Posters 30.4k Views 7 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • marekdM Offline
    marekdM Offline
    marekd
    wrote on last edited by
    #1

    Hello,
    This is my first post here, so please "be nice" to me.
    So far I built several nodes for temperature measurement, LED control, RF433 to control my outside sockets, in future my heating system will be based on reading from temperature nodes. Finishing at the moment irrigation controller for 8 zones ( think to post it when finish).

    Few days ago I received my BMP280 sensor
    for my outdoor weather station but couldn't find any projects here so I made it by myself (partly).
    So if anyone of you is going to use this sensor you may use this.
    Tested on Uno and works. I use Domoticz and it works just fine.

    //                  BMP280 I2C
    // this program is for BMP280 library :
    
     /*       
    	Bosch BMP280 pressure sensor library for the Arduino microcontroller.
    	This library uses I2C connection.
    
    	Uses floating-point equations from BMP280 datasheet.
    
    	modified by mhafuzul islam
    
    	version 1.01		 16/9/2014 initial version
    	https://github.com/mahfuz195/BMP280-Arduino-Library/tree/master/BMP280
    
    	Our example code uses the "pizza-eating" license. You can do anything
    	you like with this code. No really, anything. If you find it useful,
    	buy me italian pizza someday.
    
    I also used some parts from oryginal MySensors PressureSensor for BMP085 module  
    
    To use with MySensors 2.0.0 dev.branch
    
    * REVISION HISTORY
     * Version 1.0 - Henrik Ekblad
     * Version 1.1 - Marek Dajnowicz
    
    
    */
    
    
    // Enable debug prints to serial monitor
    #define MY_DEBUG
    //#define MY_REPEATER_FEATURE
    
    // Enable and select radio type attached
    #define MY_RADIO_NRF24
    
    //#define MY_NODE_ID 33 
    
    //#define MY_PARENT_NODE_ID
    
    #include <SPI.h>
    #include <MySensor.h>
    #include "BMP280.h"
    #include "Wire.h"
    
    #define P0 1010.6 // sea level pressure for my place
    #define CHILD_ID_TEMP 1
    #define CHILD_ID_PRESS 2
    
    const char *weather[] = { "stable", "sunny", "cloudy", "unstable", "thunderstorm", "unknown" };
    enum FORECAST
    {
      STABLE = 0,			// "Stable Weather Pattern"
      SUNNY = 1,			// "Slowly rising Good Weather", "Clear/Sunny "
      CLOUDY = 2,			// "Slowly falling L-Pressure ", "Cloudy/Rain "
      UNSTABLE = 3,		// "Quickly rising H-Press",     "Not Stable"
      THUNDERSTORM = 4,	// "Quickly falling L-Press",    "Thunderstorm"
      UNKNOWN = 5			// "Unknown (More Time needed)
    };
    
    BMP280 bmp; // call for sensor
    // for forecast
      float lastPressure = -1;
      float lastTemp = -1;
      int lastForecast = -1;
      const int LAST_SAMPLES_COUNT = 5;
      float lastPressureSamples[LAST_SAMPLES_COUNT];
      // this CONVERSION_FACTOR is used to convert from Pa to kPa in forecast algorithm
      // get kPa/h be dividing hPa by 10
      #define CONVERSION_FACTOR (1.0/10.0)
      int minuteCount = 0;
      bool firstRound = true;
      // average value is used in forecast algorithm.
      float pressureAvg;
      // average after 2 hours is used as reference value for the next iteration.
      float pressureAvg2;
      float dP_dt;
    
    // MyMessage to controler
    MyMessage msgT1(CHILD_ID_TEMP, V_TEMP);
    MyMessage msgP1(CHILD_ID_PRESS, V_PRESSURE);
    MyMessage msgF1(CHILD_ID_PRESS, V_FORECAST);
    
    // values for ServerUpdate, unmark when not using smartSleep
    //const unsigned long tUpdate = 60000; // update interval
    //unsigned long t0;
    
    void presentation()
    {
      // Send the sketch version information to the gateway and Controller
      sendSketchInfo("OUTSIDE P&T", "1.1");
      present(CHILD_ID_TEMP, S_TEMP);
      present(CHILD_ID_PRESS, S_BARO);
    }
    
    void setup()
    {
      delay(500);// just in case
      if (!bmp.begin())
      {
        Serial.println("BMP init failed!");
        while (1);
      }
      else Serial.println("BMP init success!");
      bmp.setOversampling(4);
      ServerUpdate(); // for first data reading and sending to controler
    }
    
    void loop()
    { smartSleep(60000); // adjust sleeping time here 1 minute in this case 
      ServerUpdate();
      //  if ((millis() - t0) > tUpdate) ServerUpdate();
    }
    
    void ServerUpdate() // used to read sensor data and send it to controler
    {
      double T, P;
      char result = bmp.startMeasurment();
    
      if (result != 0) {
        delay(result);
        result = bmp.getTemperatureAndPressure(T, P);
    
        int forecast = sample(P);
        if (result != 0)
        {
          // double A = bmp.altitude(P, P0); // this is to get barometric Altitude, not used in this program 
          send(msgT1.set(T, 1));
          send(msgP1.set(P, 1));
          send(msgF1.set(weather[forecast]));
          
       // unmark for debuging
       //   Serial.print("T = \t"); Serial.print(T, 1); Serial.print(" degC\t");
       //   Serial.print("P = \t"); Serial.print(P, 1); Serial.print(" mBar\t");
       //   Serial.print("A = \t"); Serial.print(A, 1); Serial.println(" m");
       //   Serial.print("F = \t"); Serial.print(weather[forecast]); Serial.println(" ?");
        }
        else {
          Serial.println("Error.");
        }
      }
      else {
        Serial.println("Error.");
      }
    
     // t0 = millis(); used without smartSleep
    }
    
    float getLastPressureSamplesAverage()
    {
      float lastPressureSamplesAverage = 0;
      for (int i = 0; i < LAST_SAMPLES_COUNT; i++)
      {
        lastPressureSamplesAverage += lastPressureSamples[i];
      }
      lastPressureSamplesAverage /= LAST_SAMPLES_COUNT;
    
      return lastPressureSamplesAverage;
    }
    
    // Algorithm found here
    // http://www.freescale.com/files/sensors/doc/app_note/AN3914.pdf
    // Pressure in hPa -->  forecast done by calculating kPa/h
    int sample(float pressure)
    {
      // Calculate the average of the last n minutes.
      int index = minuteCount % LAST_SAMPLES_COUNT;
      lastPressureSamples[index] = pressure;
    
      minuteCount++;
      if (minuteCount > 185)
      {
        minuteCount = 6;
      }
    
      if (minuteCount == 5)
      {
        pressureAvg = getLastPressureSamplesAverage();
      }
      else if (minuteCount == 35)
      {
        float lastPressureAvg = getLastPressureSamplesAverage();
        float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
        if (firstRound) // first time initial 3 hour
        {
          dP_dt = change * 2; // note this is for t = 0.5hour
        }
        else
        {
          dP_dt = change / 1.5; // divide by 1.5 as this is the difference in time from 0 value.
        }
      }
      else if (minuteCount == 65)
      {
        float lastPressureAvg = getLastPressureSamplesAverage();
        float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
        if (firstRound) //first time initial 3 hour
        {
          dP_dt = change; //note this is for t = 1 hour
        }
        else
        {
          dP_dt = change / 2; //divide by 2 as this is the difference in time from 0 value
        }
      }
      else if (minuteCount == 95)
      {
        float lastPressureAvg = getLastPressureSamplesAverage();
        float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
        if (firstRound) // first time initial 3 hour
        {
          dP_dt = change / 1.5; // note this is for t = 1.5 hour
        }
        else
        {
          dP_dt = change / 2.5; // divide by 2.5 as this is the difference in time from 0 value
        }
      }
      else if (minuteCount == 125)
      {
        float lastPressureAvg = getLastPressureSamplesAverage();
        pressureAvg2 = lastPressureAvg; // store for later use.
        float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
        if (firstRound) // first time initial 3 hour
        {
          dP_dt = change / 2; // note this is for t = 2 hour
        }
        else
        {
          dP_dt = change / 3; // divide by 3 as this is the difference in time from 0 value
        }
      }
      else if (minuteCount == 155)
      {
        float lastPressureAvg = getLastPressureSamplesAverage();
        float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
        if (firstRound) // first time initial 3 hour
        {
          dP_dt = change / 2.5; // note this is for t = 2.5 hour
        }
        else
        {
          dP_dt = change / 3.5; // divide by 3.5 as this is the difference in time from 0 value
        }
      }
      else if (minuteCount == 185)
      {
        float lastPressureAvg = getLastPressureSamplesAverage();
        float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
        if (firstRound) // first time initial 3 hour
        {
          dP_dt = change / 3; // note this is for t = 3 hour
        }
        else
        {
          dP_dt = change / 4; // divide by 4 as this is the difference in time from 0 value
        }
        pressureAvg = pressureAvg2; // Equating the pressure at 0 to the pressure at 2 hour after 3 hours have past.
        firstRound = false; // flag to let you know that this is on the past 3 hour mark. Initialized to 0 outside main loop.
      }
    
      int forecast = UNKNOWN;
      if (minuteCount < 35 && firstRound) //if time is less than 35 min on the first 3 hour interval.
      {
        forecast = UNKNOWN;
      }
      else if (dP_dt < (-0.25))
      {
        forecast = THUNDERSTORM;
      }
      else if (dP_dt > 0.25)
      {
        forecast = UNSTABLE;
      }
      else if ((dP_dt > (-0.25)) && (dP_dt < (-0.05)))
      {
        forecast = CLOUDY;
      }
      else if ((dP_dt > 0.05) && (dP_dt < 0.25))
      {
        forecast = SUNNY;
      }
      else if ((dP_dt > (-0.05)) && (dP_dt < 0.05))
      {
        forecast = STABLE;
      }
      else
      {
        forecast = UNKNOWN;
      }
    
      // uncomment when debugging
      //Serial.print(F("Forecast at minute "));
      //Serial.print(minuteCount);
      //Serial.print(F(" dP/dt = "));
      //Serial.print(dP_dt);
      //Serial.print(F("kPa/h --> "));
      //Serial.println(weather[forecast]);
    
      return forecast;
    }
    
    TheoLT 1 Reply Last reply
    4
    • E Offline
      E Offline
      emc2
      Hardware Contributor
      wrote on last edited by
      #2

      Are you using a BMP280 (temp + pressure) or as you linked a BME280 (temp + hum + pressure)?

      If you have a BME280 have a look at http://forum.mysensors.org/topic/2821/myweathergatewayesp8266-1-6-dev-branch for adding the humidity readings.

      marekdM 2 Replies Last reply
      1
      • marekdM marekd

        Hello,
        This is my first post here, so please "be nice" to me.
        So far I built several nodes for temperature measurement, LED control, RF433 to control my outside sockets, in future my heating system will be based on reading from temperature nodes. Finishing at the moment irrigation controller for 8 zones ( think to post it when finish).

        Few days ago I received my BMP280 sensor
        for my outdoor weather station but couldn't find any projects here so I made it by myself (partly).
        So if anyone of you is going to use this sensor you may use this.
        Tested on Uno and works. I use Domoticz and it works just fine.

        //                  BMP280 I2C
        // this program is for BMP280 library :
        
         /*       
        	Bosch BMP280 pressure sensor library for the Arduino microcontroller.
        	This library uses I2C connection.
        
        	Uses floating-point equations from BMP280 datasheet.
        
        	modified by mhafuzul islam
        
        	version 1.01		 16/9/2014 initial version
        	https://github.com/mahfuz195/BMP280-Arduino-Library/tree/master/BMP280
        
        	Our example code uses the "pizza-eating" license. You can do anything
        	you like with this code. No really, anything. If you find it useful,
        	buy me italian pizza someday.
        
        I also used some parts from oryginal MySensors PressureSensor for BMP085 module  
        
        To use with MySensors 2.0.0 dev.branch
        
        * REVISION HISTORY
         * Version 1.0 - Henrik Ekblad
         * Version 1.1 - Marek Dajnowicz
        
        
        */
        
        
        // Enable debug prints to serial monitor
        #define MY_DEBUG
        //#define MY_REPEATER_FEATURE
        
        // Enable and select radio type attached
        #define MY_RADIO_NRF24
        
        //#define MY_NODE_ID 33 
        
        //#define MY_PARENT_NODE_ID
        
        #include <SPI.h>
        #include <MySensor.h>
        #include "BMP280.h"
        #include "Wire.h"
        
        #define P0 1010.6 // sea level pressure for my place
        #define CHILD_ID_TEMP 1
        #define CHILD_ID_PRESS 2
        
        const char *weather[] = { "stable", "sunny", "cloudy", "unstable", "thunderstorm", "unknown" };
        enum FORECAST
        {
          STABLE = 0,			// "Stable Weather Pattern"
          SUNNY = 1,			// "Slowly rising Good Weather", "Clear/Sunny "
          CLOUDY = 2,			// "Slowly falling L-Pressure ", "Cloudy/Rain "
          UNSTABLE = 3,		// "Quickly rising H-Press",     "Not Stable"
          THUNDERSTORM = 4,	// "Quickly falling L-Press",    "Thunderstorm"
          UNKNOWN = 5			// "Unknown (More Time needed)
        };
        
        BMP280 bmp; // call for sensor
        // for forecast
          float lastPressure = -1;
          float lastTemp = -1;
          int lastForecast = -1;
          const int LAST_SAMPLES_COUNT = 5;
          float lastPressureSamples[LAST_SAMPLES_COUNT];
          // this CONVERSION_FACTOR is used to convert from Pa to kPa in forecast algorithm
          // get kPa/h be dividing hPa by 10
          #define CONVERSION_FACTOR (1.0/10.0)
          int minuteCount = 0;
          bool firstRound = true;
          // average value is used in forecast algorithm.
          float pressureAvg;
          // average after 2 hours is used as reference value for the next iteration.
          float pressureAvg2;
          float dP_dt;
        
        // MyMessage to controler
        MyMessage msgT1(CHILD_ID_TEMP, V_TEMP);
        MyMessage msgP1(CHILD_ID_PRESS, V_PRESSURE);
        MyMessage msgF1(CHILD_ID_PRESS, V_FORECAST);
        
        // values for ServerUpdate, unmark when not using smartSleep
        //const unsigned long tUpdate = 60000; // update interval
        //unsigned long t0;
        
        void presentation()
        {
          // Send the sketch version information to the gateway and Controller
          sendSketchInfo("OUTSIDE P&T", "1.1");
          present(CHILD_ID_TEMP, S_TEMP);
          present(CHILD_ID_PRESS, S_BARO);
        }
        
        void setup()
        {
          delay(500);// just in case
          if (!bmp.begin())
          {
            Serial.println("BMP init failed!");
            while (1);
          }
          else Serial.println("BMP init success!");
          bmp.setOversampling(4);
          ServerUpdate(); // for first data reading and sending to controler
        }
        
        void loop()
        { smartSleep(60000); // adjust sleeping time here 1 minute in this case 
          ServerUpdate();
          //  if ((millis() - t0) > tUpdate) ServerUpdate();
        }
        
        void ServerUpdate() // used to read sensor data and send it to controler
        {
          double T, P;
          char result = bmp.startMeasurment();
        
          if (result != 0) {
            delay(result);
            result = bmp.getTemperatureAndPressure(T, P);
        
            int forecast = sample(P);
            if (result != 0)
            {
              // double A = bmp.altitude(P, P0); // this is to get barometric Altitude, not used in this program 
              send(msgT1.set(T, 1));
              send(msgP1.set(P, 1));
              send(msgF1.set(weather[forecast]));
              
           // unmark for debuging
           //   Serial.print("T = \t"); Serial.print(T, 1); Serial.print(" degC\t");
           //   Serial.print("P = \t"); Serial.print(P, 1); Serial.print(" mBar\t");
           //   Serial.print("A = \t"); Serial.print(A, 1); Serial.println(" m");
           //   Serial.print("F = \t"); Serial.print(weather[forecast]); Serial.println(" ?");
            }
            else {
              Serial.println("Error.");
            }
          }
          else {
            Serial.println("Error.");
          }
        
         // t0 = millis(); used without smartSleep
        }
        
        float getLastPressureSamplesAverage()
        {
          float lastPressureSamplesAverage = 0;
          for (int i = 0; i < LAST_SAMPLES_COUNT; i++)
          {
            lastPressureSamplesAverage += lastPressureSamples[i];
          }
          lastPressureSamplesAverage /= LAST_SAMPLES_COUNT;
        
          return lastPressureSamplesAverage;
        }
        
        // Algorithm found here
        // http://www.freescale.com/files/sensors/doc/app_note/AN3914.pdf
        // Pressure in hPa -->  forecast done by calculating kPa/h
        int sample(float pressure)
        {
          // Calculate the average of the last n minutes.
          int index = minuteCount % LAST_SAMPLES_COUNT;
          lastPressureSamples[index] = pressure;
        
          minuteCount++;
          if (minuteCount > 185)
          {
            minuteCount = 6;
          }
        
          if (minuteCount == 5)
          {
            pressureAvg = getLastPressureSamplesAverage();
          }
          else if (minuteCount == 35)
          {
            float lastPressureAvg = getLastPressureSamplesAverage();
            float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
            if (firstRound) // first time initial 3 hour
            {
              dP_dt = change * 2; // note this is for t = 0.5hour
            }
            else
            {
              dP_dt = change / 1.5; // divide by 1.5 as this is the difference in time from 0 value.
            }
          }
          else if (minuteCount == 65)
          {
            float lastPressureAvg = getLastPressureSamplesAverage();
            float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
            if (firstRound) //first time initial 3 hour
            {
              dP_dt = change; //note this is for t = 1 hour
            }
            else
            {
              dP_dt = change / 2; //divide by 2 as this is the difference in time from 0 value
            }
          }
          else if (minuteCount == 95)
          {
            float lastPressureAvg = getLastPressureSamplesAverage();
            float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
            if (firstRound) // first time initial 3 hour
            {
              dP_dt = change / 1.5; // note this is for t = 1.5 hour
            }
            else
            {
              dP_dt = change / 2.5; // divide by 2.5 as this is the difference in time from 0 value
            }
          }
          else if (minuteCount == 125)
          {
            float lastPressureAvg = getLastPressureSamplesAverage();
            pressureAvg2 = lastPressureAvg; // store for later use.
            float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
            if (firstRound) // first time initial 3 hour
            {
              dP_dt = change / 2; // note this is for t = 2 hour
            }
            else
            {
              dP_dt = change / 3; // divide by 3 as this is the difference in time from 0 value
            }
          }
          else if (minuteCount == 155)
          {
            float lastPressureAvg = getLastPressureSamplesAverage();
            float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
            if (firstRound) // first time initial 3 hour
            {
              dP_dt = change / 2.5; // note this is for t = 2.5 hour
            }
            else
            {
              dP_dt = change / 3.5; // divide by 3.5 as this is the difference in time from 0 value
            }
          }
          else if (minuteCount == 185)
          {
            float lastPressureAvg = getLastPressureSamplesAverage();
            float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
            if (firstRound) // first time initial 3 hour
            {
              dP_dt = change / 3; // note this is for t = 3 hour
            }
            else
            {
              dP_dt = change / 4; // divide by 4 as this is the difference in time from 0 value
            }
            pressureAvg = pressureAvg2; // Equating the pressure at 0 to the pressure at 2 hour after 3 hours have past.
            firstRound = false; // flag to let you know that this is on the past 3 hour mark. Initialized to 0 outside main loop.
          }
        
          int forecast = UNKNOWN;
          if (minuteCount < 35 && firstRound) //if time is less than 35 min on the first 3 hour interval.
          {
            forecast = UNKNOWN;
          }
          else if (dP_dt < (-0.25))
          {
            forecast = THUNDERSTORM;
          }
          else if (dP_dt > 0.25)
          {
            forecast = UNSTABLE;
          }
          else if ((dP_dt > (-0.25)) && (dP_dt < (-0.05)))
          {
            forecast = CLOUDY;
          }
          else if ((dP_dt > 0.05) && (dP_dt < 0.25))
          {
            forecast = SUNNY;
          }
          else if ((dP_dt > (-0.05)) && (dP_dt < 0.05))
          {
            forecast = STABLE;
          }
          else
          {
            forecast = UNKNOWN;
          }
        
          // uncomment when debugging
          //Serial.print(F("Forecast at minute "));
          //Serial.print(minuteCount);
          //Serial.print(F(" dP/dt = "));
          //Serial.print(dP_dt);
          //Serial.print(F("kPa/h --> "));
          //Serial.println(weather[forecast]);
        
          return forecast;
        }
        
        TheoLT Offline
        TheoLT Offline
        TheoL
        Contest Winner
        wrote on last edited by
        #3

        @marekd Welcome on the forum. And thank you for sharing your sketch. Would love to see some pictures of your irrigation controller.

        marekdM 1 Reply Last reply
        1
        • E emc2

          Are you using a BMP280 (temp + pressure) or as you linked a BME280 (temp + hum + pressure)?

          If you have a BME280 have a look at http://forum.mysensors.org/topic/2821/myweathergatewayesp8266-1-6-dev-branch for adding the humidity readings.

          marekdM Offline
          marekdM Offline
          marekd
          wrote on last edited by
          #4

          @emc2 , must check it. the link is what I purchased.

          1 Reply Last reply
          0
          • TheoLT TheoL

            @marekd Welcome on the forum. And thank you for sharing your sketch. Would love to see some pictures of your irrigation controller.

            marekdM Offline
            marekdM Offline
            marekd
            wrote on last edited by
            #5

            @TheoL, I have some pictures of my Ver 1.0 (before I found MySensors), but anyway it was based on standard Promini + RTC, Bluetooth, LCD 16x2, Keyboard and some other sensors.
            And it was a bit messy with all the wires.

            Now is going to be based on Mega256, NRF24 ... still under development.
            0_1461441907000_IMG_20151229_193719.jpg 0_1461442038865_IMG_20160106_1828271.jpg 0_1461442190195_IMG_20151230_231357.jpg 0_1461442213334_IMG_20151230_231426.jpg

            TheoLT TRS-80T 2 Replies Last reply
            4
            • E emc2

              Are you using a BMP280 (temp + pressure) or as you linked a BME280 (temp + hum + pressure)?

              If you have a BME280 have a look at http://forum.mysensors.org/topic/2821/myweathergatewayesp8266-1-6-dev-branch for adding the humidity readings.

              marekdM Offline
              marekdM Offline
              marekd
              wrote on last edited by
              #6

              @emc2, Thank you for your comment, my sensor is BME280 so now I can use hum as well.
              I made quick upgrade of my sketch. Had to modify I2C address (good that you wrote that in your post), I change in the library for 0x76 instead.
              Here is my sketch for BME280:

              /*                  BME280 I2C for MySensors
              
              // this program is for BMEP280 library :Adafriut BME280 
              
              I use some parts from oryginal MySensors PressureSensor for BMP085 module  
              
              To use with MySensors 2.0.0 dev.branch
              
              * REVISION HISTORY
               * Version 1.0 - Henrik Ekblad
               * Version 1.2 - Marek Dajnowicz
              
              
              */
              
              
              // Enable debug prints to serial monitor
              #define MY_DEBUG
              //#define MY_REPEATER_FEATURE
              
              // Enable and select radio type attached
              #define MY_RADIO_NRF24
              
              //#define MY_NODE_ID 33 
              
              //#define MY_PARENT_NODE_ID
              
              #include <SPI.h>
              #include <MySensor.h>
              #include <Adafruit_Sensor.h>
              #include <Adafruit_BME280.h> // I had to change I2C address in library for 0x76 (line 32)
              #include "Wire.h"
              
              Adafruit_BME280 bme; // I2C
              
              #define CHILD_ID_HUM 0
              #define CHILD_ID_TEMP 1
              #define CHILD_ID_PRESS 2
              
              const char *weather[] = { "stable", "sunny", "cloudy", "unstable", "thunderstorm", "unknown" };
              enum FORECAST
              {
                STABLE = 0,			// "Stable Weather Pattern"
                SUNNY = 1,			// "Slowly rising Good Weather", "Clear/Sunny "
                CLOUDY = 2,			// "Slowly falling L-Pressure ", "Cloudy/Rain "
                UNSTABLE = 3,		// "Quickly rising H-Press",     "Not Stable"
                THUNDERSTORM = 4,	// "Quickly falling L-Press",    "Thunderstorm"
                UNKNOWN = 5			// "Unknown (More Time needed)
              };
              
              
              // for forecast - untouched by me :)
              
                float lastPressure = -1;
                float lastTemp = -1;
                int lastForecast = -1;
                const int LAST_SAMPLES_COUNT = 5;
                float lastPressureSamples[LAST_SAMPLES_COUNT];
                // this CONVERSION_FACTOR is used to convert from Pa to kPa in forecast algorithm
                // get kPa/h be dividing hPa by 10
                #define CONVERSION_FACTOR (1.0/10.0)
                int minuteCount = 0;
                bool firstRound = true;
                // average value is used in forecast algorithm.
                float pressureAvg;
                // average after 2 hours is used as reference value for the next iteration.
                float pressureAvg2;
                float dP_dt;
              
              // MyMessage to controler
              MyMessage msgT1(CHILD_ID_TEMP, V_TEMP);
              MyMessage msgP1(CHILD_ID_PRESS, V_PRESSURE);
              MyMessage msgF1(CHILD_ID_PRESS, V_FORECAST);
              MyMessage msgH1(CHILD_ID_HUM, V_HUM);
              
              void presentation()
              {
                // Send the sketch version information to the gateway and Controller
                sendSketchInfo("OUTSIDE P&T&H", "1.2");
                present(CHILD_ID_TEMP, S_TEMP);
                present(CHILD_ID_PRESS, S_BARO);
                present(CHILD_ID_HUM, S_HUM);  
              }
              
              void setup()
              {
                delay(500);// just in case
                if (!bme.begin())
                 {
                  Serial.println("BME init failed!");
                  while (1);
                 }
                else Serial.println("BME init success!");
                
                ServerUpdate(); // for first data reading and sending to controler
              }
              
              void loop()
              { 
                 smartSleep(60000); // adjust sleeping time here 1 minute in this case 
                 ServerUpdate();
              }
              
              void ServerUpdate() // used to read sensor data and send it to controller
              {
                double T, P, H;
                T=bme.readTemperature();
                P=bme.readPressure()/100.0;
                H=bme.readHumidity();
                
                  int forecast = sample(P);
                    send(msgT1.set(T, 1));
                    send(msgP1.set(P, 1));
                    send(msgH1.set(H,1));
                    send(msgF1.set(weather[forecast]));
                    
                 // unmark for debuging
                    Serial.print("T = \t"); Serial.print(T, 1); Serial.print(" degC\t");
                    Serial.print("P = \t"); Serial.print(P, 1); Serial.print(" mBar\t");
                    Serial.print("F = \t"); Serial.print(weather[forecast]); Serial.println(" ?");
              }
              
              float getLastPressureSamplesAverage()
              {
                float lastPressureSamplesAverage = 0;
                for (int i = 0; i < LAST_SAMPLES_COUNT; i++)
                {
                  lastPressureSamplesAverage += lastPressureSamples[i];
                }
                lastPressureSamplesAverage /= LAST_SAMPLES_COUNT;
              
                return lastPressureSamplesAverage;
              }
              
              // Algorithm found here
              // http://www.freescale.com/files/sensors/doc/app_note/AN3914.pdf
              // Pressure in hPa -->  forecast done by calculating kPa/h
              int sample(float pressure)
              {
                // Calculate the average of the last n minutes.
                int index = minuteCount % LAST_SAMPLES_COUNT;
                lastPressureSamples[index] = pressure;
              
                minuteCount++;
                if (minuteCount > 185)
                {
                  minuteCount = 6;
                }
              
                if (minuteCount == 5)
                {
                  pressureAvg = getLastPressureSamplesAverage();
                }
                else if (minuteCount == 35)
                {
                  float lastPressureAvg = getLastPressureSamplesAverage();
                  float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
                  if (firstRound) // first time initial 3 hour
                  {
                    dP_dt = change * 2; // note this is for t = 0.5hour
                  }
                  else
                  {
                    dP_dt = change / 1.5; // divide by 1.5 as this is the difference in time from 0 value.
                  }
                }
                else if (minuteCount == 65)
                {
                  float lastPressureAvg = getLastPressureSamplesAverage();
                  float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
                  if (firstRound) //first time initial 3 hour
                  {
                    dP_dt = change; //note this is for t = 1 hour
                  }
                  else
                  {
                    dP_dt = change / 2; //divide by 2 as this is the difference in time from 0 value
                  }
                }
                else if (minuteCount == 95)
                {
                  float lastPressureAvg = getLastPressureSamplesAverage();
                  float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
                  if (firstRound) // first time initial 3 hour
                  {
                    dP_dt = change / 1.5; // note this is for t = 1.5 hour
                  }
                  else
                  {
                    dP_dt = change / 2.5; // divide by 2.5 as this is the difference in time from 0 value
                  }
                }
                else if (minuteCount == 125)
                {
                  float lastPressureAvg = getLastPressureSamplesAverage();
                  pressureAvg2 = lastPressureAvg; // store for later use.
                  float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
                  if (firstRound) // first time initial 3 hour
                  {
                    dP_dt = change / 2; // note this is for t = 2 hour
                  }
                  else
                  {
                    dP_dt = change / 3; // divide by 3 as this is the difference in time from 0 value
                  }
                }
                else if (minuteCount == 155)
                {
                  float lastPressureAvg = getLastPressureSamplesAverage();
                  float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
                  if (firstRound) // first time initial 3 hour
                  {
                    dP_dt = change / 2.5; // note this is for t = 2.5 hour
                  }
                  else
                  {
                    dP_dt = change / 3.5; // divide by 3.5 as this is the difference in time from 0 value
                  }
                }
                else if (minuteCount == 185)
                {
                  float lastPressureAvg = getLastPressureSamplesAverage();
                  float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
                  if (firstRound) // first time initial 3 hour
                  {
                    dP_dt = change / 3; // note this is for t = 3 hour
                  }
                  else
                  {
                    dP_dt = change / 4; // divide by 4 as this is the difference in time from 0 value
                  }
                  pressureAvg = pressureAvg2; // Equating the pressure at 0 to the pressure at 2 hour after 3 hours have past.
                  firstRound = false; // flag to let you know that this is on the past 3 hour mark. Initialized to 0 outside main loop.
                }
              
                int forecast = UNKNOWN;
                if (minuteCount < 35 && firstRound) //if time is less than 35 min on the first 3 hour interval.
                {
                  forecast = UNKNOWN;
                }
                else if (dP_dt < (-0.25))
                {
                  forecast = THUNDERSTORM;
                }
                else if (dP_dt > 0.25)
                {
                  forecast = UNSTABLE;
                }
                else if ((dP_dt > (-0.25)) && (dP_dt < (-0.05)))
                {
                  forecast = CLOUDY;
                }
                else if ((dP_dt > 0.05) && (dP_dt < 0.25))
                {
                  forecast = SUNNY;
                }
                else if ((dP_dt > (-0.05)) && (dP_dt < 0.05))
                {
                  forecast = STABLE;
                }
                else
                {
                  forecast = UNKNOWN;
                }
              
                // uncomment when debugging
                //Serial.print(F("Forecast at minute "));
                //Serial.print(minuteCount);
                //Serial.print(F(" dP/dt = "));
                //Serial.print(dP_dt);
                //Serial.print(F("kPa/h --> "));
                //Serial.println(weather[forecast]);
              
                return forecast;
              }
              
              1 Reply Last reply
              1
              • marekdM marekd

                @TheoL, I have some pictures of my Ver 1.0 (before I found MySensors), but anyway it was based on standard Promini + RTC, Bluetooth, LCD 16x2, Keyboard and some other sensors.
                And it was a bit messy with all the wires.

                Now is going to be based on Mega256, NRF24 ... still under development.
                0_1461441907000_IMG_20151229_193719.jpg 0_1461442038865_IMG_20160106_1828271.jpg 0_1461442190195_IMG_20151230_231357.jpg 0_1461442213334_IMG_20151230_231426.jpg

                TheoLT Offline
                TheoLT Offline
                TheoL
                Contest Winner
                wrote on last edited by
                #7

                @marekd It looks great. Nice job.

                1 Reply Last reply
                0
                • E Offline
                  E Offline
                  emc2
                  Hardware Contributor
                  wrote on last edited by
                  #8

                  @marekd glad it was useful.

                  You may not need to change the address in the library.
                  If you add these 2 lines after #include <Adafruit_BME280.h> it should work without modifications of the library and so survive any future library updates.

                  #undef BME280_ADDRESS         // Undef BME280_ADDRESS from the BME280 library to easily override I2C address
                  #define BME280_ADDRESS (0x76) // Low = 0x76 , High = 0x77 (default on adafruit and sparkfun BME280 modules, default for library)
                  
                  N 1 Reply Last reply
                  0
                  • marekdM marekd

                    @TheoL, I have some pictures of my Ver 1.0 (before I found MySensors), but anyway it was based on standard Promini + RTC, Bluetooth, LCD 16x2, Keyboard and some other sensors.
                    And it was a bit messy with all the wires.

                    Now is going to be based on Mega256, NRF24 ... still under development.
                    0_1461441907000_IMG_20151229_193719.jpg 0_1461442038865_IMG_20160106_1828271.jpg 0_1461442190195_IMG_20151230_231357.jpg 0_1461442213334_IMG_20151230_231426.jpg

                    TRS-80T Offline
                    TRS-80T Offline
                    TRS-80
                    wrote on last edited by
                    #9

                    @marekd

                    Your irrigation controller looks really neat! I like that box man! Where did you get it?

                    marekdM 1 Reply Last reply
                    0
                    • TRS-80T TRS-80

                      @marekd

                      Your irrigation controller looks really neat! I like that box man! Where did you get it?

                      marekdM Offline
                      marekdM Offline
                      marekd
                      wrote on last edited by
                      #10

                      @TRS-80 Thanks. The box is MINI PRAGMA MIP12112 SCHNEIDER ELECTRIC got it from LeroyMerlin

                      1 Reply Last reply
                      1
                      • E emc2

                        @marekd glad it was useful.

                        You may not need to change the address in the library.
                        If you add these 2 lines after #include <Adafruit_BME280.h> it should work without modifications of the library and so survive any future library updates.

                        #undef BME280_ADDRESS         // Undef BME280_ADDRESS from the BME280 library to easily override I2C address
                        #define BME280_ADDRESS (0x76) // Low = 0x76 , High = 0x77 (default on adafruit and sparkfun BME280 modules, default for library)
                        
                        N Offline
                        N Offline
                        nbenm
                        wrote on last edited by
                        #11

                        @emc2 said in BMP280 + I2C:

                        @marekd glad it was useful.

                        You may not need to change the address in the library.
                        If you add these 2 lines after #include <Adafruit_BME280.h> it should work without modifications of the library and so survive any future library updates.

                        #undef BME280_ADDRESS         // Undef BME280_ADDRESS from the BME280 library to easily override I2C address
                        #define BME280_ADDRESS (0x76) // Low = 0x76 , High = 0x77 (default on adafruit and sparkfun BME280 modules, default for library)
                        

                        Thanks for this good idea, but it doesn't always work.
                        It's better to add the define before the include, in the sketch.
                        And to replace in the lib
                        #define BMP280_ADDRESS
                        by
                        #ifndef BME280_ADDRESS
                        #define BME280_ADDRESS (0x77)
                        #endif
                        Of course if library updates...

                        1 Reply Last reply
                        0
                        Reply
                        • Reply as topic
                        Log in to reply
                        • Oldest to Newest
                        • Newest to Oldest
                        • Most Votes


                        17

                        Online

                        11.7k

                        Users

                        11.2k

                        Topics

                        113.1k

                        Posts


                        Copyright 2025 TBD   |   Forum Guidelines   |   Privacy Policy   |   Terms of Service
                        • Login

                        • Don't have an account? Register

                        • Login or register to search.
                        • First post
                          Last post
                        0
                        • MySensors
                        • OpenHardware.io
                        • Categories
                        • Recent
                        • Tags
                        • Popular