Solar Powered Node

Garinger Gardens stretches across several acres. There are plans to construct several hoop houses away from the main greenhouse. These hoop houses will not have electricity. One of the high school students, Romell Sessoms, wanted to build a sensor node that was powered from a solar panel. This node would work great in a hoop house.

Voltaic Setup

We were a little aggressive with our design including  the radio plus 3 sensors (5 measurements) :

  • Air Temperature
  • Air Humidity
  • Air Pressure
  • Light Intensity (Lux)
  • Soil Moisture

That is quite substantial and will provide some great information for knowing when the temperature or moisture in the hoop house is too high or low.

Bill of Materials

For the setup to be durable we needed some quality parts

  • Voltaic 2 Watt Solar Panel Kit (comes with panel and V15 battery)
  • To add flexibility on where the panel was mounted we got the 10′ extension cable
  • Arduino Pro Mini 3.3V (Arduino, Sparkfun, Adafruit, aliexpress, ebay)
  • BME280 Breakout board (Sparkfun,Adafruit, aliexpress, ebay)
  • BH1750 Breakout Board (Sparkfun,Adafruit, aliexpress, ebay)
  • Soil Hygrometer Humidity Detection Module Water Sensor (Sparkfun,Adafruit, aliexpress, ebay)
  • NRF24L01+PA+LNA 2.4GHz Radio (Sparkfun,Adafruit, aliexpress, ebay) can use short range version if not far from gateway. Also may need a 4.7uF capactor

MySensors has a shopping page with good links for most items – http://www.mysensors.org/store/

Please note you can use any arduino board for this project although they do have slightly different power requirements. The board we chose has a lower voltage range which was fine for these sensors and radio but this board does not have a USB connection.

Wiring

First, organized everything using a breadboard –

solar_components

(click on image for larger view)

with the wires –

solar_wired_sm

(click on image for larger view)

The BH1750 and the BME280 are using I2C and are connected to the A4 and A5 pins. The sketch uses the arduino library from Embedded Adventures.

The soil moisture sensor was attached to A0 (using analog signal only).

The radio must be attached following the instructions on MySensors – Connecting the Radio.

The Pro Mini does not have a USB adapter so we cut an old USB cable and wired it directly to the board. There are only 4 wires in a standard USB cable and for this project we only need two of them. – https://en.wikipedia.org/wiki/USB#Pinouts

Programming

Since there is no USB connection on the Pro Mini you do need a FTDI USB to TTL Serial Adapter. Purchase links again on mysensors.

ftdi

(click on image for larger view)

To reduce power consumption the arduino will be in sleep mode most of the time. When it wakes it will check the sensors and if needed will transmit the values via the radio to the gateway. Transmitting via the radio takes the most energy so we only want to transmit when necessary. Our arduino is therefore programmed to only send data when a measurement changes or if a threshold of skipped measurements has occurred. This means that if the measurement does not change at a certain point it will transmit the measurement anyway. The timing depends on how long the sleep time is and the allowed number of skipped measurements.

The full sketch –


/**
* This sketch was created by Brit Pair although it builds from all the great sketches
* on MySensors and elsewhere. I include the description of mysensors here:
*
* 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.
*
*
* 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 - Brit Pair
*
* DESCRIPTION
* Weather, Light, Soil Moisture Sensor
*
*
*/
#include
#include//Weather
#include//Lux
#include
#include//Moisture// Define a static node address, remove if you want auto address assignment
#define NODE_ADDRESS 80//Child Sensor ID
#define CHILD_ID_MOIST 10
#define CHILD_ID_HUM 40
#define CHILD_ID_TEMP 41
#define CHILD_ID_PRESS 42
#define CHILD_ID_LIGHT 60#define COMPARE_TEMP 0 // Send temperature only if changed? 1 = Yes 0 = No
unsigned long SLEEP_TIME = 300000; // Sleep time between reads (in milliseconds) (Rough measurement of 5V supply is 0.3milliamps awake and 0.05mA sleeping)
int maxSkippedReadings = 15;boolean metric = false;

MySensor gw;

//lux
BH1750 lightSensor;

//Soil
#define ANALOG_INPUT_SOIL_SENSOR 0 // Digital input did you attach your soil sensor.
#define DIGITAL_INPUT_SOIL_SENSOR 3 // Digital input did you attach your soil sensor.
#define INTERRUPT DIGITAL_INPUT_SOIL_SENSOR-2 // Usually the interrupt = pin -2 (on uno/nano anyway)

//BME280
MyMessage msgHum(CHILD_ID_HUM, V_HUM);
MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
MyMessage msgPress(CHILD_ID_PRESS, V_PRESSURE);
float lastHum;
float lastTemp;
float lastPress;
int skippedTempReadings = 0;
int skippedHumidReadings = 0;
int skippedPressReadings = 0;

// Moisture
MyMessage msgMoist(CHILD_ID_MOIST, V_LEVEL);
uint16_t lastMoist;
uint16_t moistMaxReading = 1023;
uint16_t moistMinReading = 200;
int skippedMoistReadings = 0;

// light level.
MyMessage msgLux(CHILD_ID_LIGHT, V_LEVEL);
uint16_t lastlux;
int skippedLuxReadings = 0;

void setup() {
Serial.begin(115200);

// put your setup code here, to run once:
gw.begin();

#ifdef NODE_ADDRESS
gw.begin(NULL, NODE_ADDRESS, false);
#else
gw.begin(NULL, AUTO, false);
#endif

// Send the Sketch Version Information to the Gateway
gw.sendSketchInfo(“SOLAR_WEATHER”, “1.0”);

// 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_PRESS, S_BARO);
gw.present(CHILD_ID_LIGHT, S_LIGHT_LEVEL);
gw.present(CHILD_ID_MOIST, S_MOISTURE);

Wire.begin();

lightSensor.begin();

// if (!bme.begin()) {
// Serial.println(“Could not find a valid BME280 sensor, check wiring!”);
// }

}

void loop() {

gw.sleep(SLEEP_TIME); //sleep a bit first
// Process incoming messages (like config from server)
gw.process();

loopWeather();

loopMoisture();

loopLux();
}

void loopLux()
{
uint16_t lux = lightSensor.readLightLevel();// Get Lux value

if (isnan(lux)) {
Serial.println(“Failed reading Lux”);
} else if (lux != lastlux || skippedLuxReadings > maxSkippedReadings) {
skippedLuxReadings = 0;
lastlux = lux;
gw.send(msgLux.set(lux));
Serial.println(“”);
Serial.println(“Lux = “);
Serial.print(lux);
Serial.println(“”);
} else {
skippedLuxReadings = skippedLuxReadings + 1;
// Serial.println(“”);
// Serial.println(“Lux = “);
// Serial.print(lux);
// Serial.println(“”);
}

}

void loopMoisture()
{
uint16_t moistRaw = analogRead(ANALOG_INPUT_SOIL_SENSOR);
float range = (abs((float(moistRaw – moistMinReading))) / (float(moistMaxReading – moistMinReading)));

uint16_t moist = int((1 -range) * 100);

Serial.println(“”);
Serial.println(“MOISTURE RAW = “);
Serial.print(moistRaw);
Serial.println(“”);

if (isnan(moist)) {
Serial.println(“Failed reading moisture”);
} else if (moist != lastMoist || skippedMoistReadings > maxSkippedReadings) {
skippedMoistReadings = 0;
lastMoist = moist;
gw.send(msgMoist.set(moist));
Serial.println(“”);
Serial.println(“Moisture = “);
Serial.print(moist);
Serial.println(“”);
} else {
skippedMoistReadings = skippedMoistReadings + 1;
// Serial.println(“”);
// Serial.println(“Moisture = “);
// Serial.print(moist);
// Serial.println(“”);
}

}

void loopWeather()
{
// need to read the NVM compensation parameters
BME280.readCompensationParams();

// Need to turn on 1x oversampling, default is os_skipped, which means it doesn’t measure anything
BME280.writeOversamplingPressure(os1x); // 1x over sampling (ie, just one sample)
BME280.writeOversamplingTemperature(os1x);
BME280.writeOversamplingHumidity(os1x);

BME280.writeMode(smForced);
int cnt = 0;
while (BME280.isMeasuring() && cnt < 3) { cnt = cnt + 1; delay(50); } // read out the data – must do this before calling the getxxxxx routines BME280.readMeasurements(); float temp = BME280.getTemperature(); temp = ((temp * 9 )/ 5) + 32; if (isnan(temp)) { Serial.println(“Failed reading temperature from BME280”); } else if (temp != lastTemp || skippedTempReadings > maxSkippedReadings) {
skippedTempReadings = 0;
lastTemp = temp;
gw.send(msgTemp.set(temp, 1));
Serial.println(“”);
Serial.println(“Temperature = “);
Serial.print(temp);
Serial.println(“”);
} else {
skippedTempReadings = skippedTempReadings + 1;
// Serial.println(“”);
// Serial.println(“Temperature = “);
// Serial.print(temp);
// Serial.println(“”);
}

float pres = BME280.getPressure() / 33.8639;

if (isnan(pres)) {
Serial.println(“Failed reading pressure from BME280”);
} else if (pres != lastPress || skippedPressReadings > maxSkippedReadings) {
skippedPressReadings = 0;
lastPress = pres;
gw.send(msgPress.set(pres, 1));
Serial.println(“”);
Serial.println(“Pressure = “);
Serial.print(pres);
Serial.println(“”);
} else {
skippedPressReadings = skippedPressReadings + 1;
// Serial.println(“”);
// Serial.println(“Pressure = “);
// Serial.print(pres);
// Serial.println(“”);
}

float humid = BME280.getHumidity();
if (isnan(humid)) {
Serial.println(“Failed reading humidity from BME280”);
} else if (humid != lastHum || skippedHumidReadings > maxSkippedReadings) {
skippedHumidReadings = 0;
lastHum = humid;
gw.send(msgHum.set(humid, 1));
Serial.println(“”);
Serial.println(“Humidity = “);
Serial.print(humid);
Serial.println(“”);
} else {
skippedHumidReadings = skippedHumidReadings + 1;
// Serial.println(“”);
// Serial.println(“Humidity = “);
// Serial.print(humid);
// Serial.println(“”);
}

}

 

Testing

Testing the power consumption we measured the following:

Sleeping: 5V, 3.9 mA

Transmitting: 5V, 35mA

We will use a 5 minute sleep. The active time is hard to measure but should be very small 1/10th of a second.

Solar Kit

The solar kit from Voltaic is really nice. The panel is weatherproof and the battery case seems very durable. The battery has Short Circuit, Over Charge, Over Discharge, Over Current, and Over Temperature protection so we do not have to worry about it. It also has an “always on” mode which we will be using for our setup. We are in North Carolina and even when the sky was very overcast the panel was still charging the battery, so we are very optimistic.

Packaging

Our packaging selection has caused some problems. We are using a small plastic enclosure but it is a little too small. After pushing everything in to the enclosure it has created a intermittent disconnect with the soil moisture sensor. We hope to move everything into a bigger enclosure in the future or just not use the soil moisture sensor.

WeatherNodesm

(click on image for larger view)

Installation

The hoop houses are not ready yet so Romell and I put the sensor node in the worm bin.

Romellsm

(click on image for larger view)

Live Data!

Sorry the hotspot at the greenhouse unfortunately disappeared so the data is no longer available online.

If things are working smoothly you can follow the live data on the dashboard below. If the graphs below show “No Datapoints” the internet may be down at the greenhouse (not a problem with the sensor but the cellular hotspot and data plan we are using). You can view older data by selecting “Zoom Out” in the upper right and increasing the time range.