Mini Weather Station
-
This is a new mini weather station that I have been working on.
It provides Temperature, Humidity, Pressure, and Battery Voltage.
The case is designed to be printed without the need for any support, has vents in the front and sides. The front slides on to make it easy to replace the 9v battery. It is designed to take a 50x70mm prototype board. This gives heaps of room for the sensors.
The 3d files can be found on http://www.thingiverse.com/thing:704715
The code is mostly a refactor from the examples in the MySensors libraries, with a simplification of the forecast algorithm to reduce the amount of memory that it uses.
#include <SPI.h> #include <MySensor.h> #include <DHT.h> #include <Wire.h> #include <Adafruit_BMP085.h> #define CHILD_ID_HUM 0 #define CHILD_ID_TEMP 1 #define CHILD_ID_BARO 2 #define CHILD_ID_BARO_TEMP 3 #define HUMIDITY_SENSOR_DIGITAL_PIN 3 int BATTERY_SENSE_PIN = A0; // select the input pin for the battery sense point #define SLEEP_MINUTE 60000 #define SLEEP_FIVE_MINUTES 300000 MySensor gw; DHT dht; Adafruit_BMP085 bmp = Adafruit_BMP085(); // Digital Pressure Sensor float lastTemp = -1.0; float lastHum = -1.0; float lastBaroTemp = -1.0; int lastForecast = -1; char *weather[] = { "Stable", "Sunny", "Cloudy", "Unstable", "Thunderstorm", "Unknown" }; int minutes; int pressureSamples[5]; float lastPressureAvg = -1.0; int lastPressure = -1; int minuteCount = 0; float pressureAvg; int pressure; float dP_dt; boolean metric = true; MyMessage msgHum(CHILD_ID_HUM, V_HUM); MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP); MyMessage msgBaroTemp(CHILD_ID_BARO_TEMP, V_TEMP); MyMessage msgBaro(CHILD_ID_BARO, V_PRESSURE); MyMessage msgForecast(CHILD_ID_BARO, V_FORECAST); void setup() { // use the 1.1 V internal reference analogReference(INTERNAL); gw.begin(); dht.setup(HUMIDITY_SENSOR_DIGITAL_PIN); if (!bmp.begin()) { Serial.println("Could not find a valid BMP085 sensor, check wiring!"); } // Send the Sketch Version Information to the Gateway gw.sendSketchInfo("Mini Weather Station", "3.2"); // Register all sensors to gw (they will be created as child devices) gw.present(CHILD_ID_HUM, S_HUM); gw.present(CHILD_ID_TEMP, S_TEMP); gw.present(CHILD_ID_BARO, S_BARO); gw.present(CHILD_ID_BARO_TEMP, S_TEMP); metric = gw.getConfig().isMetric; } void loop() { Serial.print("minuteCount = "); Serial.println(minuteCount); // The pressure Sensor Stuff int forecast = SamplePressure(); if ( minuteCount > 4 ) { // only every 5 minutes // Process the barometric sensor data float baro_temperature = bmp.readTemperature(); if (!metric) { // Convert to fahrenheit baro_temperature = baro_temperature * 9.0 / 5.0 + 32.0; } if (baro_temperature != lastBaroTemp) { gw.send(msgBaroTemp.set(baro_temperature, 1)); lastBaroTemp = baro_temperature; } if (pressure != lastPressure) { gw.send(msgBaro.set(pressure, 0)); //delay(1000); // gw.send(msgBaro.set(pressure)); lastPressure = pressure; } if (forecast != lastForecast) { gw.send(msgForecast.set(weather[forecast])); lastForecast = forecast; } // The humidity sensor stuff delay(dht.getMinimumSamplingPeriod()); float temperature = dht.getTemperature(); if (isnan(temperature)) { Serial.println("Failed reading temperature from DHT"); } else if (temperature != lastTemp) { lastTemp = temperature; if (!metric) { temperature = dht.toFahrenheit(temperature); } gw.send(msgTemp.set(temperature, 1)); Serial.print("Temperature: "); Serial.println(temperature); } float humidity = dht.getHumidity(); if (isnan(humidity)) { Serial.println("Failed reading humidity from DHT"); } else if (humidity != lastHum) { lastHum = humidity; gw.send(msgHum.set(humidity, 1)); Serial.print("Humidity: "); Serial.println(humidity); } // get the battery Voltage long sensorValue = analogRead(BATTERY_SENSE_PIN); // 1M, 100K divider across battery and using internal ADC ref of 1.1V // Sense point is bypassed with 0.1 uF cap to reduce noise at that point // ((1e6+100e3)/100e3)*1.1 = Vmax = 12.1 Volts // 12.1/1023 = Volts per bit = 0.011827957 // sensor val at 9v = 9/0.011827957 = 760.909090217 // float batteryV = sensorValue * 0.011827957; long batteryValue = sensorValue * 100L; int batteryPcnt = batteryValue / 761; gw.sendBatteryLevel((batteryPcnt > 100 ? 100 : batteryPcnt)); // this allows for batteries that have slightly over 9v Serial.print("Batt %:"); Serial.println(batteryPcnt); } if ( minuteCount < 5 ) // sleep a bit gw.sleep(SLEEP_MINUTE); //while pressure sampling else gw.sleep(SLEEP_FIVE_MINUTES); } int SamplePressure() { // This is a simplification of Algorithm found here to same memory // http://www.freescale.com/files/sensors/doc/app_note/AN3914.pdf pressure = bmp.readSealevelPressure(60) / 100; // 60 meters above sealevel if (minuteCount > 9) { // we are going to test pressure change every 30 min (5*1min + 5*5min) lastPressureAvg = pressureAvg; minuteCount = 0; } if (minuteCount < 5) { pressureSamples[minuteCount] = pressure; // Collect 5 minutes of samples every 30 min Serial.print(" Sample("); Serial.print(minuteCount); Serial.print(") = "); Serial.println(pressure); } if (minuteCount == 4) { // the 5th minute // Avg pressure in first 5 min, value averaged from 0 to 5 min. pressureAvg = ((pressureSamples[0] + pressureSamples[1] + pressureSamples[2] + pressureSamples[3] + pressureSamples[4]) / 5); float change = pressureAvg - lastPressureAvg; dP_dt = (((65.0 / 1023.0) * change) / 0.5); // divide by 0.5 as this is the difference in time from last sample 0.5 hours Serial.print("dP_dt = "); Serial.println(dP_dt); } minuteCount++; if (lastPressureAvg < 0) // no previous pressure sample. return 5; // Unknown, more time needed else if (dP_dt < (-0.25)) return 4; // Quickly falling LP, Thunderstorm, not stable else if (dP_dt > 0.25) return 3; // Quickly rising HP, not stable weather else if ((dP_dt > (-0.25)) && (dP_dt < (-0.05))) return 2; // Slowly falling Low Pressure System, stable rainy weather else if ((dP_dt > 0.05) && (dP_dt < 0.25)) return 1; // Slowly rising HP stable good weather else if ((dP_dt > (-0.05)) && (dP_dt < 0.05)) return 0; // Stable weather else return 5; // Unknown } -
Nice!! I'm thinking about running a Nano + DHT22 with 9V block. What do you suppose, how long will the sensor run?
-
-
Nice!! I'm thinking about running a Nano + DHT22 with 9V block. What do you suppose, how long will the sensor run?
@TimO Its been running for about 2 weeks now, and used 5-6% of the battery. I have pulled the leds off of the nano to make it last longer (I was only getting 3 weeks with the leds on). It would be nice to think that I could get 20 weeks. I am also thinking of some more code changes to reduce them amount of power consumed.
-
@TimO Its been running for about 2 weeks now, and used 5-6% of the battery. I have pulled the leds off of the nano to make it last longer (I was only getting 3 weeks with the leds on). It would be nice to think that I could get 20 weeks. I am also thinking of some more code changes to reduce them amount of power consumed.
else if (temperature != lastTemp)So I've been working with temperature sensors a while and I worry about comparing floats, and their notorious precision triggering a true here and superfluously affecting the rate of the radio updates. The DHT22 is accurate to about 1 Celsius degree, so it may be unnecessary to transmit a change if there is a change to temperature at any precision of less than 1.
maybe try something like:
if (temperature > lastTemp + 0.5 || temperature < lastTemp - 0.5) { doSomething(); lastTemp = temperature; }Would reduce transmissions and save battery?
same argument with your hygrometer and barometric pressure, but different level of precision. Not for the weather calculations, just for the decision to transmit updates, IMO.
all easy to test with your serial monitor.
-
This is a new mini weather station that I have been working on.
It provides Temperature, Humidity, Pressure, and Battery Voltage.
The case is designed to be printed without the need for any support, has vents in the front and sides. The front slides on to make it easy to replace the 9v battery. It is designed to take a 50x70mm prototype board. This gives heaps of room for the sensors.
The 3d files can be found on http://www.thingiverse.com/thing:704715
The code is mostly a refactor from the examples in the MySensors libraries, with a simplification of the forecast algorithm to reduce the amount of memory that it uses.
#include <SPI.h> #include <MySensor.h> #include <DHT.h> #include <Wire.h> #include <Adafruit_BMP085.h> #define CHILD_ID_HUM 0 #define CHILD_ID_TEMP 1 #define CHILD_ID_BARO 2 #define CHILD_ID_BARO_TEMP 3 #define HUMIDITY_SENSOR_DIGITAL_PIN 3 int BATTERY_SENSE_PIN = A0; // select the input pin for the battery sense point #define SLEEP_MINUTE 60000 #define SLEEP_FIVE_MINUTES 300000 MySensor gw; DHT dht; Adafruit_BMP085 bmp = Adafruit_BMP085(); // Digital Pressure Sensor float lastTemp = -1.0; float lastHum = -1.0; float lastBaroTemp = -1.0; int lastForecast = -1; char *weather[] = { "Stable", "Sunny", "Cloudy", "Unstable", "Thunderstorm", "Unknown" }; int minutes; int pressureSamples[5]; float lastPressureAvg = -1.0; int lastPressure = -1; int minuteCount = 0; float pressureAvg; int pressure; float dP_dt; boolean metric = true; MyMessage msgHum(CHILD_ID_HUM, V_HUM); MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP); MyMessage msgBaroTemp(CHILD_ID_BARO_TEMP, V_TEMP); MyMessage msgBaro(CHILD_ID_BARO, V_PRESSURE); MyMessage msgForecast(CHILD_ID_BARO, V_FORECAST); void setup() { // use the 1.1 V internal reference analogReference(INTERNAL); gw.begin(); dht.setup(HUMIDITY_SENSOR_DIGITAL_PIN); if (!bmp.begin()) { Serial.println("Could not find a valid BMP085 sensor, check wiring!"); } // Send the Sketch Version Information to the Gateway gw.sendSketchInfo("Mini Weather Station", "3.2"); // Register all sensors to gw (they will be created as child devices) gw.present(CHILD_ID_HUM, S_HUM); gw.present(CHILD_ID_TEMP, S_TEMP); gw.present(CHILD_ID_BARO, S_BARO); gw.present(CHILD_ID_BARO_TEMP, S_TEMP); metric = gw.getConfig().isMetric; } void loop() { Serial.print("minuteCount = "); Serial.println(minuteCount); // The pressure Sensor Stuff int forecast = SamplePressure(); if ( minuteCount > 4 ) { // only every 5 minutes // Process the barometric sensor data float baro_temperature = bmp.readTemperature(); if (!metric) { // Convert to fahrenheit baro_temperature = baro_temperature * 9.0 / 5.0 + 32.0; } if (baro_temperature != lastBaroTemp) { gw.send(msgBaroTemp.set(baro_temperature, 1)); lastBaroTemp = baro_temperature; } if (pressure != lastPressure) { gw.send(msgBaro.set(pressure, 0)); //delay(1000); // gw.send(msgBaro.set(pressure)); lastPressure = pressure; } if (forecast != lastForecast) { gw.send(msgForecast.set(weather[forecast])); lastForecast = forecast; } // The humidity sensor stuff delay(dht.getMinimumSamplingPeriod()); float temperature = dht.getTemperature(); if (isnan(temperature)) { Serial.println("Failed reading temperature from DHT"); } else if (temperature != lastTemp) { lastTemp = temperature; if (!metric) { temperature = dht.toFahrenheit(temperature); } gw.send(msgTemp.set(temperature, 1)); Serial.print("Temperature: "); Serial.println(temperature); } float humidity = dht.getHumidity(); if (isnan(humidity)) { Serial.println("Failed reading humidity from DHT"); } else if (humidity != lastHum) { lastHum = humidity; gw.send(msgHum.set(humidity, 1)); Serial.print("Humidity: "); Serial.println(humidity); } // get the battery Voltage long sensorValue = analogRead(BATTERY_SENSE_PIN); // 1M, 100K divider across battery and using internal ADC ref of 1.1V // Sense point is bypassed with 0.1 uF cap to reduce noise at that point // ((1e6+100e3)/100e3)*1.1 = Vmax = 12.1 Volts // 12.1/1023 = Volts per bit = 0.011827957 // sensor val at 9v = 9/0.011827957 = 760.909090217 // float batteryV = sensorValue * 0.011827957; long batteryValue = sensorValue * 100L; int batteryPcnt = batteryValue / 761; gw.sendBatteryLevel((batteryPcnt > 100 ? 100 : batteryPcnt)); // this allows for batteries that have slightly over 9v Serial.print("Batt %:"); Serial.println(batteryPcnt); } if ( minuteCount < 5 ) // sleep a bit gw.sleep(SLEEP_MINUTE); //while pressure sampling else gw.sleep(SLEEP_FIVE_MINUTES); } int SamplePressure() { // This is a simplification of Algorithm found here to same memory // http://www.freescale.com/files/sensors/doc/app_note/AN3914.pdf pressure = bmp.readSealevelPressure(60) / 100; // 60 meters above sealevel if (minuteCount > 9) { // we are going to test pressure change every 30 min (5*1min + 5*5min) lastPressureAvg = pressureAvg; minuteCount = 0; } if (minuteCount < 5) { pressureSamples[minuteCount] = pressure; // Collect 5 minutes of samples every 30 min Serial.print(" Sample("); Serial.print(minuteCount); Serial.print(") = "); Serial.println(pressure); } if (minuteCount == 4) { // the 5th minute // Avg pressure in first 5 min, value averaged from 0 to 5 min. pressureAvg = ((pressureSamples[0] + pressureSamples[1] + pressureSamples[2] + pressureSamples[3] + pressureSamples[4]) / 5); float change = pressureAvg - lastPressureAvg; dP_dt = (((65.0 / 1023.0) * change) / 0.5); // divide by 0.5 as this is the difference in time from last sample 0.5 hours Serial.print("dP_dt = "); Serial.println(dP_dt); } minuteCount++; if (lastPressureAvg < 0) // no previous pressure sample. return 5; // Unknown, more time needed else if (dP_dt < (-0.25)) return 4; // Quickly falling LP, Thunderstorm, not stable else if (dP_dt > 0.25) return 3; // Quickly rising HP, not stable weather else if ((dP_dt > (-0.25)) && (dP_dt < (-0.05))) return 2; // Slowly falling Low Pressure System, stable rainy weather else if ((dP_dt > 0.05) && (dP_dt < 0.25)) return 1; // Slowly rising HP stable good weather else if ((dP_dt > (-0.05)) && (dP_dt < 0.05)) return 0; // Stable weather else return 5; // Unknown } -
else if (temperature != lastTemp)So I've been working with temperature sensors a while and I worry about comparing floats, and their notorious precision triggering a true here and superfluously affecting the rate of the radio updates. The DHT22 is accurate to about 1 Celsius degree, so it may be unnecessary to transmit a change if there is a change to temperature at any precision of less than 1.
maybe try something like:
if (temperature > lastTemp + 0.5 || temperature < lastTemp - 0.5) { doSomething(); lastTemp = temperature; }Would reduce transmissions and save battery?
same argument with your hygrometer and barometric pressure, but different level of precision. Not for the weather calculations, just for the decision to transmit updates, IMO.
all easy to test with your serial monitor.
@BulldogLowell Thanks, that looks like it is worth a try, or just round to 0.5 degree. I am also going to cut down the sample interval. After the 1min samples to average for the pressure, the rest of the time 5min is probably good enough.
-
@BulldogLowell Thanks, that looks like it is worth a try, or just round to 0.5 degree. I am also going to cut down the sample interval. After the 1min samples to average for the pressure, the rest of the time 5min is probably good enough.
maybe, but you may still have the same precision problem if you are using floats.
maybe just round and cast it to an int... DHT22 isn't precise to half a degree F or C...
int roundedTemperature = (int) floor(temperature + 0.5); if (roundedTemperature != lastTemperature) { doSomething(); lastTemperature = roundedTemperature; }more on floats and their precision...
-
-
@ jtm312
Dear..
Great project!
I print your station, very good quality!!!How is the battery?
Do you have options to reduce the power?
Is this sketch the best option?
Do you have a list that i need to buy so i can build this nice station?Thanks!!!
@Dylano Thanks.
I get 3-4 months from a battery by just removing the 2 LEDs from the arduino. Could probably do better running it from 2 AAA batteries and removing the voltage regulator as well. To save more power, you could also increase the interval between sending updates to the controller.
To build it you need:
- Arduino Pro Mini
- Humidity Sensor – DHT22 Aliexpress
- list itemPressure Sensor – BMP180 Aliexpress
- Prototype board & Battery Connector
Connections:
- Radio connected as http://www.mysensors.org/build/connect_radio
- 3.3V to sensors from arduino
- Battery Sense - A0 - connected as http://www.mysensors.org/build/battery R1=1M * R2=100k
- BMP085 - SCL - A5
- BMP085 - SCA - A4
- DHT22 - D3
-
Think about to replace your DHT22 with a less current hungry sensor
HTU21D cold be a good choice (But only running 3,3V)

