BME280 temp/humidity/pressure sensor
-
@yoshida Hello
You can share your sketch.
Please
I can not make modifications.
I still have a lot of errors.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); } } -
@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. -
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,
-
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,
@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.
-
@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.
@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.
-
@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.
@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)
-
@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); } } -
@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); } }@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)); }
-
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.