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. Hardware
  3. BME280 temp/humidity/pressure sensor

BME280 temp/humidity/pressure sensor

Scheduled Pinned Locked Moved Hardware
31 Posts 13 Posters 32.6k Views 17 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.
  • hekH hek

    Hmm.. I wonder if this change might have interfered with the Vera plugin.

    https://github.com/mysensors/Arduino/commit/bbc6a221f4c153f41993207e521f5531ba853d1a

    https://github.com/mysensors/Arduino/pull/420

    signal15S Offline
    signal15S Offline
    signal15
    wrote on last edited by
    #14

    @hek

    Let me know if you make a change and need me to test.

    1 Reply Last reply
    0
    • signal15S signal15

      Awesome. I just got it working with a test sketch like 2 minutes ago. If I get a working sketch for MySensors, how can I get it uploaded to the site as an example?

      Also, if anyone has done it before, I'd appreciate any code you might have to save some time. I only get like 5 minutes here an there to work on this.

      Y Offline
      Y Offline
      yoshida
      wrote on last edited by
      #15

      @emc2 or anybody:

      Does anyone have a working BME280 mysensors arduino sketch? The code above states include mysensor.h now it is mysensorS.h, so I have renamed, but it won't compile, it says:

      In function 'void setup()':
      
      bme280:252: error: 'getConfig' was not declared in this scope
      

      I have a MySensors Gateway USB
      Version: 2.1.1 (arduino nano) with Domoticz, and I would like to use the bme280 for a battery powered outdoor temp/humidity/barometer (as DHT22 does not like battery level below 3.3V, and I would run on 2x1.5V AA)

      Thanks

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

        Was modified in 2.1.1, you need to change

        metric = getConfig().isMetric;
        

        to

        metric = getControllerConfig().isMetric;  // was getConfig().isMetric; before MySensors v2.1.1
        
        Y 1 Reply Last reply
        1
        • A Offline
          A Offline
          anno
          wrote on last edited by anno
          #17

          Still a lot of errors in this sketch, did take some out but this is still in it:

          In file included from C:\Users\x\Documents\Arduino\BME280_sensor\BME280_sensor.ino:48:0:

          C:\Users\x\Documents\Arduino\libraries\BME280/BME280_MOD-1022.h:41:21: warning: extra tokens at end of #ifndef directive

          #ifndef __BME280_MOD-1022_H

                           ^
          

          C:\Users\x\Documents\Arduino\libraries\BME280/BME280_MOD-1022.h:42:21: warning: ISO C99 requires whitespace after the macro name

          #define __BME280_MOD-1022_H

                           ^
          

          In file included from C:\Users\x\Documents\Arduino\libraries\BME280\BME280_MOD-1022.cpp:40:0:

          C:\Users\x\Documents\Arduino\libraries\BME280\BME280_MOD-1022.h:41:21: warning: extra tokens at end of #ifndef directive

          #ifndef __BME280_MOD-1022_H

                           ^
          

          C:\Users\x\Documents\Arduino\libraries\BME280\BME280_MOD-1022.h:42:21: warning: ISO C99 requires whitespace after the macro name

          #define __BME280_MOD-1022_H

                           ^
          

          C:\Users\x\Documents\Arduino\libraries\BME280\BME280_MOD-1022.cpp: In member function 'BME280Class::readCompensationParams()':

          C:\Users\x\Documents\Arduino\libraries\BME280\BME280_MOD-1022.cpp:276:45: warning: iteration 20 invokes undefined behavior [-Waggressive-loop-optimizations]

          compParams.compArray[count] = Wire.read();
          
                                                   ^
          

          C:\Users\x\Documents\Arduino\libraries\BME280\BME280_MOD-1022.cpp:275:3: note: containing loop

          for (count = 0; count < 28; count++) { // first 28 bytes we can process like this

          ^

          C:\Users\x\Documents\Arduino\BME280_sensor\BME280_sensor.ino: In function 'loop':

          C:\Users\x\Documents\Arduino\libraries\BME280\BME280_MOD-1022.cpp:276:45: warning: iteration 20 invokes undefined behavior [-Waggressive-loop-optimizations]

          compParams.compArray[count] = Wire.read();
          
                                                   ^
          

          C:\Users\x\Documents\Arduino\libraries\BME280\BME280_MOD-1022.cpp:275:3: note: containing loop

          for (count = 0; count < 28; count++) { // first 28 bytes we can process like this

          1 Reply Last reply
          0
          • E emc2

            Was modified in 2.1.1, you need to change

            metric = getConfig().isMetric;
            

            to

            metric = getControllerConfig().isMetric;  // was getConfig().isMetric; before MySensors v2.1.1
            
            Y Offline
            Y Offline
            yoshida
            wrote on last edited by
            #18

            @emc2 Thanks! With this modification the sketch compiled successfully. Today I had time, so put everything together, and the BME280 works with the 2.4GH radio, temp/hum/pressure all reporting like they should.

            Using arduino pro mini, bme280, nrf24, 2XAA Batteries. It reports to the mysensors serial gw, and then shown in domoticz.

            Z 1 Reply Last reply
            2
            • Y yoshida

              @emc2 Thanks! With this modification the sketch compiled successfully. Today I had time, so put everything together, and the BME280 works with the 2.4GH radio, temp/hum/pressure all reporting like they should.

              Using arduino pro mini, bme280, nrf24, 2XAA Batteries. It reports to the mysensors serial gw, and then shown in domoticz.

              Z Offline
              Z Offline
              Zbigniew Ko
              wrote on last edited by
              #19

              @yoshida Hello
              You can share your sketch.
              Please
              I can not make modifications.
              I still have a lot of errors.

              Y 1 Reply Last reply
              0
              • A Offline
                A Offline
                anno
                wrote on last edited by anno
                #20
                This post is deleted!
                1 Reply Last reply
                0
                • Z Zbigniew Ko

                  @yoshida Hello
                  You can share your sketch.
                  Please
                  I can not make modifications.
                  I still have a lot of errors.

                  Y Offline
                  Y Offline
                  yoshida
                  wrote on last edited by
                  #21

                  Zbigniew Ko:

                  (2.1.1 mysensors compatible, but first you need to install the BME280_MOD-1022.h library in arduino IDE)

                  /**
                   * The MySensors Arduino library handles the wireless radio link and protocol
                   * between your home built sensors/actuators and HA controller of choice.
                   * The sensors forms a self healing radio network with optional repeaters. Each
                   * repeater and gateway builds a routing tables in EEPROM which keeps track of the
                   * network topology allowing messages to be routed to nodes.
                   *
                   * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
                   * Copyright (C) 2013-2015 Sensnology AB
                   * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
                   *
                   * Documentation: http://www.mysensors.org
                   * Support Forum: http://forum.mysensors.org
                   *
                   * This program is free software; you can redistribute it and/or
                   * modify it under the terms of the GNU General Public License
                   * version 2 as published by the Free Software Foundation.
                   *
                   *******************************
                   *
                   * REVISION HISTORY
                   * Version 1.0 - Henrik Ekblad
                   * 
                   * DESCRIPTION
                   * Pressure sensor example using BMP085 module  
                   * http://www.mysensors.org/build/pressure
                   *
                   */
                  
                  // Enable debug prints to serial monitor
                  #define MY_DEBUG 
                  
                  // Enable and select radio type attached
                  #define MY_RADIO_NRF24
                  //#define MY_RADIO_RFM69
                  
                  #include <SPI.h>
                  #include <MySensors.h>  
                  #include <Wire.h>
                  
                  // BME280 libraries and variables
                  // Bosch BME280 Embedded Adventures MOD-1022 weather multi-sensor Arduino code
                  // Written originally by Embedded Adventures
                  // https://github.com/embeddedadventures/BME280
                  #include <BME280_MOD-1022.h>
                  
                  #define BARO_CHILD 0
                  #define TEMP_CHILD 1
                  #define HUM_CHILD 2
                  
                  const float ALTITUDE = 184; // <-- adapt this value to your location's altitude (in m). Use your smartphone GPS to get an accurate value!
                  
                  // Sleep time between reads (in ms). Do not change this value as the forecast algorithm needs a sample every minute.
                  const unsigned long SLEEP_TIME = 60000; 
                  
                  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)
                  };
                  
                  float lastPressure = -1;
                  float lastTemp = -1;
                  float lastHum = -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 the forecast algorithm
                  // get kPa/h by 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;
                  boolean metric;
                  MyMessage tempMsg(TEMP_CHILD, V_TEMP);
                  MyMessage humMsg(HUM_CHILD, V_HUM);
                  MyMessage pressureMsg(BARO_CHILD, V_PRESSURE);
                  MyMessage forecastMsg(BARO_CHILD, V_FORECAST);
                  
                  
                  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;
                  }
                  
                  
                  void setup() {
                    metric = getControllerConfig().isMetric;  // was getConfig().isMetric; before MySensors v2.1.1
                    Wire.begin(); // Wire.begin(sda, scl)
                  }
                  
                  void presentation()  {
                    // Send the sketch version information to the gateway and Controller
                    sendSketchInfo("BME280 Sensor", "1.6");
                  
                    // Register sensors to gw (they will be created as child devices)
                    present(BARO_CHILD, S_BARO);
                    present(TEMP_CHILD, S_TEMP);
                    present(HUM_CHILD, S_HUM);
                  }
                  
                  // Loop
                  void loop() {
                    
                    // need to read the NVM compensation parameters
                    BME280.readCompensationParams();
                  
                    /* After taking the measurement the chip goes back to sleep, use when battery powered.
                    // Oversampling settings (os1x, os2x, os4x, os8x or os16x).
                    BME280.writeFilterCoefficient(fc_16);       // IIR Filter coefficient, higher numbers avoid sudden changes to be accounted for (such as slamming a door)
                    BME280.writeOversamplingPressure(os16x);    // pressure x16
                    BME280.writeOversamplingTemperature(os8x);  // temperature x8
                    BME280.writeOversamplingHumidity(os8x);     // humidity x8
                  
                    BME280.writeMode(smForced);                 // Forced sample.  After taking the measurement the chip goes back to sleep
                    */
                  
                    // Normal mode for regular automatic samples
                    BME280.writeStandbyTime(tsb_0p5ms);         // tsb = 0.5ms
                    BME280.writeFilterCoefficient(fc_16);       // IIR Filter coefficient 16
                    BME280.writeOversamplingPressure(os16x);    // pressure x16
                    BME280.writeOversamplingTemperature(os8x);  // temperature x8
                    BME280.writeOversamplingHumidity(os8x);     // humidity x8
                    
                    BME280.writeMode(smNormal);
                    
                    while (1) {
                      // Just to be sure, wait until sensor is done mesuring  
                      while (BME280.isMeasuring()) {
                    }
                    
                    // Read out the data - must do this before calling the getxxxxx routines
                    BME280.readMeasurements();
                  
                    float temperature = BME280.getTemperatureMostAccurate();                    // must get temp first
                    float humidity = BME280.getHumidityMostAccurate();
                    float pressure_local = BME280.getPressureMostAccurate();                    // Get pressure at current location
                    float pressure = pressure_local/pow((1.0 - ( ALTITUDE / 44330.0 )), 5.255); // Adjust to sea level pressure using user altitude
                    int forecast = sample(pressure);
                    
                    if (!metric) 
                    {
                      // Convert to fahrenheit
                      temperature = temperature * 9.0 / 5.0 + 32.0;
                    }
                  
                    Serial.println();
                    Serial.print("Temperature = ");
                    Serial.print(temperature);
                    Serial.println(metric ? " °C" : " °F");
                    Serial.print("Humidity = ");
                    Serial.print(humidity);
                    Serial.println(" %");
                    Serial.print("Pressure = ");
                    Serial.print(pressure);
                    Serial.println(" hPa");
                    Serial.print("Forecast = ");
                    Serial.println(weather[forecast]);
                    Serial.println();
                  
                  
                    if (temperature != lastTemp) 
                    {
                      send(tempMsg.set(temperature, 1));
                      lastTemp = temperature;
                    }
                  
                  
                    if (humidity != lastHum) 
                    {
                      send(humMsg.set(humidity, 1));
                      lastHum = humidity;
                    }
                  
                    if (pressure != lastPressure) 
                    {
                      send(pressureMsg.set(pressure, 2));
                      lastPressure = pressure;
                    }
                  
                    if (forecast != lastForecast)
                    {
                      send(forecastMsg.set(weather[forecast]));
                      lastForecast = forecast;
                    }
                    
                    sleep(SLEEP_TIME);
                    
                  }
                  }
                  
                  
                  1 Reply Last reply
                  0
                  • Z Offline
                    Z Offline
                    Zbigniew Ko
                    wrote on last edited by Zbigniew Ko
                    #22

                    @yoshida Thank you very much.
                    As soon as I find time I will check it out.

                    Yes checked, sketch works.
                    Thanks yoshida.
                    Please note that the library BME_MOD-1022.h consists of two parts: file-h, and file cpp.

                    1 Reply Last reply
                    0
                    • gohanG Offline
                      gohanG Offline
                      gohan
                      Mod
                      wrote on last edited by
                      #23

                      I am using the one from adafruit : what's the difference with this other library?

                      alexsh1A 1 Reply Last reply
                      0
                      • gohanG gohan

                        I am using the one from adafruit : what's the difference with this other library?

                        alexsh1A Offline
                        alexsh1A Offline
                        alexsh1
                        wrote on last edited by
                        #24

                        @gohan I have been using both libraries with a chinese module I bought from Aliexpress. I did not notice any differences apart from size and maybe a module address, which you can change in either library.

                        1 Reply Last reply
                        0
                        • B Offline
                          B Offline
                          bluezr1
                          wrote on last edited by
                          #25

                          I used the last sketch posed by Yoshida and for some reason whenever the temp and humidity goes through a stretch where there isn't any change, it's as if the node goes into a deep sleep and doesn't come out of it until I hit the reset on a pro mini.

                          I have it plunged in and not on batteries, so no need for any deep sleep. Is there anything I can change in the sketch? I'm still fairly new at this, although I'm having a blast.

                          Thanks,

                          Y 1 Reply Last reply
                          0
                          • B bluezr1

                            I used the last sketch posed by Yoshida and for some reason whenever the temp and humidity goes through a stretch where there isn't any change, it's as if the node goes into a deep sleep and doesn't come out of it until I hit the reset on a pro mini.

                            I have it plunged in and not on batteries, so no need for any deep sleep. Is there anything I can change in the sketch? I'm still fairly new at this, although I'm having a blast.

                            Thanks,

                            Y Offline
                            Y Offline
                            yoshida
                            wrote on last edited by
                            #26

                            @bluezr1 Interesting... :) I used it with a pro mini as well, and my problem was that it ate up the batteries in 2 weeks... :D So I would need more deep sleep for the same sketch :D

                            But for that 2 weeks, it was working well. Temp/Hum/Baro updated every minute.

                            mfalkviddM 1 Reply Last reply
                            0
                            • Y yoshida

                              @bluezr1 Interesting... :) I used it with a pro mini as well, and my problem was that it ate up the batteries in 2 weeks... :D So I would need more deep sleep for the same sketch :D

                              But for that 2 weeks, it was working well. Temp/Hum/Baro updated every minute.

                              mfalkviddM Offline
                              mfalkviddM Offline
                              mfalkvidd
                              Mod
                              wrote on last edited by mfalkvidd
                              #27

                              @yoshida did you do the modifications (remove led and regulator) recommended at https://www.mysensors.org/build/battery ?

                              My storage room sensor (https://forum.mysensors.org/topic/7227/esp8266-wifi-gateway-with-rssi-for-rfm69-and-wifi ) uses the bme280. Not sure if that sketch is any help, but you are welcome to use it. It is much much simpler than the sketch posted above though.

                              Y 1 Reply Last reply
                              0
                              • mfalkviddM mfalkvidd

                                @yoshida did you do the modifications (remove led and regulator) recommended at https://www.mysensors.org/build/battery ?

                                My storage room sensor (https://forum.mysensors.org/topic/7227/esp8266-wifi-gateway-with-rssi-for-rfm69-and-wifi ) uses the bme280. Not sure if that sketch is any help, but you are welcome to use it. It is much much simpler than the sketch posted above though.

                                Y Offline
                                Y Offline
                                yoshida
                                wrote on last edited by
                                #28

                                @mfalkvidd good question, yes I have removed the two leds I found, but I am too lame to remove the voltage regulator :( I have read here that the most consuming part is the LED(s)

                                1 Reply Last reply
                                1
                                • S Offline
                                  S Offline
                                  scalpel
                                  wrote on last edited by gohan
                                  #29

                                  @yoshida said in BME280 temp/humidity/pressure sensor:

                                  > /**
                                  >  * The MySensors Arduino library handles the wireless radio link and protocol
                                  >  * between your home built sensors/actuators and HA controller of choice.
                                  >  * The sensors forms a self healing radio network with optional repeaters. Each
                                  >  * repeater and gateway builds a routing tables in EEPROM which keeps track of the
                                  >  * network topology allowing messages to be routed to nodes.
                                  >  *
                                  >  * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
                                  >  * Copyright (C) 2013-2015 Sensnology AB
                                  >  * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
                                  >  *
                                  >  * Documentation: http://www.mysensors.org
                                  >  * Support Forum: http://forum.mysensors.org
                                  >  *
                                  >  * This program is free software; you can redistribute it and/or
                                  >  * modify it under the terms of the GNU General Public License
                                  >  * version 2 as published by the Free Software Foundation.
                                  >  *
                                  >  *******************************
                                  >  *
                                  >  * REVISION HISTORY
                                  >  * Version 1.0 - Henrik Ekblad
                                  >  * 
                                  >  * DESCRIPTION
                                  >  * Pressure sensor example using BMP085 module  
                                  >  * http://www.mysensors.org/build/pressure
                                  >  *
                                  >  */
                                  > 
                                  > // Enable debug prints to serial monitor
                                  > #define MY_DEBUG 
                                  > 
                                  > // Enable and select radio type attached
                                  > #define MY_RADIO_NRF24
                                  > //#define MY_RADIO_RFM69
                                  > 
                                  > #include <SPI.h>
                                  > #include <MySensors.h>  
                                  > #include <Wire.h>
                                  > 
                                  > // BME280 libraries and variables
                                  > // Bosch BME280 Embedded Adventures MOD-1022 weather multi-sensor Arduino code
                                  > // Written originally by Embedded Adventures
                                  > // https://github.com/embeddedadventures/BME280
                                  > #include <BME280_MOD-1022.h>
                                  > 
                                  > #define BARO_CHILD 0
                                  > #define TEMP_CHILD 1
                                  > #define HUM_CHILD 2
                                  > 
                                  > const float ALTITUDE = 184; // <-- adapt this value to your location's altitude (in m). Use your smartphone GPS to get an accurate value!
                                  > 
                                  > // Sleep time between reads (in ms). Do not change this value as the forecast algorithm needs a sample every minute.
                                  > const unsigned long SLEEP_TIME = 60000; 
                                  > 
                                  > 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)
                                  > };
                                  > 
                                  > float lastPressure = -1;
                                  > float lastTemp = -1;
                                  > float lastHum = -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 the forecast algorithm
                                  > // get kPa/h by 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;
                                  > boolean metric;
                                  > MyMessage tempMsg(TEMP_CHILD, V_TEMP);
                                  > MyMessage humMsg(HUM_CHILD, V_HUM);
                                  > MyMessage pressureMsg(BARO_CHILD, V_PRESSURE);
                                  > MyMessage forecastMsg(BARO_CHILD, V_FORECAST);
                                  > 
                                  > 
                                  > 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;
                                  > }
                                  > 
                                  > 
                                  > void setup() {
                                  >   metric = getControllerConfig().isMetric;  // was getConfig().isMetric; before MySensors v2.1.1
                                  >   Wire.begin(); // Wire.begin(sda, scl)
                                  > }
                                  > 
                                  > void presentation()  {
                                  >   // Send the sketch version information to the gateway and Controller
                                  >   sendSketchInfo("BME280 Sensor", "1.6");
                                  > 
                                  >   // Register sensors to gw (they will be created as child devices)
                                  >   present(BARO_CHILD, S_BARO);
                                  >   present(TEMP_CHILD, S_TEMP);
                                  >   present(HUM_CHILD, S_HUM);
                                  > }
                                  > 
                                  > // Loop
                                  > void loop() {
                                  >   
                                  >   // need to read the NVM compensation parameters
                                  >   BME280.readCompensationParams();
                                  > 
                                  >   /* After taking the measurement the chip goes back to sleep, use when battery powered.
                                  >   // Oversampling settings (os1x, os2x, os4x, os8x or os16x).
                                  >   BME280.writeFilterCoefficient(fc_16);       // IIR Filter coefficient, higher numbers avoid sudden changes to be accounted for (such as slamming a door)
                                  >   BME280.writeOversamplingPressure(os16x);    // pressure x16
                                  >   BME280.writeOversamplingTemperature(os8x);  // temperature x8
                                  >   BME280.writeOversamplingHumidity(os8x);     // humidity x8
                                  > 
                                  >   BME280.writeMode(smForced);                 // Forced sample.  After taking the measurement the chip goes back to sleep
                                  >   */
                                  > 
                                  >   // Normal mode for regular automatic samples
                                  >   BME280.writeStandbyTime(tsb_0p5ms);         // tsb = 0.5ms
                                  >   BME280.writeFilterCoefficient(fc_16);       // IIR Filter coefficient 16
                                  >   BME280.writeOversamplingPressure(os16x);    // pressure x16
                                  >   BME280.writeOversamplingTemperature(os8x);  // temperature x8
                                  >   BME280.writeOversamplingHumidity(os8x);     // humidity x8
                                  >   
                                  >   BME280.writeMode(smNormal);
                                  >   
                                  >   while (1) {
                                  >     // Just to be sure, wait until sensor is done mesuring  
                                  >     while (BME280.isMeasuring()) {
                                  >   }
                                  >   
                                  >   // Read out the data - must do this before calling the getxxxxx routines
                                  >   BME280.readMeasurements();
                                  > 
                                  >   float temperature = BME280.getTemperatureMostAccurate();                    // must get temp first
                                  >   float humidity = BME280.getHumidityMostAccurate();
                                  >   float pressure_local = BME280.getPressureMostAccurate();                    // Get pressure at current location
                                  >   float pressure = pressure_local/pow((1.0 - ( ALTITUDE / 44330.0 )), 5.255); // Adjust to sea level pressure using user altitude
                                  >   int forecast = sample(pressure);
                                  >   
                                  >   if (!metric) 
                                  >   {
                                  >     // Convert to fahrenheit
                                  >     temperature = temperature * 9.0 / 5.0 + 32.0;
                                  >   }
                                  > 
                                  >   Serial.println();
                                  >   Serial.print("Temperature = ");
                                  >   Serial.print(temperature);
                                  >   Serial.println(metric ? " °C" : " °F");
                                  >   Serial.print("Humidity = ");
                                  >   Serial.print(humidity);
                                  >   Serial.println(" %");
                                  >   Serial.print("Pressure = ");
                                  >   Serial.print(pressure);
                                  >   Serial.println(" hPa");
                                  >   Serial.print("Forecast = ");
                                  >   Serial.println(weather[forecast]);
                                  >   Serial.println();
                                  > 
                                  > 
                                  >   if (temperature != lastTemp) 
                                  >   {
                                  >     send(tempMsg.set(temperature, 1));
                                  >     lastTemp = temperature;
                                  >   }
                                  > 
                                  > 
                                  >   if (humidity != lastHum) 
                                  >   {
                                  >     send(humMsg.set(humidity, 1));
                                  >     lastHum = humidity;
                                  >   }
                                  > 
                                  >   if (pressure != lastPressure) 
                                  >   {
                                  >     send(pressureMsg.set(pressure, 2));
                                  >     lastPressure = pressure;
                                  >   }
                                  > 
                                  >   if (forecast != lastForecast)
                                  >   {
                                  >     send(forecastMsg.set(weather[forecast]));
                                  >     lastForecast = forecast;
                                  >   }
                                  >   
                                  >   sleep(SLEEP_TIME);
                                  >   
                                  > }
                                  > }
                                  

                                  Added to sketch @yoshida battery state send, but its not sending it, please chek it:

                                  /**
                                   * The MySensors Arduino library handles the wireless radio link and protocol
                                   * between your home built sensors/actuators and HA controller of choice.
                                   * The sensors forms a self healing radio network with optional repeaters. Each
                                   * repeater and gateway builds a routing tables in EEPROM which keeps track of the
                                   * network topology allowing messages to be routed to nodes.
                                   *
                                   * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
                                   * Copyright (C) 2013-2015 Sensnology AB
                                   * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
                                   *
                                   * Documentation: http://www.mysensors.org
                                   * Support Forum: http://forum.mysensors.org
                                   *
                                   * This program is free software; you can redistribute it and/or
                                   * modify it under the terms of the GNU General Public License
                                   * version 2 as published by the Free Software Foundation.
                                   *
                                   *******************************
                                   *
                                   * REVISION HISTORY
                                   * Version 1.0 - Henrik Ekblad
                                   * 
                                   * DESCRIPTION
                                   * Pressure sensor example using BMP085 module  
                                   * http://www.mysensors.org/build/pressure
                                   *
                                   */
                                  
                                  // Enable debug prints to serial monitor
                                  #define MY_DEBUG 
                                  
                                  // Enable and select radio type attached
                                  #define MY_RADIO_NRF24
                                  //#define MY_RADIO_RFM69
                                  
                                  #include <SPI.h>
                                  #include <MySensors.h>  
                                  #include <Wire.h>
                                  
                                  // BME280 libraries and variables
                                  // Bosch BME280 Embedded Adventures MOD-1022 weather multi-sensor Arduino code
                                  // Written originally by Embedded Adventures
                                  // https://github.com/embeddedadventures/BME280
                                  #include <BME280_MOD-1022.h>
                                  
                                  #define BARO_CHILD 0
                                  #define TEMP_CHILD 1
                                  #define HUM_CHILD 2
                                  
                                  int BATTERY_SENSE_PIN = A0; // select the input pin for the battery sense point
                                  int oldBatteryPcnt = 0;
                                  
                                  const float ALTITUDE = 450; // <-- adapt this value to your location's altitude (in m). Use your smartphone GPS to get an accurate value!
                                  
                                  // Sleep time between reads (in ms). Do not change this value as the forecast algorithm needs a sample every minute.
                                  const unsigned long SLEEP_TIME = 300000; 
                                  
                                  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)
                                  };
                                  
                                  float lastPressure = -1;
                                  float lastTemp = -1;
                                  float lastHum = -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 the forecast algorithm
                                  // get kPa/h by 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;
                                  boolean metric;
                                  MyMessage tempMsg(TEMP_CHILD, V_TEMP);
                                  MyMessage humMsg(HUM_CHILD, V_HUM);
                                  MyMessage pressureMsg(BARO_CHILD, V_PRESSURE);
                                  MyMessage forecastMsg(BARO_CHILD, V_FORECAST);
                                  
                                  
                                  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;
                                  }
                                  
                                  
                                  void setup() {
                                    metric = getControllerConfig().isMetric;  // was getConfig().isMetric; before MySensors v2.1.1
                                    Wire.begin(); // Wire.begin(sda, scl)
                                    // use the 1.1 V internal reference
                                    #if defined(__AVR_ATmega2560__)
                                    analogReference(INTERNAL1V1);
                                    #else
                                    analogReference(INTERNAL);
                                    #endif
                                  }
                                  
                                  void presentation()  {
                                    // Send the sketch version information to the gateway and Controller
                                    sendSketchInfo("BME280 Sensor", "1.6");
                                  
                                    // Register sensors to gw (they will be created as child devices)
                                    present(BARO_CHILD, S_BARO);
                                    present(TEMP_CHILD, S_TEMP);
                                    present(HUM_CHILD, S_HUM);
                                  }
                                  
                                  // Loop
                                  void loop() {
                                  
                                    
                                    
                                    // need to read the NVM compensation parameters
                                    BME280.readCompensationParams();
                                  
                                    /* After taking the measurement the chip goes back to sleep, use when battery powered.
                                    // Oversampling settings (os1x, os2x, os4x, os8x or os16x).
                                    BME280.writeFilterCoefficient(fc_16);       // IIR Filter coefficient, higher numbers avoid sudden changes to be accounted for (such as slamming a door)
                                    BME280.writeOversamplingPressure(os16x);    // pressure x16
                                    BME280.writeOversamplingTemperature(os8x);  // temperature x8
                                    BME280.writeOversamplingHumidity(os8x);     // humidity x8
                                  
                                    BME280.writeMode(smForced);                 // Forced sample.  After taking the measurement the chip goes back to sleep
                                    */
                                  
                                    // Normal mode for regular automatic samples
                                    BME280.writeStandbyTime(tsb_0p5ms);         // tsb = 0.5ms
                                    BME280.writeFilterCoefficient(fc_16);       // IIR Filter coefficient 16
                                    BME280.writeOversamplingPressure(os16x);    // pressure x16
                                    BME280.writeOversamplingTemperature(os8x);  // temperature x8
                                    BME280.writeOversamplingHumidity(os8x);     // humidity x8
                                    
                                    BME280.writeMode(smNormal);
                                    
                                    while (1) {
                                      // Just to be sure, wait until sensor is done mesuring  
                                      while (BME280.isMeasuring()) {
                                    }
                                    
                                    // Read out the data - must do this before calling the getxxxxx routines
                                    BME280.readMeasurements();
                                  
                                    float temperature = BME280.getTemperatureMostAccurate();                    // must get temp first
                                    float humidity = BME280.getHumidityMostAccurate();
                                    float pressure_local = BME280.getPressureMostAccurate();                    // Get pressure at current location
                                    float pressure = pressure_local/pow((1.0 - ( ALTITUDE / 44330.0 )), 5.255); // Adjust to sea level pressure using user altitude
                                    int forecast = sample(pressure);
                                    
                                    if (!metric) 
                                    {
                                      // Convert to fahrenheit
                                      temperature = temperature * 9.0 / 5.0 + 32.0;
                                    }
                                  
                                    Serial.println();
                                    Serial.print("Temperature = ");
                                    Serial.print(temperature);
                                    Serial.println(metric ? " °C" : " °F");
                                    Serial.print("Humidity = ");
                                    Serial.print(humidity);
                                    Serial.println(" %");
                                    Serial.print("Pressure = ");
                                    Serial.print(pressure);
                                    Serial.println(" hPa");
                                    Serial.print("Forecast = ");
                                    Serial.println(weather[forecast]);
                                    Serial.println();
                                  
                                  
                                    if (temperature != lastTemp) 
                                    {
                                      send(tempMsg.set(temperature, 1));
                                      lastTemp = temperature;
                                    }
                                  
                                  
                                    if (humidity != lastHum) 
                                    {
                                      send(humMsg.set(humidity, 1));
                                      lastHum = humidity;
                                    }
                                  
                                    if (pressure != lastPressure) 
                                    {
                                      send(pressureMsg.set(pressure, 2));
                                      lastPressure = pressure;
                                    }
                                  
                                    if (forecast != lastForecast)
                                    {
                                      send(forecastMsg.set(weather[forecast]));
                                      lastForecast = forecast;
                                    }
                                  
                                      int sensorValue = analogRead(BATTERY_SENSE_PIN);
                                      int batteryPcnt = sensorValue / 10;
                                      if (oldBatteryPcnt != batteryPcnt) {
                                      // Power up radio after sleep
                                      sendBatteryLevel(batteryPcnt);
                                      oldBatteryPcnt = batteryPcnt;
                                      }
                                      
                                    sleep(SLEEP_TIME);
                                    
                                  }
                                  }
                                  
                                  sundberg84S 1 Reply Last reply
                                  0
                                  • S scalpel

                                    @yoshida said in BME280 temp/humidity/pressure sensor:

                                    > /**
                                    >  * The MySensors Arduino library handles the wireless radio link and protocol
                                    >  * between your home built sensors/actuators and HA controller of choice.
                                    >  * The sensors forms a self healing radio network with optional repeaters. Each
                                    >  * repeater and gateway builds a routing tables in EEPROM which keeps track of the
                                    >  * network topology allowing messages to be routed to nodes.
                                    >  *
                                    >  * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
                                    >  * Copyright (C) 2013-2015 Sensnology AB
                                    >  * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
                                    >  *
                                    >  * Documentation: http://www.mysensors.org
                                    >  * Support Forum: http://forum.mysensors.org
                                    >  *
                                    >  * This program is free software; you can redistribute it and/or
                                    >  * modify it under the terms of the GNU General Public License
                                    >  * version 2 as published by the Free Software Foundation.
                                    >  *
                                    >  *******************************
                                    >  *
                                    >  * REVISION HISTORY
                                    >  * Version 1.0 - Henrik Ekblad
                                    >  * 
                                    >  * DESCRIPTION
                                    >  * Pressure sensor example using BMP085 module  
                                    >  * http://www.mysensors.org/build/pressure
                                    >  *
                                    >  */
                                    > 
                                    > // Enable debug prints to serial monitor
                                    > #define MY_DEBUG 
                                    > 
                                    > // Enable and select radio type attached
                                    > #define MY_RADIO_NRF24
                                    > //#define MY_RADIO_RFM69
                                    > 
                                    > #include <SPI.h>
                                    > #include <MySensors.h>  
                                    > #include <Wire.h>
                                    > 
                                    > // BME280 libraries and variables
                                    > // Bosch BME280 Embedded Adventures MOD-1022 weather multi-sensor Arduino code
                                    > // Written originally by Embedded Adventures
                                    > // https://github.com/embeddedadventures/BME280
                                    > #include <BME280_MOD-1022.h>
                                    > 
                                    > #define BARO_CHILD 0
                                    > #define TEMP_CHILD 1
                                    > #define HUM_CHILD 2
                                    > 
                                    > const float ALTITUDE = 184; // <-- adapt this value to your location's altitude (in m). Use your smartphone GPS to get an accurate value!
                                    > 
                                    > // Sleep time between reads (in ms). Do not change this value as the forecast algorithm needs a sample every minute.
                                    > const unsigned long SLEEP_TIME = 60000; 
                                    > 
                                    > 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)
                                    > };
                                    > 
                                    > float lastPressure = -1;
                                    > float lastTemp = -1;
                                    > float lastHum = -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 the forecast algorithm
                                    > // get kPa/h by 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;
                                    > boolean metric;
                                    > MyMessage tempMsg(TEMP_CHILD, V_TEMP);
                                    > MyMessage humMsg(HUM_CHILD, V_HUM);
                                    > MyMessage pressureMsg(BARO_CHILD, V_PRESSURE);
                                    > MyMessage forecastMsg(BARO_CHILD, V_FORECAST);
                                    > 
                                    > 
                                    > 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;
                                    > }
                                    > 
                                    > 
                                    > void setup() {
                                    >   metric = getControllerConfig().isMetric;  // was getConfig().isMetric; before MySensors v2.1.1
                                    >   Wire.begin(); // Wire.begin(sda, scl)
                                    > }
                                    > 
                                    > void presentation()  {
                                    >   // Send the sketch version information to the gateway and Controller
                                    >   sendSketchInfo("BME280 Sensor", "1.6");
                                    > 
                                    >   // Register sensors to gw (they will be created as child devices)
                                    >   present(BARO_CHILD, S_BARO);
                                    >   present(TEMP_CHILD, S_TEMP);
                                    >   present(HUM_CHILD, S_HUM);
                                    > }
                                    > 
                                    > // Loop
                                    > void loop() {
                                    >   
                                    >   // need to read the NVM compensation parameters
                                    >   BME280.readCompensationParams();
                                    > 
                                    >   /* After taking the measurement the chip goes back to sleep, use when battery powered.
                                    >   // Oversampling settings (os1x, os2x, os4x, os8x or os16x).
                                    >   BME280.writeFilterCoefficient(fc_16);       // IIR Filter coefficient, higher numbers avoid sudden changes to be accounted for (such as slamming a door)
                                    >   BME280.writeOversamplingPressure(os16x);    // pressure x16
                                    >   BME280.writeOversamplingTemperature(os8x);  // temperature x8
                                    >   BME280.writeOversamplingHumidity(os8x);     // humidity x8
                                    > 
                                    >   BME280.writeMode(smForced);                 // Forced sample.  After taking the measurement the chip goes back to sleep
                                    >   */
                                    > 
                                    >   // Normal mode for regular automatic samples
                                    >   BME280.writeStandbyTime(tsb_0p5ms);         // tsb = 0.5ms
                                    >   BME280.writeFilterCoefficient(fc_16);       // IIR Filter coefficient 16
                                    >   BME280.writeOversamplingPressure(os16x);    // pressure x16
                                    >   BME280.writeOversamplingTemperature(os8x);  // temperature x8
                                    >   BME280.writeOversamplingHumidity(os8x);     // humidity x8
                                    >   
                                    >   BME280.writeMode(smNormal);
                                    >   
                                    >   while (1) {
                                    >     // Just to be sure, wait until sensor is done mesuring  
                                    >     while (BME280.isMeasuring()) {
                                    >   }
                                    >   
                                    >   // Read out the data - must do this before calling the getxxxxx routines
                                    >   BME280.readMeasurements();
                                    > 
                                    >   float temperature = BME280.getTemperatureMostAccurate();                    // must get temp first
                                    >   float humidity = BME280.getHumidityMostAccurate();
                                    >   float pressure_local = BME280.getPressureMostAccurate();                    // Get pressure at current location
                                    >   float pressure = pressure_local/pow((1.0 - ( ALTITUDE / 44330.0 )), 5.255); // Adjust to sea level pressure using user altitude
                                    >   int forecast = sample(pressure);
                                    >   
                                    >   if (!metric) 
                                    >   {
                                    >     // Convert to fahrenheit
                                    >     temperature = temperature * 9.0 / 5.0 + 32.0;
                                    >   }
                                    > 
                                    >   Serial.println();
                                    >   Serial.print("Temperature = ");
                                    >   Serial.print(temperature);
                                    >   Serial.println(metric ? " °C" : " °F");
                                    >   Serial.print("Humidity = ");
                                    >   Serial.print(humidity);
                                    >   Serial.println(" %");
                                    >   Serial.print("Pressure = ");
                                    >   Serial.print(pressure);
                                    >   Serial.println(" hPa");
                                    >   Serial.print("Forecast = ");
                                    >   Serial.println(weather[forecast]);
                                    >   Serial.println();
                                    > 
                                    > 
                                    >   if (temperature != lastTemp) 
                                    >   {
                                    >     send(tempMsg.set(temperature, 1));
                                    >     lastTemp = temperature;
                                    >   }
                                    > 
                                    > 
                                    >   if (humidity != lastHum) 
                                    >   {
                                    >     send(humMsg.set(humidity, 1));
                                    >     lastHum = humidity;
                                    >   }
                                    > 
                                    >   if (pressure != lastPressure) 
                                    >   {
                                    >     send(pressureMsg.set(pressure, 2));
                                    >     lastPressure = pressure;
                                    >   }
                                    > 
                                    >   if (forecast != lastForecast)
                                    >   {
                                    >     send(forecastMsg.set(weather[forecast]));
                                    >     lastForecast = forecast;
                                    >   }
                                    >   
                                    >   sleep(SLEEP_TIME);
                                    >   
                                    > }
                                    > }
                                    

                                    Added to sketch @yoshida battery state send, but its not sending it, please chek it:

                                    /**
                                     * The MySensors Arduino library handles the wireless radio link and protocol
                                     * between your home built sensors/actuators and HA controller of choice.
                                     * The sensors forms a self healing radio network with optional repeaters. Each
                                     * repeater and gateway builds a routing tables in EEPROM which keeps track of the
                                     * network topology allowing messages to be routed to nodes.
                                     *
                                     * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
                                     * Copyright (C) 2013-2015 Sensnology AB
                                     * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
                                     *
                                     * Documentation: http://www.mysensors.org
                                     * Support Forum: http://forum.mysensors.org
                                     *
                                     * This program is free software; you can redistribute it and/or
                                     * modify it under the terms of the GNU General Public License
                                     * version 2 as published by the Free Software Foundation.
                                     *
                                     *******************************
                                     *
                                     * REVISION HISTORY
                                     * Version 1.0 - Henrik Ekblad
                                     * 
                                     * DESCRIPTION
                                     * Pressure sensor example using BMP085 module  
                                     * http://www.mysensors.org/build/pressure
                                     *
                                     */
                                    
                                    // Enable debug prints to serial monitor
                                    #define MY_DEBUG 
                                    
                                    // Enable and select radio type attached
                                    #define MY_RADIO_NRF24
                                    //#define MY_RADIO_RFM69
                                    
                                    #include <SPI.h>
                                    #include <MySensors.h>  
                                    #include <Wire.h>
                                    
                                    // BME280 libraries and variables
                                    // Bosch BME280 Embedded Adventures MOD-1022 weather multi-sensor Arduino code
                                    // Written originally by Embedded Adventures
                                    // https://github.com/embeddedadventures/BME280
                                    #include <BME280_MOD-1022.h>
                                    
                                    #define BARO_CHILD 0
                                    #define TEMP_CHILD 1
                                    #define HUM_CHILD 2
                                    
                                    int BATTERY_SENSE_PIN = A0; // select the input pin for the battery sense point
                                    int oldBatteryPcnt = 0;
                                    
                                    const float ALTITUDE = 450; // <-- adapt this value to your location's altitude (in m). Use your smartphone GPS to get an accurate value!
                                    
                                    // Sleep time between reads (in ms). Do not change this value as the forecast algorithm needs a sample every minute.
                                    const unsigned long SLEEP_TIME = 300000; 
                                    
                                    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)
                                    };
                                    
                                    float lastPressure = -1;
                                    float lastTemp = -1;
                                    float lastHum = -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 the forecast algorithm
                                    // get kPa/h by 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;
                                    boolean metric;
                                    MyMessage tempMsg(TEMP_CHILD, V_TEMP);
                                    MyMessage humMsg(HUM_CHILD, V_HUM);
                                    MyMessage pressureMsg(BARO_CHILD, V_PRESSURE);
                                    MyMessage forecastMsg(BARO_CHILD, V_FORECAST);
                                    
                                    
                                    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;
                                    }
                                    
                                    
                                    void setup() {
                                      metric = getControllerConfig().isMetric;  // was getConfig().isMetric; before MySensors v2.1.1
                                      Wire.begin(); // Wire.begin(sda, scl)
                                      // use the 1.1 V internal reference
                                      #if defined(__AVR_ATmega2560__)
                                      analogReference(INTERNAL1V1);
                                      #else
                                      analogReference(INTERNAL);
                                      #endif
                                    }
                                    
                                    void presentation()  {
                                      // Send the sketch version information to the gateway and Controller
                                      sendSketchInfo("BME280 Sensor", "1.6");
                                    
                                      // Register sensors to gw (they will be created as child devices)
                                      present(BARO_CHILD, S_BARO);
                                      present(TEMP_CHILD, S_TEMP);
                                      present(HUM_CHILD, S_HUM);
                                    }
                                    
                                    // Loop
                                    void loop() {
                                    
                                      
                                      
                                      // need to read the NVM compensation parameters
                                      BME280.readCompensationParams();
                                    
                                      /* After taking the measurement the chip goes back to sleep, use when battery powered.
                                      // Oversampling settings (os1x, os2x, os4x, os8x or os16x).
                                      BME280.writeFilterCoefficient(fc_16);       // IIR Filter coefficient, higher numbers avoid sudden changes to be accounted for (such as slamming a door)
                                      BME280.writeOversamplingPressure(os16x);    // pressure x16
                                      BME280.writeOversamplingTemperature(os8x);  // temperature x8
                                      BME280.writeOversamplingHumidity(os8x);     // humidity x8
                                    
                                      BME280.writeMode(smForced);                 // Forced sample.  After taking the measurement the chip goes back to sleep
                                      */
                                    
                                      // Normal mode for regular automatic samples
                                      BME280.writeStandbyTime(tsb_0p5ms);         // tsb = 0.5ms
                                      BME280.writeFilterCoefficient(fc_16);       // IIR Filter coefficient 16
                                      BME280.writeOversamplingPressure(os16x);    // pressure x16
                                      BME280.writeOversamplingTemperature(os8x);  // temperature x8
                                      BME280.writeOversamplingHumidity(os8x);     // humidity x8
                                      
                                      BME280.writeMode(smNormal);
                                      
                                      while (1) {
                                        // Just to be sure, wait until sensor is done mesuring  
                                        while (BME280.isMeasuring()) {
                                      }
                                      
                                      // Read out the data - must do this before calling the getxxxxx routines
                                      BME280.readMeasurements();
                                    
                                      float temperature = BME280.getTemperatureMostAccurate();                    // must get temp first
                                      float humidity = BME280.getHumidityMostAccurate();
                                      float pressure_local = BME280.getPressureMostAccurate();                    // Get pressure at current location
                                      float pressure = pressure_local/pow((1.0 - ( ALTITUDE / 44330.0 )), 5.255); // Adjust to sea level pressure using user altitude
                                      int forecast = sample(pressure);
                                      
                                      if (!metric) 
                                      {
                                        // Convert to fahrenheit
                                        temperature = temperature * 9.0 / 5.0 + 32.0;
                                      }
                                    
                                      Serial.println();
                                      Serial.print("Temperature = ");
                                      Serial.print(temperature);
                                      Serial.println(metric ? " °C" : " °F");
                                      Serial.print("Humidity = ");
                                      Serial.print(humidity);
                                      Serial.println(" %");
                                      Serial.print("Pressure = ");
                                      Serial.print(pressure);
                                      Serial.println(" hPa");
                                      Serial.print("Forecast = ");
                                      Serial.println(weather[forecast]);
                                      Serial.println();
                                    
                                    
                                      if (temperature != lastTemp) 
                                      {
                                        send(tempMsg.set(temperature, 1));
                                        lastTemp = temperature;
                                      }
                                    
                                    
                                      if (humidity != lastHum) 
                                      {
                                        send(humMsg.set(humidity, 1));
                                        lastHum = humidity;
                                      }
                                    
                                      if (pressure != lastPressure) 
                                      {
                                        send(pressureMsg.set(pressure, 2));
                                        lastPressure = pressure;
                                      }
                                    
                                      if (forecast != lastForecast)
                                      {
                                        send(forecastMsg.set(weather[forecast]));
                                        lastForecast = forecast;
                                      }
                                    
                                        int sensorValue = analogRead(BATTERY_SENSE_PIN);
                                        int batteryPcnt = sensorValue / 10;
                                        if (oldBatteryPcnt != batteryPcnt) {
                                        // Power up radio after sleep
                                        sendBatteryLevel(batteryPcnt);
                                        oldBatteryPcnt = batteryPcnt;
                                        }
                                        
                                      sleep(SLEEP_TIME);
                                      
                                    }
                                    }
                                    
                                    sundberg84S Offline
                                    sundberg84S Offline
                                    sundberg84
                                    Hardware Contributor
                                    wrote on last edited by
                                    #30

                                    @scalpel - works great! Thank you!!
                                    Downloaded the library from the link in your sketch and up and running i no time.
                                    Here is my sketch, with some modifications:

                                    • Lightsensor A0
                                    • No sleep (might want to enable repeater function later)
                                    • Sends every 5 minute regardless of prevoius value (I use Domoticz and want to avoid red nodes and combined nodes).
                                    • Fixed node it
                                    // Enable debug prints to serial monitor
                                    //#define MY_DEBUG 
                                    
                                    // Enable and select radio type attached
                                    #define MY_RADIO_NRF24
                                    //#define MY_RADIO_RFM69
                                    
                                    //Fixed ID/Parent?
                                    #define MY_NODE_ID 20                     //To set a fixed ID for your node
                                    //#define MY_PARENT_NODE_ID 100             //To set a fixed parent for this node
                                    
                                    #include <SPI.h>
                                    #include <MySensors.h>  
                                    #include <Wire.h>
                                    
                                    // BME280 libraries and variables
                                    // Bosch BME280 Embedded Adventures MOD-1022 weather multi-sensor Arduino code
                                    // Written originally by Embedded Adventures
                                    // https://github.com/embeddedadventures/BME280
                                    #include <BME280_MOD-1022.h>
                                    
                                    #define BARO_CHILD 0
                                    #define TEMP_CHILD 1
                                    #define HUM_CHILD 2
                                    
                                    long interval = 300000;           // interval at which to send (milliseconds)
                                    long previousMillis = interval;        // will store last time data was sent
                                    
                                    const float ALTITUDE = 135; // <-- adapt this value to your location's altitude (in m). Use your smartphone GPS to get an accurate value!
                                    
                                    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)
                                    };
                                    
                                    
                                    const int LAST_SAMPLES_COUNT = 5;
                                    float lastPressureSamples[LAST_SAMPLES_COUNT];
                                    
                                    
                                    // this CONVERSION_FACTOR is used to convert from Pa to kPa in the forecast algorithm
                                    // get kPa/h by 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;
                                    boolean metric;
                                    MyMessage tempMsg(TEMP_CHILD, V_TEMP);
                                    MyMessage humMsg(HUM_CHILD, V_HUM);
                                    MyMessage pressureMsg(BARO_CHILD, V_PRESSURE);
                                    MyMessage forecastMsg(BARO_CHILD, V_FORECAST);
                                    
                                    //Light
                                    #define CHILD_ID_LIGHT 3
                                    #define LIGHT_SENSOR_ANALOG_PIN A0
                                    MyMessage light_Msg(CHILD_ID_LIGHT, V_LIGHT_LEVEL);
                                    
                                    
                                    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;
                                    }
                                    
                                    
                                    void setup() {
                                      metric = getControllerConfig().isMetric;  // was getConfig().isMetric; before MySensors v2.1.1
                                      Wire.begin(); // Wire.begin(sda, scl)
                                      // use the 1.1 V internal reference
                                      #if defined(__AVR_ATmega2560__)
                                      analogReference(INTERNAL1V1);
                                      #else
                                      analogReference(INTERNAL);
                                      #endif
                                    }
                                    
                                    void presentation()  {
                                      // Send the sketch version information to the gateway and Controller
                                      sendSketchInfo("WeatherStation #20", "1.0");
                                    
                                      // Register sensors to gw (they will be created as child devices)
                                      present(BARO_CHILD, S_BARO);
                                      present(TEMP_CHILD, S_TEMP);
                                      present(HUM_CHILD, S_HUM);
                                      present(CHILD_ID_LIGHT, S_LIGHT_LEVEL);
                                    }
                                    
                                    // Loop
                                    void loop() {
                                    
                                    unsigned long currentMillis = millis();  
                                    
                                    if(currentMillis - previousMillis > interval) {
                                        // save the last time sent the data
                                        previousMillis = currentMillis;
                                    
                                    
                                      analogReference(DEFAULT);
                                      wait(500);
                                       readLightLevel();   //Read Light
                                    
                                      analogReference(INTERNAL);
                                      wait(500);
                                      
                                      // need to read the NVM compensation parameters
                                      BME280.readCompensationParams();
                                    
                                      // Normal mode for regular automatic samples
                                      BME280.writeStandbyTime(tsb_0p5ms);         // tsb = 0.5ms
                                      BME280.writeFilterCoefficient(fc_16);       // IIR Filter coefficient 16
                                      BME280.writeOversamplingPressure(os16x);    // pressure x16
                                      BME280.writeOversamplingTemperature(os8x);  // temperature x8
                                      BME280.writeOversamplingHumidity(os8x);     // humidity x8
                                      
                                      BME280.writeMode(smNormal);
                                    
                                        // Just to be sure, wait until sensor is done mesuring  
                                        while (BME280.isMeasuring()) {
                                      }
                                    
                                      // Read out the data - must do this before calling the getxxxxx routines
                                      BME280.readMeasurements();
                                    
                                      float temperature = BME280.getTemperatureMostAccurate();                    // must get temp first
                                      float humidity = BME280.getHumidityMostAccurate();
                                      float pressure_local = BME280.getPressureMostAccurate();                    // Get pressure at current location
                                      float pressure = pressure_local/pow((1.0 - ( ALTITUDE / 44330.0 )), 5.255); // Adjust to sea level pressure using user altitude
                                      int forecast = sample(pressure);
                                    
                                      if (!metric) 
                                      {
                                        // Convert to fahrenheit
                                        temperature = temperature * 9.0 / 5.0 + 32.0;
                                      }
                                    
                                      Serial.println();
                                      Serial.print("Temperature = ");
                                      Serial.print(temperature);
                                      Serial.println(metric ? " °C" : " °F");
                                      Serial.print("Humidity = ");
                                      Serial.print(humidity);
                                      Serial.println(" %");
                                      Serial.print("Pressure = ");
                                      Serial.print(pressure);
                                      Serial.println(" hPa");
                                      Serial.print("Forecast = ");
                                      Serial.println(weather[forecast]);
                                      Serial.println();
                                    
                                    
                                        send(tempMsg.set(temperature, 1));
                                    wait(50);
                                        send(humMsg.set(humidity, 1));
                                    wait(50);
                                        send(pressureMsg.set(pressure, 2));
                                    wait(50);
                                        send(forecastMsg.set(weather[forecast]));
                                    wait(50);
                                    
                                    }
                                    }
                                    
                                    void readLightLevel()      {
                                      Serial.println(analogRead(A0));  
                                      int lightLevel = (1023 - analogRead(LIGHT_SENSOR_ANALOG_PIN)) / 10.23; //To get a value ranging from 0 (dark) to 100 (bright).
                                    
                                    #ifdef MY_DEBUG
                                      Serial.print("Light: "); Serial.println(lightLevel);
                                    #endif
                                      send(light_Msg.set(lightLevel));
                                    
                                    }
                                    

                                    0_1506074720708_170922-IMG_20170922_103752.jpg

                                    Controller: Proxmox VM - Home Assistant
                                    MySensors GW: Arduino Uno - W5100 Ethernet, Gw Shield Nrf24l01+ 2,4Ghz
                                    MySensors GW: Arduino Uno - Gw Shield RFM69, 433mhz
                                    RFLink GW - Arduino Mega + RFLink Shield, 433mhz

                                    1 Reply Last reply
                                    0
                                    • R Offline
                                      R Offline
                                      RickyTerzis
                                      wrote on last edited by RickyTerzis
                                      #31

                                      Hi...i am a new user here. I built a RFM69 gateway and a node.I decided to place the RFM69 node in a basement storage room. The room has been flooded a few times historically, so being able to monitor humidity in the room seems like a good idea.The room has thick brick walls, which the RFM69-433MHz radio is much more capable to handle than the nrf24. Still, I wanted to keep an eye on the signal strength. Because of this, I added code to the gateway to report RSSI from the node.

                                      circuit card assembly

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


                                      20

                                      Online

                                      11.7k

                                      Users

                                      11.2k

                                      Topics

                                      113.0k

                                      Posts


                                      Copyright 2019 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