Introduction: Solar Powered Time-Lapse Cold Frame

This project is an effort to take time-lapse images of plants growing using only solar power.

It is principally an arduino project using the Ai-thinker ESP32-Cam.

Features

  • Saves an image to SD card every at regular intervals during daylight hours
  • Measures humidity
  • Measures the temperature inside the frame, outside the frame and of the soil
  • Measures moisture of soil
  • Measures solar panel voltage
  • Measures battery voltage
  • Records sensor data using IFTTT service to google sheets
  • Records sensor data to an MQTT server running on a raspberry PI
  • Data displayed on Node-Red Dashboard (pictured)

Shopping list

  • Materials for the cold frame. I used flooring offcuts, since your flooring offcuts will be different I have omitted the construction of this. (Hopefully free)
  • ESP32-CAM - I used the Ai-thinker module because it has a built in SD reader and has some spare IO (£7ish)
  • BME280 breakout board. This instructable asssumes you have an I2C version. There aren't enough vacant pins for the SPI version. (£5 ish)
  • 2 x Dallas DS18B20 one-wire temperature sensors. Waterproof ones are a good idea.
  • Adafruit ADS1115 breakout board. This is an I2C addressable analogue input chip required only because of the IO pin shortage (£14ish)
  • Solar panel approx 2W. I bought mine with the charge controller to ensure they were matched
  • Solar charge controller: I used a CN3065 breakout board because it was cheap and available in England. It also includes USB charging as an option. Adafruit have better options. (£5ish including panel)
  • MCP1825S-3302E/AB low drop out regulator (£5 ish)
  • LiPo battery. Make sure you select one with low voltage cut out. (£10ish)
  • Optional: Raspberry Pi (£30ish)
  • Project box (£5ish)

Code

https://github.com/No-George/Cold_Frame

Video

Supplies

Step 1: Minimising Power Consumption

What to do

  1. Use the ESP32's famed deep sleep mode
  2. Remove the linear regulator on the ESP32-Cam
  3. Turn off all other devices whilst not in use

How to do it

  1. This is implemented in the code. Steps. The battery monitor routine will also schedule more sleeping if the battery is low
  2. The picture shows a board with and without the AS1117 regulator. Simply remove it, it doesnt matter how. I pulled it off with pliers as I dont have a hot air gun.
  3. Follow the schematic so that the sensors are all powered from one of the IO pins.

Why to do it[Please note: This part is boring. There is no need to read it unless really interested]

This project is all about minimising power consumption so that it can be driven by a small battery and solar panel.

My rule of thumb for capturing solar power is that on a miserable day the panel wil collect approximately 1/20th of it's rating for 1/3 of the day.

The charge-discharge efficiency of a cheap lipo and charge controller followed by a linear regulator are unlikely to be better than 50%. That means that a 1 watt panel can only be relied upon for around 8mW. For a battery voltage of 4ish, this works out at 2mA average per watt. Using 2W this gives 4mA average.

The ESP32-Cam uses around 180mA when running normally, there are also periferal components which use power too.

Deep sleep helps a lot. By running code for only a few seconds each hour we can concern ourselves simply with the deep-sleep power consumption.

The ESP32-Cam board can run at 6mA in deep sleep. To improve this the AS1117 regulator can be removed and substituted for a microchip MCP1825S-3302E/AB. This has been selected because it has the lowest quiescent current for a DIP package which I could find at only 120micro amps.

The current consumed by the sensors low enough that it can be powered directly by an IO pin but not so low that it is insignificant.

Step 2: Wiring

Just in case the wiring from the photo cant be deciphered, I have included a schematic.

There are a few things which aren't quite captured.

  • The moisture sensor and dallas sensors are on a connector allowing them to be removed from the box.
  • The micro-sd card has an extension cable attached so that it an be accessed without openning the box
  • The FTDI adapter is plugged into a USB chassis mount
  • The battery is wrapped in kevlar so that it doesnt warm in the sun or present a fire risk
  • The voltage divider uses 1MΩ resistors to minimise the discharge rate
  • The switch has 3 posisions.
    1. Power connected to regulator
    2. Not connected
    3. Power connected to regulator AND GPIO_0 connected to ground

Noteworthy features

GPIO_0 will place the board into programming mode if pulled down. There may be a pin on your FTDI adapter which does this for you but mine did not have this pin.

An additional regulator is bypassing the one originally on the board. This reduces the power consumption by approximately 6x.

Table shows which pins are doing what on the ESP32. The ones highlighted red are involved in bootstrapping so if adapting to your own project this is worth noting.

Many pins are shared with the SD card which can also cause problems In this code I was unable to init the SD card at the same time as the I2C bus. Neither have a de-init command so I reboot the chip.

Step 3: Moisture Sensor Wand

The moisture sensor and one dallas temperature sensor are housed within a wand which is 3d printed. This is not really necessary but is cosmetically nice and helps protect the wiring.

Print the attached parts and assemble as shown. There is an M8 cable gland in the end to tidy it up but it could be glued.

Step 4: Code

*/ Download the arduino board definisions for the ESP32 Cam Set board as esp32 wrover w/huge app https://github.com/No-George/Cold_Frame You only need to edit the first few lines in the code shown here /*

// Replace with your unique IFTTT URL resource const char* server = "maker.ifttt.com"; const char* resource = "place your IFTTT link"; // Replace with your wifi settings const char* ssid = "ssid"; const char* password = "password"; //Mosquitto settings const char* mqtt_server = "mosquitto IP"; //#define mqtt_user "username" //#define mqtt_password "password"

Step 5: IFTTT

IFTTT if this then that is a free service which can be used to do many many things. In this project it is used to record the sensor data to google sheets.

If you dont want this functionality then comment out this line

//makeIFTTTRequest();

If you do want this functionality then create and account @ IFTTT.com.

Create an applet and select the following

This:"Webhooks"

That:"Google Sheets"-->"Add row to spreadsheet"

Settings are in the attached pdf.

To get your uniquie URL click your applet>webhook icon>documentation

Step 6: Mosquitto and Node-RED

Mosquitto is my chosen MQTT broker since it is easy to run on a Raspberry Pi. The screengrab shows a dashboard produced in Node-RED. I have this application running on the same Raspberry Pi.

It can be configured to send notifications and do all sorts of other things based on the received data. I used it predominantly to develop the power consumption whilst the other data is there as a curiosity.

If you dont want to use node-red or mosquitto, simply change the code like so:

Uncomment:

initNTP(); //use if not running mosquitto. This is slower and will result in the first few picutues probably not having a timestamp.

Comment out
//publishMQTT();

//MQTTdateTime();

There are some terrific tutorials on here showing how to set up both mosquitto and node-red on a raspbery pi so I won't duplicate these steps.

Once you are up and running you can import the flow in the next page or from https://github.com/No-George/Cold_Framehttps://github.com/No-George/Cold_Frame/blob/master/flows.json

Step 7: Node Red JSON Flow

[{"id":"e87153c6.da928","type":"tab","label":"Cold Frame","disabled":false,"info":""},{"id":"6fd77b21.48c5e4","type":"ui_gauge","z":"e87153c6.da928","name":"","group":"aa29c57.bdb2038","order":1,"width":"4","height":"4","gtype":"gage","title":"Soil ","label":"Degrees","format":"{{value}}","min":"-10","max":"35","colors":["#804000","#804000","#804000"],"seg1":"","seg2":"","x":350,"y":500,"wires":[]},{"id":"829ac61a.d15ea8","type":"mqtt in","z":"e87153c6.da928","name":"Soil Temp","topic":"Cold_Frame/Soil_Temp","qos":"2","datatype":"auto","broker":"aeb1a0ee.74751","x":100,"y":500,"wires":[["6fd77b21.48c5e4","324b9ea8.35f272"]]},{"id":"632f3168.6778c","type":"ui_gauge","z":"e87153c6.da928","name":"","group":"aa29c57.bdb2038","order":2,"width":"4","height":"4","gtype":"gage","title":"Inside Frame ","label":"degrees","format":"{{value}}","min":"-10","max":"40","colors":["#008000","#008000","#008000"],"seg1":"","seg2":"","x":370,"y":560,"wires":[]},{"id":"ca5e95b8.0382e8","type":"mqtt in","z":"e87153c6.da928","name":"Inside Frame Temp","topic":"Cold_Frame/Frame_Temp","qos":"2","datatype":"auto","broker":"aeb1a0ee.74751","x":130,"y":560,"wires":[["632f3168.6778c","324b9ea8.35f272"]]},{"id":"d191749.c4b5088","type":"ui_gauge","z":"e87153c6.da928","name":"","group":"aa29c57.bdb2038","order":3,"width":"4","height":"4","gtype":"gage","title":"Outside","label":"Degrees","format":"{{value}}","min":"-10","max":"40","colors":["#0000a0","#0000a0","#0000a0"],"seg1":"","seg2":"","x":360,"y":620,"wires":[]},{"id":"14a838d.197b1c7","type":"mqtt in","z":"e87153c6.da928","name":"Outside Temp","topic":"Cold_Frame/Outside_Temp","qos":"2","datatype":"auto","broker":"aeb1a0ee.74751","x":110,"y":620,"wires":[["d191749.c4b5088","324b9ea8.35f272"]]},{"id":"c319d2.192f963","type":"ui_gauge","z":"e87153c6.da928","name":"","group":"b555b5ad.ed4a88","order":1,"width":"4","height":"4","gtype":"gage","title":"Humidity","label":"%","format":"{{value}}","min":"0","max":"100","colors":["#b50000","#2fce17","#2414ed"],"seg1":"","seg2":"","x":300,"y":300,"wires":[]},{"id":"bafc54b4.8b7088","type":"mqtt in","z":"e87153c6.da928","name":"Humidity","topic":"Cold_Frame/Humidity","qos":"2","datatype":"auto","broker":"aeb1a0ee.74751","x":100,"y":300,"wires":[["c319d2.192f963"]]},{"id":"329ca2f.0d0235e","type":"ui_gauge","z":"e87153c6.da928","name":"","group":"b555b5ad.ed4a88","order":2,"width":"4","height":"4","gtype":"gage","title":"Pressure","label":"kPa","format":"{{value}}","min":"92.5","max":"105","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","x":300,"y":360,"wires":[]},{"id":"3badb66c.b80a1a","type":"mqtt in","z":"e87153c6.da928","name":"Pressure","topic":"Cold_Frame/Pressure","qos":"2","datatype":"auto","broker":"aeb1a0ee.74751","x":100,"y":360,"wires":[["329ca2f.0d0235e"]]},{"id":"be3904c2.445438","type":"ui_gauge","z":"e87153c6.da928","name":"","group":"9f29d63c.52cb28","order":1,"width":"4","height":"4","gtype":"gage","title":"Battery","label":"V","format":"{{value}}","min":"0","max":"4.5","colors":["#f00000","#e6e600","#00b500"],"seg1":"3.5","seg2":"3.8","x":360,"y":680,"wires":[]},{"id":"d83ce998.558848","type":"mqtt in","z":"e87153c6.da928","name":"Battery Voltage","topic":"Cold_Frame/Battery_Voltage","qos":"2","datatype":"auto","broker":"aeb1a0ee.74751","x":120,"y":680,"wires":[["be3904c2.445438","58a1c1f3.f68f1"]]},{"id":"a139ce7f.c9775","type":"ui_gauge","z":"e87153c6.da928","name":"","group":"b555b5ad.ed4a88","order":3,"width":"4","height":"3","gtype":"wave","title":"Moisture Reading","label":"%","format":"{{value}}","min":"0","max":"100","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","x":610,"y":200,"wires":[]},{"id":"184a678d.670738","type":"mqtt in","z":"e87153c6.da928","name":"Moisture Reading","topic":"Cold_Frame/Moisture_Reading","qos":"2","datatype":"auto","broker":"aeb1a0ee.74751","x":120,"y":200,"wires":[["bdb6dc1c.47c71","6eb49340.466e8c"]]},{"id":"479d291.4c052d8","type":"mqtt in","z":"e87153c6.da928","name":"Solar Voltage","topic":"Cold_Frame/Solar_Voltage","qos":"2","datatype":"auto","broker":"aeb1a0ee.74751","x":110,"y":740,"wires":[["788454c1.78d3dc","58a1c1f3.f68f1"]]},{"id":"a0fce587.cc2bb8","type":"mqtt out","z":"e87153c6.da928","name":"dateTime","topic":"dateTime","qos":"2","retain":"true","broker":"aeb1a0ee.74751","x":840,"y":720,"wires":[]},{"id":"16a4ecdb.c0ddd3","type":"ui_text","z":"e87153c6.da928","group":"8de08eff.7402e","order":5,"width":0,"height":0,"name":"","label":"Current time","format":"{{msg.payload}}","layout":"row-spread","x":860,"y":820,"wires":[]},{"id":"733f83c1.553e5c","type":"inject","z":"e87153c6.da928","name":"","topic":"","payload":"","payloadType":"date","repeat":"1","crontab":"","once":true,"onceDelay":0.1,"x":570,"y":760,"wires":[["16a4ecdb.c0ddd3","a0fce587.cc2bb8"]]},{"id":"324b9ea8.35f272","type":"ui_chart","z":"e87153c6.da928","name":"","group":"aa29c57.bdb2038","order":4,"width":0,"height":0,"label":"","chartType":"line","legend":"false","xformat":"dd HH:mm","interpolate":"linear","nodata":"","dot":true,"ymin":"0","ymax":"","removeOlder":"7","removeOlderPoints":"","removeOlderUnit":"86400","cutout":0,"useOneColor":false,"useUTC":false,"colors":["#804000","#008000","#0000a0","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"outputs":1,"x":350,"y":440,"wires":[[]]},{"id":"bdb6dc1c.47c71","type":"ui_chart","z":"e87153c6.da928","name":"","group":"b555b5ad.ed4a88","order":4,"width":0,"height":0,"label":"Thirst","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":true,"ymin":"","ymax":"","removeOlder":"7","removeOlderPoints":"","removeOlderUnit":"86400","cutout":0,"useOneColor":false,"useUTC":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"outputs":1,"x":430,"y":80,"wires":[[]]},{"id":"788454c1.78d3dc","type":"ui_gauge","z":"e87153c6.da928","name":"","group":"9f29d63c.52cb28","order":2,"width":"4","height":"4","gtype":"gage","title":"Solar","label":"V","format":"{{value}}","min":"0","max":"6","colors":["#f00000","#e6e600","#00b500"],"seg1":"3.5","seg2":"3.8","x":350,"y":740,"wires":[]},{"id":"6eb49340.466e8c","type":"range","z":"e87153c6.da928","minin":"5500","maxin":"16000","minout":"0","maxout":"100","action":"clamp","round":true,"property":"payload","name":"","x":270,"y":200,"wires":[["8c381f31.8ce41"]]},{"id":"c12a1e54.0cf46","type":"mqtt out","z":"e87153c6.da928","name":"","topic":"Cold_Frame/Mapped_Moisture","qos":"2","retain":"true","broker":"aeb1a0ee.74751","x":650,"y":260,"wires":[]},{"id":"8c381f31.8ce41","type":"function","z":"e87153c6.da928","name":"invert","func":"msg.payload = 100 - msg.payload;\nreturn msg;","outputs":1,"noerr":0,"x":430,"y":200,"wires":[["a139ce7f.c9775","c12a1e54.0cf46"]]},{"id":"58a1c1f3.f68f1","type":"ui_chart","z":"e87153c6.da928","name":"","group":"9f29d63c.52cb28","order":3,"width":0,"height":0,"label":"","chartType":"line","legend":"false","xformat":"dd HH:mm","interpolate":"linear","nodata":"","dot":true,"ymin":"3","ymax":"","removeOlder":"7","removeOlderPoints":"","removeOlderUnit":"604800","cutout":0,"useOneColor":false,"useUTC":false,"colors":["#804000","#ffff00","#0000a0","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"outputs":1,"x":350,"y":800,"wires":[[]]},{"id":"aa29c57.bdb2038","type":"ui_group","z":"","name":"Temperature","tab":"9fe8ce8c.cb014","order":1,"disp":true,"width":"12","collapse":false},{"id":"aeb1a0ee.74751","type":"mqtt-broker","z":"","name":"Mosquitto","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"b555b5ad.ed4a88","type":"ui_group","z":"","name":"Environment","tab":"9fe8ce8c.cb014","order":2,"disp":true,"width":"12","collapse":false},{"id":"9f29d63c.52cb28","type":"ui_group","z":"","name":"Power","tab":"9fe8ce8c.cb014","order":3,"disp":true,"width":"12","collapse":false},{"id":"8de08eff.7402e","type":"ui_group","z":"","name":"Stats","tab":"9dba662d.491c18","order":2,"disp":true,"width":"12","collapse":false},{"id":"9fe8ce8c.cb014","type":"ui_tab","z":"","name":"Cold Frame","icon":"local_florist","order":1,"disabled":false,"hidden":false},{"id":"9dba662d.491c18","type":"ui_tab","z":"","name":"PI","icon":"fa-power-off","order":3,"disabled":false,"hidden":false}]

Step 8: You're Done

Here is a time-lapse of some borage growing over a few weeks.

Backyard Contest

Participated in the
Backyard Contest