BME280 node connecting but not showing data



  • So i'm using the PressureSensor.ino sketch. With BME280 and a featherM0 rfm69. The node connects and shows up on domoticz but the childs are not showing data. Any ideas?

    I'm using the #include <BME280_MOD-1022.h> library

    
    2018-10-08 02:22:55.923 (ESP8266 LAN GW) Temp + Humidity (TempHum)
    2018-10-08 02:23:00.920 Status: MySensors: Node: 2, Sketch Name: BME280 Sensor
    2018-10-08 02:23:00.921 Status: MySensors: Node: 2, Sketch Version: 1.1
    2018-10-08 02:23:02.928 (ESP8266 LAN GW) Temp + Humidity (TempHum)
    2018-10-08 02:23:07.985 Status: Incoming connection from: 192.168.1.1```

  • Mod

    @andrew-maynard what do the debug logs from the gateway and the node say?



  • @mfalkvidd
    This is the log from the node

    6967 TSF:MSG:SEND,11-11-0-0,s=255,c=3,t=11,pt=0,l=13,sg=0,ft=0,st=OK:BME280 Sensor
    7199 TSF:MSG:SEND,11-11-0-0,s=255,c=3,t=12,pt=0,l=3,sg=0,ft=0,st=OK:1.1
    7599 TSF:MSG:SEND,11-11-0-0,s=2,c=0,t=8,pt=0,l=0,sg=0,ft=0,st=OK:
    7870 TSF:MSG:SEND,11-11-0-0,s=0,c=0,t=6,pt=0,l=0,sg=0,ft=0,st=OK:
    8006 TSF:MSG:SEND,11-11-0-0,s=1,c=0,t=7,pt=0,l=0,sg=0,ft=0,st=OK:
    21:27:27.336 -> 8016 MCO:REG:REQ
    8467 TSF:MSG:SEND,11-11-0-0,s=255,c=3,t=26,pt=1,l=1,sg=0,ft=0,st=OK:2
    8706 TSF:MSG:READ,0-0-11,s=255,c=3,t=27,pt=1,l=1,sg=0:1
    21:27:28.047 -> 8716 MCO:PIM:NODE REG=1
    21:27:28.047 -> 8726 MCO:BGN:STP
    21:27:28.047 -> Hello world, I am a sensor node.
    8736 MCO:BGN:INIT OK,TSP=1
    

    and this is the gateway log

    21:41:32.284 -> 398709 TSF:MSG:BC
    21:41:32.317 -> 398727 TSF:MSG:FPAR REQ,ID=11
    21:41:32.317 -> 398759 TSF:PNG:SEND,TO=0
    21:41:32.351 -> 398785 TSF:CKU:OK
    21:41:32.386 -> 398804 TSF:MSG:GWL OK
    399978 TSF:MSG:SEND,0-0-11-11,s=255,c=3,t=8,pt=1,l=1,sg=0,ft=0,st=OK:0
    402053 TSF:MSG:READ,11-11-0,s=255,c=3,t=24,pt=1,l=1,sg=0:1
    21:41:35.701 -> 402114 TSF:MSG:PINGED,ID=11,HP=1
    403464 !TSF:MSG:SEND,0-0-11-11,s=255,c=3,t=25,pt=1,l=1,sg=0,ft=0,st=NACK:1
    405699 TSF:MSG:READ,11-11-0,s=255,c=3,t=24,pt=1,l=1,sg=0:1
    21:41:39.338 -> 405761 TSF:MSG:PINGED,ID=11,HP=1
    405830 TSF:MSG:SEND,0-0-11-11,s=255,c=3,t=25,pt=1,l=1,sg=0,ft=0,st=OK:1
    405990 GWT:RFC:C=0,MSG=0;0;3;0;18;PING
    406152 TSF:MSG:READ,11-11-0,s=255,c=3,t=15,pt=6,l=2,sg=0:0100
    406435 TSF:MSG:SEND,0-0-11-11,s=255,c=3,t=15,pt=6,l=2,sg=0,ft=0,st=OK:0100
    406693 TSF:MSG:READ,11-11-0,s=255,c=0,t=17,pt=0,l=5,sg=0:2.3.0
    406998 TSF:MSG:READ,11-11-0,s=255,c=3,t=6,pt=1,l=1,sg=0:0
    407996 GWT:RFC:C=0,MSG=11;255;3;0;6;M
    21:41:41.612 -> 408053 TSF:MSG:SEND,0-0-11-11,s=255,c=3,t=6,pt=0,l=1,sg=0,ft=0,st=OK:M
    408346 TSF:MSG:READ,11-11-0,s=255,c=3,t=11,pt=0,l=13,sg=0:BME280 Sensor
    408612 TSF:MSG:READ,11-11-0,s=255,c=3,t=12,pt=0,l=3,sg=0:1.1
    408932 TSF:MSG:READ,11-11-0,s=2,c=0,t=8,pt=0,l=0,sg=0:
    409188 TSF:MSG:READ,11-11-0,s=0,c=0,t=6,pt=0,l=0,sg=0:
    409418 TSF:MSG:READ,11-11-0,s=1,c=0,t=7,pt=0,l=0,sg=0:
    409728 TSF:MSG:READ,11-11-0,s=255,c=3,t=26,pt=1,l=1,sg=0:2
    409817 TSF:MSG:SEND,0-0-11-11,s=255,c=3,t=27,pt=1,l=1,sg=0,ft=0,st=OK:1
    415992 GWT:RFC:C=0,MSG=0;0;3;0;18;PING
    425993 GWT:RFC:C=0,MSG=0;0;3;0;18;PING
    

    no changes are needed for the code right? besides the obvious radio configuration


  • Mod

    @andrew-maynard interesting. presentation() and setup() works fine but it seems like the node never enters loop(). Could you add a serial debug print on the first line in loop() to check?

    Could you post your entire sketch so we can check there is nothing strange with any of the defines?



  • @mfalkvidd of course! just add Serial.begin(115200);?

    // Enable debug prints to serial monitor
    #define MY_SERIALDEVICE Serial  // this will override Serial port define in MyHwSAMD.h file
    #define MY_DEBUG // used by MySensor (Print debug messages via serial)
    
    //#define MY_RFM69_NEW_DRIVER
    #define MY_RFM69_CSMA_LIMIT_DBM             (-95)      
    #define MY_RADIO_RFM69                            // Select Radio-Module RFM69
    #define MY_RFM69_FREQUENCY   (RFM69_433MHZ)
    #define MY_IS_RFM69HW                             // Module is high power (HW/HCW)
    //#define MY_RFM69_NETWORKID 100                 // leave out for gateway selection
    #define MY_NODE_ID 11                          // Node ID
    
    #define MY_RF69_SPI_CS 8                          // SPI CS PIN
    #define MY_RFM69_CS_PIN  8                            // SPI CS PIN
    #define MY_RF69_IRQ_PIN 3                         // IRQ PIN
    #define MY_RF69_IRQ_NUM 3                         // IRQ PIN NUM (for M0 it is the same as IRQ PIN. Will be obsolete in upcoming MySensors.h)
    #define MY_RFM69_RST_PIN 4 
    #define MY_DEFAULT_TX_LED_PIN 13                  // LED Pin for "Blink while sending"
    
    // Do you want this sensor to also be a repeater?
    // #define MY_REPEATER_FEATURE                    // Just remove the two slashes at the beginning of this line to also enable this sensor to act as a repeater for other sensors. If this node is on battery power, you probably shouldn't enable this.
    
    // Are you using this sensor on battery power?
    // #define BATTERY_POWERED                        // Just remove the two slashes at the beginning of this line if your node is battery powered. It will then go into deep sleep as much as possible. While it's sleeping it can't work as a repeater!
    
    // Would you like the sensor to generate a weather forecast based on the barometric pressure? 
    //#define GENERATE_FORECAST              // Just remove the two slashes at the beginning of this line to enable this feature.
    
    
    // LIBRARIES
    #include <SPI.h>                                  // A communication backbone, the Serial Peripheral Interface.
    #include <MySensors.h>                            // The MySensors library. Hurray!
    #include <Wire.h>                                 // Enables the Wire communication protocol.
    //#include <Adafruit_BME280.h>                    // alternative library you could try (DIY; no code for this is in here yet).
    //#include <SparkFunBME280.h>                     // alternative library you could try (DIY; no code for this is in here yet).
    #include <BME280_MOD-1022.h>                      // Bosch BME280 Embedded Adventures MOD-1022 weather multi-sensor Arduino code, written originally by Embedded Adventures. https://github.com/embeddedadventures/BME280
    
    
    // VARIABLES YOU CAN CHANGE
    const float ALTITUDE = 292;                        // Change this value to your location's altitude (in m). Use your smartphone GPS to get an accurate value, or use an online map.
    unsigned long BME280measurementInterval = 30000;  // Sleep time between reads for the BME sensor (in ms). Keep this value at 60000 if you have enabled the forecast feature, as the forecast algorithm needs a sample every minute.
    #define COMPARE_TEMP 1                            // Send temperature only if it changed? 1 = Yes 0 = No. Can save battery.
    float tempThreshold = 0.1;                        // How big a temperature difference has to minimally  be before an update is sent. Makes the sensor less precise, but also less jittery, and can save battery.
    #define COMPARE_HUM 1                             // Send temperature only if changed? 1 = Yes 0 = No. Can save battery.
    float humThreshold = 0.1;                         // How big a humidity difference has to minimally be before an update is sent. Makes the sensor less precise, but also less jittery, and can save battery.
    #define COMPARE_BARO 1                            // Send temperature only if changed? 1 = Yes 0 = No. Can save battery.
    float presThreshold = 0.1;                        // How big a barometric difference has to minimally be before an update is sent. Makes the sensor less precise, but also less jittery, and can save battery.
    
    
    //VARIABLES YOU PROBABLY SHOULDN'T CHANGE
    #define TEMP_CHILD_ID 0                // for MySensors. Within this node each sensortype should have its own ID number.
    #define HUM_CHILD_ID 1                // for MySensors. Within this node each sensortype should have its own ID number.
    #define BARO_CHILD_ID 2             // for MySensors. Within this node each sensortype should have its own ID number.
    float lastTemperature = -1;            // Stores the previous measurement, so it can be compared with a new measurement.
    float lastHumidity = -1;            // Stores the previous measurement, so it can be compared with a new measurement.
    float lastPressure = -1;            // Stores the previous measurement, so it can be compared with a new measurement.
    unsigned long BME280measurementSleepTime = 0;      // variable to store the calculated Sleep time if the node is battery powered.
    bool metric = true;                // Variable that stores if the sensor will output the temperature in Fahrenheit of Celsius. The gateway sends this preference to the node, so you dont need to change it here.
    bool receivedConfig = false;            // The MySensors gateway will tell the node if it should output in metric or not.
    
    #define CONVERSION_FACTOR (1.0/10.0)         // used by forecast algorithm to convert from Pa to kPa, by dividing hPa by 10.
    
    #ifdef GENERATE_FORECAST             //  Below you will find a lot of variables used by the forecast algorithm.
    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)
    };
    int lastForecast = -1;                // Stores the previous forecast, so it can be compared with a new forecast.
    const int LAST_SAMPLES_COUNT = 5;
    float lastPressureSamples[LAST_SAMPLES_COUNT];
    int minuteCount = 0;                // Helps the forecst algorithm keep time.
    bool firstRound = true;                // Helps the forecast algorithm recognise if the sensor has just been powered up.
    float pressureAvg;                // Average value is used in forecast algorithm.
    float pressureAvg2;                // Average after 2 hours is used as reference value for the next iteration.
    float dP_dt;                    // Pressure delta over time
    #endif
    
    // MYSENSORS COMMUNICATION VARIABLES
    MyMessage temperatureMsg(TEMP_CHILD_ID, V_TEMP);
    MyMessage humidityMsg(HUM_CHILD_ID, V_HUM);
    MyMessage pressureMsg(BARO_CHILD_ID, V_PRESSURE);
    #ifdef GENERATE_FORECAST
    MyMessage forecastMsg(BARO_CHILD_ID, V_FORECAST);
    #endif
    
    
    void setup() {
     Wire.begin(); // Wire.begin(sda, scl) // starts the wire communication protocol, used to chat with the BME280 sensor.
     Serial.begin(115200); // for serial debugging over USB.
     Serial.println("Hello world, I am a sensor node.");
    
    #ifdef BATTERY_POWERED // If the node is battery powered, we'll let Sleep take over the scheduling.
      BME280measurementSleepTime = BME280measurementInterval;
      BME280measurementInterval = 0; // When the Arduino is asleep, millis doesn't increment anymore (time stops as it were). To fix this, we'll set the measurement interval time to 1, so that when the arduino wakes up it will immediately try to measure again.
    #endif
    
    }
    
    
    void presentation()  {
     // Send the sketch version information to the gateway and Controller
     sendSketchInfo("BME280 Sensor", "1.1");
    
     // Tell the MySensors gateway what kind of sensors this node has, and what their ID's on the node are, as defined in the code above.
     present(BARO_CHILD_ID, S_BARO);
     present(TEMP_CHILD_ID, S_TEMP);
     present(HUM_CHILD_ID, S_HUM);
    }
    
    
    void loop() {
    
     // You should not change these variables:
     static unsigned long previousBME280Millis = 0;  // Used to remember the time that the BME280 sensor was asked for a measurement.
     unsigned long currentMillis = millis();         // The time since the sensor started, counted in milliseconds. This script tries to avoid using the Sleep function, so that it could at the same time be a MySensors repeater.
     static boolean BME280shouldAsk = true;          // This is true when the time is right for a new measurement to be made.
     static boolean BME280justAsked = false;         // This indicates whether we have just asked the sensor module for a measurement, so the receiving part of the code (part 2) should be primed. This two-part construction helps to bridge the time where the BME280 module is busy, without blocking the entire node from doing anything else (like being a repeater, or working with other connected sensor modules).
    
    
     // PART 1. If enough time has passed, a new measurement should be taken:
     if (BME280shouldAsk == true && currentMillis - previousBME280Millis >= BME280measurementInterval) {
       previousBME280Millis = currentMillis; // store the current time as the previous measurement start time.
       BME280shouldAsk = false;
       Serial.println("");
       Serial.println("BME280 - Requesting new data from sensor module.");
       BME280.readCompensationParams();    // Need to read the NVM compensation parameters.
    
    #ifdef BATTERY_POWERED
       // After taking the measurement the chip goes back to sleep. This code is only enabled if you enabled BATTERY POWERED at the top of this script.
       // 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.
    #else
       // 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);
    #endif
    
       // As we exit part 1, in theory BME280.isMeasuring() should now be true.
       BME280justAsked = true;   
     }
    
    
     // Part 2. This will trigger if the sensor has just been asked for a measurement, and is also just done figuring out those measurements.
     if(BME280justAsked == true && BME280.isMeasuring() == false) { // 
       BME280justAsked = false; // makes sure we don't do this part again in the next pass through the main loop.
       Serial.println("BME280 - Sensor module has some new values ready:");
    
       // Read out the data - must do this before calling the getxxxxx routines
       BME280.readMeasurements();
    
       float temperature = BME280.getTemperatureMostAccurate();                    // Must get the temperature first.
       float humidity = BME280.getHumidityMostAccurate();                // Get the humidity.
       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
    #ifdef GENERATE_FORECAST      
       int forecast = sample(pressure);                        // Run the forecast function with a new pressure update.
    #endif
    
       if (!metric) {
         // Convert temperature to fahrenheit
         temperature = temperature * 9.0 / 5.0 + 32.0;
       }
    
       // Useful for debugging
       Serial.print("BME280 - Temperature = ");
       Serial.print(temperature);
       Serial.println(metric ? " B0C" : " B0F");
       Serial.print("BME280 - Humidity = ");
       Serial.print(humidity);
       Serial.println(" %");
       Serial.print("BME280 - Pressure = ");
       Serial.print(pressure);
       Serial.println(" hPa");
    #ifdef GENERATE_FORECAST      
       Serial.print("BME280 - Forecast = ");
       Serial.println(weather[forecast]);
    #endif
    
       // Now, let's send the measurements to the gateway.
    
       // Send temperature
       if (COMPARE_TEMP == 1 && abs(temperature - lastTemperature) < tempThreshold) { // is the temperature difference bigger than the threshold?
         Serial.print(temperature - lastTemperature);
         Serial.print("- BME280 - Temperature difference too small, so not sending the new measurement to the gateway.\n");
       } else {
         Serial.print("BME280 - Sending the new temperature to the gateway.\n");
         send(temperatureMsg.set(temperature, 1));
         lastTemperature = temperature; // Save new temperatures to be able to compare in the next round.
       } 
    
       // Send humidity
       if (COMPARE_TEMP == 1 && abs(humidity - lastHumidity) < humThreshold) { // is the humidity difference bigger than the threshold?
         Serial.print(humidity - lastHumidity);
         Serial.println("- BME280 - Humidity difference too small, so not sending the new measurement to the gateway.");
       } else {
         Serial.println("BME280 - Sending the new humidity to the gateway.");
         send(humidityMsg.set(humidity, 1));
         lastHumidity = humidity; // Save new humidity to be able to compare in the next round.
       }
    
       // Send pressure
       if (COMPARE_TEMP == 1 && abs(pressure - lastPressure) < presThreshold) { // is the pressure difference bigger than the threshold?
         Serial.print(pressure - lastPressure);
         Serial.println("- BME280 - Pressure difference too small, so not sending the new measurement to the gateway.");
       } else {
         Serial.println("BME280 - Sending the new pressure to the gateway.");
         send(pressureMsg.set(pressure, 1));
         lastPressure = pressure; // Save new pressure to be able to compare in the next round.
       }
    
    #ifdef GENERATE_FORECAST
       // Send forecast
       if (forecast != lastForecast) {
         Serial.println("BME280 - Sending the latest forecast to the gateway.");      
         send(forecastMsg.set(weather[forecast]));
         lastForecast = forecast;
       }
    #endif 
    
     Serial.println("BME280 - Measurement complete. Going to wait until next measurement.");
     BME280shouldAsk = true; // Ready for the new round.
     }
    
    #ifdef BATTERY_POWERED
     // This code will only be included in the sketch if the BATTERY POWERED feature is enabled.
     if(BME280shouldAsk == true && BME280justAsked == false) { // Both parts are done, so we can let the sensor sleep again.
       unsigned long quicktimecheck = millis(); // To check how much time has passed since the beginning of being awake, and then calculate from that how long to sleep until the next intended measuring time, we need to know how many milliseconds have passed.
       unsigned long sleeptime = BME280measurementSleepTime - (quicktimecheck - previousBME280Millis); // How much time has passed already during the calculating? Subtract that from the intended interval time.
       Serial.println("BME280 - zzzzZZZZzzzzZZZZzzzz");
       sleep (sleeptime);
       Serial.println("BME280 - Waking up.");
     }
    #endif
    
    } // end of main loop.
    
    
    
    #ifdef GENERATE_FORECAST
    // These functions are only included if the forecast function is enables. The are used to generate a weater prediction by checking if the barometric pressure is rising or falling over time.
    
    float getLastPressureSamplesAverage()
    {
     float lastPressureSamplesAverage = 0;
     for (int i = 0; i < LAST_SAMPLES_COUNT; i++) {
       lastPressureSamplesAverage += lastPressureSamples[i];
     }
     lastPressureSamplesAverage /= LAST_SAMPLES_COUNT;
    
     return lastPressureSamplesAverage;
    }
    
    
    // Forecast 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("BME280 - 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;
    }
    #endif```

  • Mod

    @andrew-maynard no, something like this:

    Serial.println("At start of loop");
    

    If it turns out this line is printed, add more inside each if clause to see what happens / why nothing happens.


  • Mod

    @andrew-maynard the defines look good to me



  • I could not make the example BME280 sketch work either and upon investigation the code is not for the standard BME280 it is for the BME280 library by Embedded Adventures - https://github.com/embeddedadventures/BME280. This device is not the same as the cheaper standard BME280 as linked on the forum page. The Embedded Adventure one has humidity, the standard BME280 does not.

    Anyway I researched and converted some other BME280 code I found from the SFE_BMP180 library, coupled the Forecast code and created the following sketch for the BME280. You will need to install the SFE_BMP180.h library using library manager

    /**
     * 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
     * 
     */
    
    // Enable debug prints
    #define MY_DEBUG
    
    // Enable and select radio type attached 
    #define MY_RADIO_NRF24
    // #define MY_RF24_CHANNEL 82
    
    // #define MY_NODE_ID 22 //uncomment this line to assign a static ID
    
    #include <MySensors.h>  
    
    #define CHILD_ID_BARO  0
    #define CHILD_ID_TEMP 1
    
    static bool metric = true;
    
    // Sleep time between sensor updates (in milliseconds)
    unsigned long UPDATE_INTERVAL = 60000;
    
    #define ALTITUDE 28.0 // Altitude  in meters
    
    #define GENERATE_FORECAST
    
    #define CONVERSION_FACTOR (1.0/10.0)     // used by forecast algorithm to convert from Pa to kPa, by dividing hPa by 10.
    #ifdef GENERATE_FORECAST      //  Below you will find a lot of variables used by the forecast algorithm.
      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)
      };
      int lastForecast = -1;        // Stores the previous forecast, so it can be compared with a new forecast.
      const int LAST_SAMPLES_COUNT = 5;
      float lastPressureSamples[LAST_SAMPLES_COUNT];
      int minuteCount = 0;        // Helps the forecst algorithm keep time.
      bool firstRound = true;       // Helps the forecast algorithm recognise if the sensor has just been powered up.
      float pressureAvg;        // Average value is used in forecast algorithm.
      float pressureAvg2;       // Average after 2 hours is used as reference value for the next iteration.
      float dP_dt;          // Pressure delta over time
    #endif
    
    #include <SFE_BMP180.h>
    
    static SFE_BMP180 pressure;
    
    static MyMessage msgBaro(CHILD_ID_BARO, V_PRESSURE );
    static MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
    #ifdef GENERATE_FORECAST
      MyMessage msgForecast(CHILD_ID_BARO, V_FORECAST);
    #endif
    
    void presentation()  
    { 
      // Send the sketch info to the gateway
      sendSketchInfo("TemperatureAndPressure", "1.0");
    
      // Present sensors as children to gateway
      present(CHILD_ID_BARO, S_BARO, "Pressure");
      wait(50);
      present(CHILD_ID_TEMP, S_TEMP, "Temperature");
      wait(50);
      metric = getControllerConfig().isMetric;
    }
    
    void setup()
    {
      pressure.begin();
    }
    
    
    void loop()      
    {  
      char status;
      double T,P,p0,a;
      unsigned long currentMillis = millis();
    
      status = pressure.startTemperature();
      if (status != 0) { wait(status); }
      status = pressure.getTemperature(T);
      if (status != 0)
      {
        // Print out the measurement:
        Serial.print("temperature: ");
        Serial.print(T,2);
        Serial.print(" deg C, ");
        Serial.print((9.0/5.0)*T+32.0,2);
        Serial.println(" deg F");
        send(msgTemp.set(T, 2));
      }
      // Start a pressure measurement:
      // The parameter is the oversampling setting, from 0 to 3 (highest res, longest wait).
      // If request is successful, the number of ms to wait is returned.
      // If request is unsuccessful, 0 is returned.
      status = pressure.startPressure(3);
      if (status != 0) { wait(status); }
      status = pressure.getPressure(P,T);
      if (status != 0)
      {
        // Print out the measurement:
        Serial.print("absolute pressure: ");
        Serial.print(P,2);
        Serial.print(" mb, ");
        Serial.print(P*0.0295333727,2);
        Serial.println(" inHg");
        send(msgBaro.set(P, 2));        
      }
      
    #ifdef GENERATE_FORECAST      
        int forecast = sample(P);            // Run the forecast function with a new pressure update.
    
        // Send forecast
        if (forecast != lastForecast) {
          Serial.println("BME280 - Sending the latest forecast to the gateway.");      
          send(msgForecast.set(weather[forecast]));
          lastForecast = forecast;
        }
    #endif
    
      // Sleep until next update to save energy but check for how long to sleep based on delays in getting data
      unsigned long sleeptime = UPDATE_INTERVAL  - (millis() - currentMillis); // How much time has passed already during the calculating? Subtract that from the intended interval time.
      wait(sleeptime); 
    }
    
    
    
    #ifdef GENERATE_FORECAST
    // These functions are only included if the forecast function is enables. The are used to generate a weater prediction by checking if the barometric pressure is rising or falling over time.
    
    float getLastPressureSamplesAverage()
    {
      float lastPressureSamplesAverage = 0;
      for (int i = 0; i < LAST_SAMPLES_COUNT; i++) {
        lastPressureSamplesAverage += lastPressureSamples[i];
      }
      lastPressureSamplesAverage /= LAST_SAMPLES_COUNT;
    
      return lastPressureSamplesAverage;
    }
    
    
    // Forecast 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("BME280 - 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;
    }
    #endif
    

  • Mod

    @itbeyond some chinese suppliers sell the BMP280 labelled as BME280. Could that be the case with yours? See https://goughlui.com/2018/08/05/note-bosch-sensortec-bmp280-vs-bme280-sensor-confusion/ for some details.



  • @mfalkvidd Yes seems right but the most confusing part and the one I stumbled on is that on the page https://www.mysensors.org/build/pressure for the sensor the Shopping Guide points you at the BMP280 which as we are identifying is not the relevant item for the project - I followed the provided link and purchased the sensor (after waiting for weeks for delivery) only to find it does not work at all (as I suspect my be the case for @Andrew-Maynard as the sensors does not init and the loop does not run) and hence my code was needed to run the node using the item shown in the shopping guide.


  • Mod

    @itbeyond good catch. I've created https://forum.mysensors.org/topic/9801/bmp-e-atmospheric-pressure to not derail this thread.



  • @mfalkvidd Finally we get the build page sorted out ?- that would be good 😉

    I purchased a BME280 and was sent BMP280.

    I sent the seller photos of the module and the screen capture of the test reporting it as BMP and not BME.

    Seller then stopped all communcations. A week later I had to open dispute to get my money back.

    I got mine from ....

    "Aliexpress" seller "All Electronics Trading Company" - I do not trust this seller......

    I am now awaiting a BME280 from another seller on another site!



  • @itbeyond unfortunately I have the BME280 from Adafruit.



  • @mfalkvidd I took a glance at the embeddedadventures code on Github. They have a separate sketch for the samd21. Since I'm using a FeatherM0 could that be the reason why? I don't have the skills to decipher the differences. Once again I appreciate it!

    I added the serial print to the beginning of loop().

    15:37:58.624 -> At start of loop
    15:37:58.624 -> At start of loop
    15:37:58.624 -> At start of loop
    15:37:58.624 -> At start of loop
    15:37:58.624 -> At start of loop
    

 

424
Online

7.9k
Users

8.8k
Topics

93.8k
Posts