Raspberry Pi Gardening: Monitoring a Vegetable Garden using a Raspberry Pi - Part 2: 3D Printing
Introduction
In the last iteration of this project, I walked you through my journey of throwing a Raspberry Pi into my garden beds to monitor sun and water exposure. In this article, we’ll improve the prototype into something that can feasibly used both indoors and outdoors.
Just as the previous article, this here part 2 will go over all the steps I went through and documents some of the learning experiences I’ve had.
Version 1’s Issues
Version 1 was fun - and it worked! But it wasn’t without its problems. Let’s do a quick retrospective as to what all needs to improve here.
Cost
One fairly prohibitive thing was cost - as a prototype, it used a beefy Raspberry Pi 4 (4GB), a machine that retails for a solid $55. Realistically, however, we’d want to build the same box for maybe $30 all in (at consumer prices!), so we can deploy multiple of them inside and out.
This is an easy fix - Raspberry Pi Zero W comes with WiFi (which will be cheaper and more ubiquitous than [PoE] Ethernet [0]) and can be had for $10 (if you can find one for that price). Cheap micro-SD cards retail for $3, and so do cheap micro-usb cables and power bricks, but I assume everyone has multiple piles of cables and adapters anyways. We’ll be using small breadboards, but you can also just solder copper together if you’re down for a fun ride of short circuits. Add about $2 for a solderable breadboard - and continue reading to see why that might be a good idea.
Back to the Zero W
: It’s a magical little stick: 1Ghz, one core, 512MB memory, 40 PIN GPIO headers, camera connector, BLE / Bluetooth 4.1 and 802.11 b/g/n WiFi. For $10. $5 without WiFi. That’s about ~7.7x the CPU capabilities of my first PC, in about 1/1,000 the volume!
It’s fair to say that it’s tiny, about half the size of a spacebar (if that’s a unit of measurement?):
Sure - some ESP32’s might come cheaper - but Raspberries also have the distinct advantage of not being a microcontroller, but rather a fully-fledged computer. And for somebody who isn’t exactly an Embedded Engineer, the learning curve is a lot less steep. The little RasPis also support USB, which is neat!
[0] This here is a fun read that relies on PoE and can use a simpler design because of it.
Power Consumption
Using a Raspberry
vs. an ESP32
does have its disadvantages, though - power consumption being one of them. Assuming we’d want to collect data wireless for 48 hrs:
The previously used Raspberry Pi 4
will consume around 500 - 600mA at idle. On a 5V power supply, we’re looking at ~3W or ~144Wh for 48hrs.
Reminder:
Power (as Watt hour) = Voltage (as Volts) / Current (as Amps)
W = Voltage * Amps * Hours
A Raspberry Pi Zero W
on WiFi should be around 150 - 180 mA on 3.3V, with a voltage regulator on-board to support 5V PSUs - so about 0.55W or 26.64Wh for 48hrs (about 18.5% the power consumption of a Pi 4!).
However, an ESP32-WROOM-32, on the other hand, would range around 100 mA at 2.2 to 3.6V (as little as 10.5Wh for 48hrs) when actively sending data, and barely nothing when idle:
To put it into perspective, a single AA Lithium battery clocks in at about ~3,000mA, albeit at 3.7V. Powerbanks, of course, come with power converters - with Pi Zero W
’s estimated consumption and a minimum runtime of 48hrs, a tiny powerbank at 10,000mAh (10A) and 3.7V (which would be typical for lithium) could power a Pi, in an ideal world without conversion loss and inefficiencies, for about 67hrs (37Wh/0.55Wh). Assuming 50% efficiency, 10Ah would get us to about 1 1/2 days, which isn’t amazing.
Cost is also a prohibitive factor - even cheap(ish) power bank or straight up lithium batteries would almost double the cost of one unit, for ultimately little benefit. The PiSugar project, for instance, clocks in at $39.99 for a 1,200mAh battery, with an estimated runtime of 5-6hrs - which is in line with the calculations above (1.2A*3.7V=4.44Wh
, 4.44/0.55Wh*.5=4.3hrs
, with 50% efficiency).
So, despite this being not ideal, we’ll take the efficiency gain, but forego the battery topic for now.
Sensors & New Parts List
The last project also used a lot of different sensors to figure out which ones work best - this time around, we already know the ones we need.
So, here’s an updated part list:
- Board: Raspberry Pi Zero W - $10
- SD Card: Any cheap, 8-16GB card will do - $3
- Moisture: Any resistive humidity sensor - $5
- Temperature: MCP9808 High Accuracy I2C Temperature Sensor - $4.95
- Light: NOYITO MAX44009 (up to 188k lux) - $4.95 (price increased at time of writing)
- ADC: MCP3008 8-Channel 10bit ADC With SPI Interface - $3.75
Which brings our total from almost $100 for a development board to about $31.60. Add ~$2 for a solderable breadboard and maybe $0.10 for some jumper wires, if you want a more sturdy design.
I’ll call this a win, simply because I’d be able to get all parts (sans the Pi) from Aliexpress for about half the price, like a MCP3008 for $1.50. But even domestically, from places like Adafruit, Microcenter, and Amazon, the total cost per unit seems reasonable.
Size, Enclosure, and Layout
The bigger and more obvious limitation of the previous iteration, however, was size: Due to my genius plan of using a Dremel to drill holes into a massive (albeit flimsy) box from Ikea, the resulting box was both huge and impractical. A classic lose-lose situation, just how I like it.
It also relied on a breadboard, lots of dupont cables, and was generally not very well thought out - everything in it should have fit onto a much smaller footprint.
Improving the layout should be a relatively simple task: Since we know the sensors we need, we can optimize for space. We’ll do that further down.
The enclosure for that, however… that is a different topic. We’ll get to that now.
Introducing: The 3D Printer
I’ve mentioned it last time, I’m using this as an opportunity to buy a 3D printer. I chose the Creality Ender 3 V2, which is probably the most recommended budget 3D printer for PLA and ABS at around $250.
This being my first 3D printer, it was an interesting learning experience to say the least.
You will find the background of all photos changing quite the bit, as we moved this ~19x19" thing around the house a lot - I wound up buying a ~22x22" IKEA Lack table for it, in case you were curious.
Building a 3D Printer
Creality’s own website (!) offers the following advice:
Sure, it’s far from perfect.
But at this lower price, it offers a decent print volume, is easy to assemble and improve, and can produce high-quality prints.
(https://www.creality.com/goods-detail/ender-3-v2-3d-printer)
So, reading up online, it was clear to my that a “standard” Ender 3 v2 won’t cut it - too many reports of people struggling with basic functionality. So, I installed some updates before starting my first print. That wasn’t an overly smart move - I should have started with a test-print first.
Aluminum extruder, 0.4mm Nozzle, and Capricorn PTFE Bowden Tubing
The first number of updates fell under “preventative maintenance”, i.e. things I probably wouldn’t notice until I used the printer a bunch, but it seemed like a good thing to replace, since the printer doesn’t come assembled anyways. I soon learned that that was a mistake.
The first upgrade was an aluminum extruder: A simply sturdier version to move filament into the hot end (the part melting the filament), compared to the plastic default, with a stronger spring to keep better tension during the extruding process. This ensures that filament will always flow evenly. It’s also simply much less likely to break.
What I didn’t realize, however, was that this process might mess up the calibration of the printer, where the length of filament requested and the length of filament extruded are out of sync, causing pooling on the hotbed and misshapen prints:
Thanks to a friend who actually knows stuff about 3D printing (for I am but a humble novice), we were able to follow the steps on this wonderful website to re-calibrate it. This happened after many a failed print, though - even though it wasn’t the only root cause. In any case, heed his advice and bookmark this website - it’ll save you a lot of time.
I also installed updated tubing, nozzles, and connectors the same reasons - don’t believe I’d run into issues any time soon, but those upgrades were easiest to do while everything else was taken apart already.
Auto-Leveling
One of the most important things about 3D printing is leveling - one of the main problems with messed-up prints like the one above - and leveling something manually, especially in a house from 1949 (level floors weren’t invented until 1972, fun fact) was bound to be a pain, if not outright impossible.
So, the Creality BLTouch V3.1 for about $40 is a terrific little invention: Instead of relying on a human to manually move the Z-Axis every on practically inch of the printing bed, it probes the surface for you.
Installing it was relatively straightforward: You replace the regular Z-Limiter’s cable with the BLTouch (which requires you to remove the mainboard cover), route the cable alongside the tubing, and bolt it to the print head.
At this point, it is advised to note down the mainboard version, as we’ll need that for the firmware upgrade in the next step:
Once installed, it looks like this:
The other thing I installed was a set of updated springs, so the bed stays level once it is leveled once.
New Firmware
After those updates were installed, the next journey was to get firmware installed - otherwise, the BLTouch won’t do a thing. The Ender 3 v2 has an interesting process for this - you place a .bin
file onto an otherwise empty SD card and it’ll install it.
I used a pre-compiled Marlin firmware for this task.
If you, however, chose a wrong firmware, the display will just stay black or the machine will beep horribly loud.
Part of my wonders how it validates authenticity, of if it just executes random code. I have that theory that it’s the latter.
OctoPrint
While all these improvements were great, the process of printing anything on an Ender 3 is as follows:
- Find or design a CAD model
- Use a slicer, such as Cura, to turn your CAD into sliced G-code that your printer understands
- Move it onto an SD-card
- Plug the SD-card into the printer
- Print, run into the room with the printer every 10 minutes to check for inevitable failures
However, a wonderful piece of software exists, called Octoprint that can be used to control your printer remotely (or, rather, from the local network) via a Raspberry Pi!
First off, I printed enclosures for a Raspberry Pi (using charming “rainbow filament”, which explains the, uh, interesting color combinations):
And installed it:
And then installed Octoprint using docker-compose
, after telling the DHCP server and the Pi to keep a static IP over WiFi:
|
|
(All you really need to check here is your dev
ices - the container thinks its talking to a serial port, whereas in reality, it’s the first USB device).
And once it was up and running, it was possible to upload G-Code and monitor prints in real-time:
You can also see a print’s individual steps in real-time:
Leveling and Elmer’s Glue
Earlier, I mentioned that leveling is one of the key things that need doing - otherwise, they’ll produce spaghetti:
Fortunately, Octoprint has a plugin we can use to support this.
I’ve used the following GCODE:
|
|
And here’s the result, after manually leveling it before:
This process, however, took me a long time - and for some prints you see on the pictures above, I used Elmer’s glue to increase adhesion to avoid the print from moving. I’m not saying I recommend it - it does, however, make prints stick without supports on less-than-perfectly leveled beds.
Test Prints and Progress
This was the first print:
And here’s one of the later models - you can see the imperfections as I was trying to figure out - but it’s quite a bit better than the mess in the first attempt:
So far, so good!
A New Component Layout
Now that we can print anything from test cubes over anime figurines to enclosures, let’s also re-visit the layout of the initial prototype.
Designing a new Layout
This layout, naturally, wasted a ton of space. Using the same wiring as before, but using a 20-pin breadboard (as I won’t be etching a PCB, so much is for certain) as opposed to a 60-pin one and dropping the cobbler, we’re left with this tiny 9x6.5cm layout:
I will accept that it isn’t super easy to maintain on that form-factor and that splicing the 5V channel might not be super-duper-smart - just don’t overload it. I2C
can have issues with many devices in series (due to resistance on the same bus), but ultimately, I don’t think this will be a problem here. It isn’t super elegant, but it should work.
In any case, the layout is 2-dimensional in this Fritzing drawing - once we design an enclosure for a Pi Zero W
, we can start stacking components and save even more space. We’ll see to that below.
New Components
We’ve also replaced the UV with a new Lux sensor, the tiny NOYITO MAX44009
. This sensor hooks up to I2C as usual (Power, GND, SCL, SDA), which is why we’re re-using the same lanes on the board. It’s also positively tiny, which is nice for a compact design.
Software Updates
The next thing to re-visit is software.
MAX44009
and the Quest for 0x4B
Naturally, we’ll need to integrate the new sensor somehow. The documentation for this thing is available here, but there is no ready-to-use pip3
dependency.
People took the documentation and figured out the conversion math here and here - if you’re interested in doing this from scratch, please take a look at Part 1.
This sensor has one disadvantage, though - every documentation mentions that it uses the I2C address 0x4A
, but in my case, it used 0x4B
, but not consistently:
|
|
And Amazon review said as such:
These have a selectable I2C address 0x4a or 0x4b. But note that the address on the modules I received was NOT set by the manufacturer.
So you’ll need to solder the jumper pads on the board one way or another or the address will not be deterministic and may change on you between uses. (I found out the hard way).
CTRL+F on the official docs yields no results for 0x4B
and the sample code also defaults to 0x4A:
|
|
Isn’t that fun?! (╯°□°)╯︵ ┻━┻
Anyways, I’ve simply created a customized version that worked with the existing code base from the first iteration and my odd address masking:
|
|
Re-Writing the Client
Other than that, I updated the main code a bit to be a bit more flexible, by using a class hierarchy that allows the various sensor implementations from libraries, custom code, SPI etc.
It’s not exactly a marvel of engineering - but it is better than it was before. The full code, as usual, is on GitHub.
|
|
The whole if
/else
switch can of course be avoided, for instance with a plugin model like I wrote here for scarecrow-cam
, another RasPi project. But that’s a bit more effort than I’m willing to spend right now.
Anyways, we can test locally with:
|
|
And update the systemd
service.
Updating the Backend
Of course, the addition of the sensor requires schema updates, which is easy in go
, because go
has structs
and doesn’t hate you:
|
|
The same goes for the SQL
interface/DDL - a fairly standard exercise.
Adding new Features
Another useful feature, apart from collecting data, would be to notify the gardener of any issues. For that, I implemented a simple notification system in go
, i.e. on the server.
The implementation is straightforward - we define constants for thresholds:
|
|
Using thresholds as const
ants is, to be fair, like re-compiling your Kernel for a ulimit
adjustment - but I’m trying to avoid config
files.
An in order not to send notifications every time the sensor triggers, we also implement a timer, which for the sake of simplicity uses a global map
and a mutex
:
|
|
Sending the notifications happens via smtp
, and similar to the previous iteration, we keep secrets in environment variables, rather than a config file - for simplicity’s sake, once again:
|
|
And the sending part can be done natively in go
:
|
|
Which will send a message like this:
Sensor unit_test encountered the following threshold failure at 2021-07-01T10:00:00: Temperature: 4 (Thresholds: Min: 5 / Max: 40) Moisture: 1.5 (Thresholds: Min: 2.2 / Max: N/A)
Useful! As we’ll see below, 40C is pretty low, but that can always be adjusted.
Re-Deploying the Pi Zero W
Now that we have all software up-to-date, it’s time to set up a new Raspberry Pi Zero W
.
Physical Assembly
This one’s simple: I slapped an aluminum heatsink on it (potentially pointless, but I do have those lying around - I have no idea how hot it’ll get outside) and soldered the I2C headers onto some pins.
Part of the reason the Pi Zero
is so cheap is the fact that you need to solder the pins yourself - which I did “upside down” (as if to put the Pi
onto a breadboard) in order to save space for the final design. The idea here is to slap the breadboard onto the back of the board, without obstructing the APU and hence, without creating a thermal nightmare for the little Pi.
Of course, one could solder the cables on the Pi directly, but I wanted to leave room for potential adjustments down the road. As you’ll see in a bit, that was a wise choice.
Software Deployment
Now, of course, I was thinking about writing an actual deployment pipeline, or even to build Docker images - but when faced with a conflict between “fishing on the lake and doing nothing” and “configuring CI/CD from scratch”, the former (fortunately) wins.
First, use Raspi Imager to install a Raspbian
OS. This should mount boot
and root
onto your PC.
Now, if you don’t have a monitor for the Pi
, we can enable ssh
headlessly and then chroot
the entire SD card.
chroot
, in case you’re not familiar, is like docker
, just not as hipster. :)
First, enable ssh by doing a touch ssh
onto the mount point of boot
.
Then, to enable WiFi, copy your existing /etc/wpa_supplicant/wpa_supplicant.conf
onto the same partition. If you don’t have one or use macOS/Windows customize this:
|
|
Then, chroot
the main partition:
|
|
And run this setup script:
|
|
And run:
|
|
raspi-config
, however, must be run on an actual device, as it loads Kernel modules.You might also want to customize the logrotate
config in /etc/logrotate.d
:
|
|
We only need to run this once and dd
the entire SD card to another Pi
, or run it on each Pi
- it doesn’t really make a difference.
If you want to dd
, I suggest you do that after booting the Pi
and running sudo raspi-config
:
|
|
Having an image is useful, so you might want to do this once it’s working.
A Quick Test
At this point, it would be advised to test the entire setup, for instance looking at the load:
And maybe check out Grafana, as the service will start running once you enable I2C
and SPI
via raspi-config
.
Building a new Enclosure
Let’s get to building a new case!
Originally, I wanted to “remix” (fork) an existing Pi Zero enclosure, like this one, but quickly learned that my CAD skills are way too fresh to work on actually functional models. So I started from scratch.
Test Assembly
Before anything else, we must assemble the whole thing without a case to get a feel for how everything will fit together:
Take Measurements
Next, I used some decently accurate calipers to measure all dimensions and drew some rough ideas on paper.
I will spare you from seeing the rough sketches.
Foray into CAD
There are a lot of options available when it comes to CAD - but I chose Autodesk’s free Tinkercad, because it’s pretty simple. Fusion 360 does have a free version for personal use, but it doesn’t run on Linux.
While I can’t stand browser-based tools (eLeCtrOn wEb aPpS), they are sometimes easier than trying to force other software to play nice with Linux. It is what it is, as they say.
Anyways, Tinkercad is aimed at hobbyists and students and comes with a colorful tutorial, which even I understood.
The Design (v.1.0)
My design was very, very simple - but that might be because it was my first CAD design I’ve ever built - I am usually the type to measure once, cut twice.
Fun Fact: There’s a little piece of 2x4 in my shed with measurements written on it in sharpie. They do not match the 2x4’s dimensions at all. That’s all you should know - but, it usually works out. I did build all the raised beds on this property, after all!
Well, turns out, CAD needs more prevision than a circular saw. The idea behind the design isn’t much different to other, commercial cases: 4 Pins stick together to hold the case together. Small cutouts support the exact placement of cables I need - just less cutouts than commercial cases. Also, the case has a lot more wasted space than it needs to, to support dupont cables without the need to solder things directly onto the headers.
Once I had something resembling a model based on these ideas and measurements, I exported the .stl
file, loaded it into Cura and got to printing.
Naturally, I messed up the print settings and over-estimated the capabilities of the printer (which, ultimately, are dependent on the slicer settings) - the little support beams turned to spaghetti.
I also realized that the tolerances that I measured were a little too detailed for the print settings I set up in Cura, and I messed up other measurements altogether - in other words, the design wasn’t very good.
Design (v2.0)
The second design followed a different philosophy: Larger tolerances that can be filled in later.
It also avoided flimsy support beams and relied on a top piece that was ever so slightly smaller than the bottom. It also moved the cutout for the moisture sensor to the top, giving the fit more play.
Last but not least, it added 2 support pyramids for the Pi itself, so it could sit safely on the bottom of the enclosure.
The Waterproofing Issue
One thing was unfortunately not solved by this design: Water (or weather) proofing.
Now, while a purpose-built case will undoubtedly be a better fit than any commercial case (if you’d be able to find that that fits all the components), designing and printing something that takes seals and has very little tolerances is not within my current CAD skillset.
There are alternatives, however - namely nail polish and electrical tape, which I already used liberally last time. Nail polish is not electrically conductive, creates a good seal, but isn’t particularly heat safe - supposedly until about 120C (248F). Given that this will only be applied to the 2 external sensors, I am not terribly worried about that part - I don’t think my peppers are that heat-safe.
While I don’t plan to douse the entire Pi in nail polish, we can somewhat weather-proof the sensors, which *have to be outside the case for accurate measurements. The connection between the sensors and the case are precise enough to be sealed with, you guessed it!, electrical tape.
There have been a lot of smart experiments conducted, regarding nail polish as a conformal coating alternative - from what I can tell, it works, but since there is no standard nail polish formula (as I found out at my local Kroger), some additives might mess with the plastic on the PCB.
Of course, if you foresee never having to access the Pi again, one could douse the entire thing in resin or silicone as well - but we’ll stick to nail polish for now.
Assembly
With the 2nd design printed, assembly was relatively straightforward: Just throw everything in, accept some design flaws for now and use more electrical tape for keeping it in place, and place the sensors into the top cutouts.
Naturally, everything being on a breadboard caused an issue everybody who built a desktop PC before knows to well - cable management. It was tight with standard-length cables, to say the least:
Options here include crimping some tiny cables myself or buying smaller cables. Or, of course, the school of redneck engineering always helps: De-sleeve a cable and tin the end with a soldering iron until it fits into the breadboard’s slot (believe it or not, this works). A roll of 24AWG wiring would work too.
While I’m not trying to tell you how to live your life, I may be able to offer a word of advice: It is not worth spending an hour trying to frankenstein cables together and inhaling a lot of bad fumes while doing so, just to save $10 for a handful of wires. Or so I heard. Version 3.0 down below heeds some of that advice.
One related issue were the moisture sensors - I didn’t account for long dupont end pieces in that spot. So I did what any sane person would do and just de-sleeved some cables and soldered them onto the PC directly, rather than doing another 4+hr print for ~5mm.
Beta Testing Outdoors
With all that out of the way and the new backend service deployed (stop the systemd
service, re-compile from git
, copy the new binary over, and re-start the service - adjust the .env.sh
file if you want emails), we are ready to test!
Finding a spot
For this test, I moved the little box onto the deck first to keep watch over some of our pepper plants, namely a tremendously happy Capsicum Chinense “Habanero” (also just known as “Habanero Pepper” if you’re a normal human being).
The only issue left is still the one of power delivery - I don’t own an waterproof USB power brick.
(Ignore the tape - see the cable comment above - the next iteration won’t need it)
In any case, I threw the box out there at about noon before heading off to buy pesticides to try and save about 30 cauliflower plants from pests, as well 10 cu-ft of mulch, because obviously, the garden-ride never stops.
Before leaving though, a quick peak at the database shows that the little box starts collecting data as soon as it gets power, thanks to the systemd
service (I’d call that “plug and play”).
And after about 2 hours, we can find good data for Light and Temp:
We can see some seriously impressive peaks here - over 60C (140F) in direct sunlight (much higher than the 40C peak we configured in the backend!). This isn’t overly surprising - cars parked in the sun can reach similar temperatures (in hindsight, that would explain why my truck seemingly tries to boil my sunglasses practically every day).
However, we can see that the ADC didn’t collect data:
Which, turns out, was an invalid pin wiring on the MCP3008
- so we get voltage fluctuations reading as data. Please see Part 1 for a deep dive on that - the summary is, an ADC will always report values, even if they’re not really based on anything.
Fine-Tuning and Troubleshooting
After fixing that mistake, I also printed the top case another 10mm taller, although that didn’t solve all problems - the case was still a very tight fit and some printing imperfections made fitting both parts together not easier.
It also happened way too often that some of the dupont cables fell out during assembly - something you’d only realize once the whole thing is sending data.
I2C and SPI are also especially charming in that regard, because once there is current on the data or sync line, they show up as connected, despite there maybe being no power on the sensor (because the cable decided to fall out). The sheer size of the 10-20cm cables got in the way too often.
This won’t do.
Version 3.0 and Deployment
This would be the final version for the purpose of this article.
Assembly
The only way I could use to optimize this was to actually solder everything together with regular standard 24 AWG wire directly, as well as using some 50mm dupont cables - reducing the wire length and density around all connections that are not on the breadboard itself (as it’s easy to use jumper wires here).
More on that later.
A Final Test Indoors
Finally, the little box was ready for its deployment in the (literal) field. Before doing that, though, I left it run over night hooked up to a low-light plant in the kitchen, to make sure everything worked properly for the last time:
Which I’m sure glad I did, because if you short SDA
and SCL
, this is what i2detect
does:
|
|
Oh well. ヽ(´ー` )┌
Indoors, especially at night, the only somewhat relevant metrics are temperature - 25C/77F seems reasonable with the AC off at night - and soil moisture, which won’t change that quickly. As we remember from the last article, 1.5V is “damp soil”. It works!
Lumen is constantly at zero, however - please see below for an attempt at explaining that.
Outdoor Deployment & Data Collection
The next morning around 8:30am, I finally deployed the little green box inbetween my carrots and cucumbers:
Godspeed, little one!
Data Analysis & Reminders
And what a day it had! I turned off the RasPi at around 10:30pm, after a gorgeous evening with many a magical firefly:
So let’s take a look at all the metrics throughout the day!
Lumen/Light
This one is really interesting - you can see the peak at about 900 Lux.
Now, looking at Wiki, 900 lux is roughly an “Overcast day”.
The whole scale is logarithmic, so looking at values <= 0 is a bit of a challenge with Grafana - we can, however, find those values on the database. However, looking at the sensor’s spec sheet, I don’t think values <= 0 should be regarded as valid (as the python
program on the Pi
is running with fairly standard settings).
Also -
The illuminance provided by a light source on a surface perpendicular to the direction to the source is a measure of the strength of that source as perceived from that location.
For instance, a star of apparent magnitude 0 provides 2.08 microlux (μlx) at the Earth’s surface.
A barely perceptible magnitude 6 star provides 8 nanolux (nlx). The unobscured Sun provides an illumination of up to 100 kilolux (klx) on the Earth’s surface, the exact value depending on time of year and atmospheric conditions.
This direct normal illuminance is related to the solar illuminance constant Esc, equal to 128000 lux (see Sunlight and Solar constant).
So the angle - that being parallel to the ground - might have played quite a big role. As any measurement of a I2C sensor is relative by nature, let’s take a look at…
Temperature
… the temperature and see if we can correlate the two to compensate for less-than-ideal calibrations. The iOS weather app said 84-86F during the day (29-30C), which is a pretty average summer day around here.
Looking at the sensor’s metric, we’ll find peaks of up to 50C (122F), which correlate to the peaks in lumen, but are not nearly as strong as they were on the deck (which is, if you recall from part 1, right above the observed raised bed):
So we can reasonably conclude: The carrots, cucumbers, and bell peppers under observation do not get 6 hours of full sunlight a day (the common metric for “full sun”), but closer to ~3hrs, which would qualify as “part sun”. All the hot peppers, however, get to deal with 60C+ and ~1.5k lumen - which probably explains why they’re growing at the rate they are, mere feet away from the other plants.
Moisture
This one is rather boring - while I did water the beds at around 5:30pm, given the sheer volume of top soil (they are raised beds, after all), a couple of gallons across ~50sqft probably didn’t make a difference:
Unless you water the specific spot where the prongs are, the measurement won’t change too much, unless the entire bed is dried out, at which point you probably shouldn’t be looking at Grafana, but be out there with a watering can or a hose in your hand.
They do work well on small pots, however - in raised beds, maybe a different method might be in order.
Criticism and next Steps
Let’s to another retrospective after all those improvements - or at least, something of the sort.
The new enclosure turned out to be a bit of a Frankenstein - I do have some solderable mini breadboards on the way, but at the time of writing, I did not - so it’s a mix of soldered cables, semi-fixed connections, and electrical tape. Connections to get lose and cause issues, and it’s hard to figure out why, as a single strand of copper can short it. The i2c
lanes especially are loose all the time.
But the box does finally close and due to the lack of precision (0.2/0.4mm print with PLA @ 210C), sticks together really, really tight (which is good!). It is impossible to tell whether it’s on, though - a status LED would be a good addition.
I also only have one MCP9808
here, so short of de-soldering the pins or soldering wires onto them, I had to use more DuPont cables here. It does work fairly well though, as they keep the sensor in place without a special enclosure.
Besides the mix of cables, the (new) Pi also flops around a bit, needing to be held in place with tape, as my little pyramid-spacers only apply pressure from the bottom, and my precision measuring, designing, and printing skills leave too much to be desired to do anything complicated. Folks with a lot more experience under their belt have built some amazing cases, however - so there’s something to strive towards.
All things considered, it’s far from perfect, but still pretty a-OK, considering my starting position. But like so many things, one can always optimize away further and further.
In this case (heh), I’ll probably try and work on a version 4.0, but mostly for my own enjoyment. In terms of functionality, it’s already there: It fits together, it works, it’s small at 75.8x54.7x57.5mm, and with a bit of sealant around the sensor spots, I’m pretty sure its decently weather-proof.
When it comes to software, I actually have nothing to complain about (apart from code quality, which wasn’t the focus of this project). The base image on the SD card we built earlier works like a charm (I tested it by using a fresh Pi for the soldered version), and the Pi starts the service on boot, doesn’t run hot, therefore doesn’t use a ton of resources, and just does what it’s told.
So, in summary, an eventual version 4.0 should -
- Have a little status LED
- Don’t rely on DuPont connectors, anywhere
- Use soldered connections and no breadboards
- Keep the
Pi
safely in place - Maybe provide more purpose-built enclosures for the sensors themselves
- And be a lot more sturdy overall
Conclusion
Well, I must say, I enjoyed this project quite a bit, and probably more than previous ones. Granted (and I’ve said it before), I wouldn’t exactly describe it as necessary - but I’d also wager that growing that many vegetables and then turning them into pickles (because 2 people can’t eat that much) or lacto-fermenting peppers into hot sauce (for the same reason), or smoking and curing my own bacon (for the reasons of store-bought bacon being rather lackluster) is necessary, especially if you have a grocery store 10 minutes away from the house.
However, if we ignore the time and money spent on it, the resulting green box is actually pretty useful: It does take a lof of guesswork out of the gardening work. Sure, it doesn’t solve many of the other problems, like the poor Sugar Snap Peas that succumbed to a fungus - but it does supply interesting data.
Take a look at those guys, for instance:
Daucus carota should have matured, i.e. be around 5" long and 1 1/2" across, 10-20 days before this picture was taken. Carrots enjoy full sun - and where they’re sowed, presumably, they won’t get full sun. With the power of technology, I probably won’t plant them down there again, because I now know, that they don’t get the ~6hrs of full sun they need.
On a more broader level, however, this was also an amazing learning experience throughout. If you spend your day job as a Software Engineer (or anything vaguely related), be it Junior or Principal, you might be in the same position I found myself in: You have no idea how electronics, computer aided design, soldering, middle school physics, I2C/SPI, or any of the above really work. It’s simply not part of the daily job, albeit technically pretty closely related to that.
However, as the last few sections of this article demonstrate, the whole process is also very (and I hate myself for using the word) agile. The product is never finished, but at a certain point (in my case, near the end of my staycation), an MVP must be delivered - even though I have a lot to complain about (i.e., a lot to improve). Having this particular mindset is a core attribute of a good engineer, at least in my opinion.
You will probably notice this iterative approach while reading the article, as I wrote sections shortly after I worked on the thing, as opposed to supplying a summary at the end - so you can follow this journey along, if you are so inclined.
Going through a project like this, meaning starting from scratch and figuring things out as they come along, all the way to integrating it with known technologies (from a Data Engineering perspective, specifically go
, SQL
, python
) is just… neat. It’s a fun way of using existing skills, enhancing them, and learning a lot of completely new things along the way, and much more so than “just” a software project (unless it’s TempleOS
, maybe).
In any case - I hope you learned something as well or, at the very least, found this journey as entertaining to read as I found building it.
And if you want to build one yourself: All code is available on GitHub. You can also find all CAD files there.
All development and benchmarking was done under GNU/Linux [PopOS! 20.10 on Kernel 5.11] with 12 Intel i7-9750H vCores @ 4.5Ghz and 16GB RAM on a 2019 System76 Gazelle Laptop, as well as a Raspberry Pi Zero W, using bigiron.local as endpoint