The plant asks water

By on January 14, 2020
Pin It

 

A flower pot with a technological flowerpot dish that, when a person comes near, produces a colour-changing, rotating light which varies based on the humidity of the ground and therefore on the plant’s need to be watered.

 

How many things can we do with Arduino? Since it first appeared on magazines and on the web, one would say basically everything, since every day, thanks to the makers’ fervent activity, the board puts on some new clothes and plays more and more original roles. Sometimes, even we are part of the makers’ cauldron since we have made an ally out of Arduino, but also turned it into a seed, a matrix on which to grow and develop new prototyping boards such as the performing and indispensable Fishino boards, but also the Electronic Business Card proposed in issue 214, which is the starting point for the project described in these pages. It is a special flowerpot with flowerpot dish, everything 3D-printed in clear PLA (which is useful to let light pass through it) however not a traditional one because the flowerpot dish is “intelligent” and, thanks to a humidity sensor on a breakout board, it checks how moist the soil in the flowerpot is and, whenever it senses a person getting near, it lights the Neopixel LED ring on to generate a rotating light which hue depends on how much the plant needs water. To be more specific, the light is red when the soil is dry, alternating between red and green when it’s somewhat moist, green when the humidity level is optimal, blue-green if there’s much water and blue when there is too much water (blue is, of course, the colour we commonly associate with water).

We can achieve all this using an Arduino board as a brain, although not any board but the slimmest board there is, which is the business card hardware, which basically is an Arduino Leonardo without a header and equipped with five keys, along with a USB connection, useful to power it or provide power to the remainder of the electronics involved.

 

Arduino Business Card: what it this about

The circuit we’re talking about is an Arduino Leonardo board with an Arduino compatible format and side connectors (it can, therefore, host the strip connectors to support the shields) plus the wall for the ICSP, although it lacks the Vin power section, therefore it receives 5 V (so there is no Vin on the headers); you can see it in Fig. 1; The 3.3 V needed for the logics of the possible shields are brought on the side terminal 3V3, come from the 5 V of the USB via a voltage regulator on the board side.

The heart of the circuit is the 32u4 Atmel microcontroller, the same of the Arduino Leonardo, which has an internally device-type USB interface; this micro is powered by the 5 V from the USB and internally extracts 3 V for its logics. The in-circuit programming lines are brought on the standard ICSP connector of Arduino boards (2 files from 3 terminals, with a 2.54 mm pitch). As usual, the reset line (RST) is used to start the sketch upload through the bootloader and, in the diagram, is connected to the unfailing pull-up resistor and to the grounding key when we need to manually reset the microcontroller (the automatic reset is handled by the PC through the USB connection).

 

Fig. 1

 

The other five keys, connected to lines PD7, PC6, PD4, PD0 and PD1 (P1, P2, P3, P4, P5 respectively) allow us, when pressed, to activate the functions assigned to them by the sketch, which you can customize as you prefer. The two LEDs found on the circuit are managed by the microcontroller to signal the starting of the sketch, the uploading and activity on the USB; in the last case, LD2 is the TX LED and LD1 is the RX LED of Arduino. Furthermore, LD1 (red) blinks whenever, after it’s been connected and recognized by the PC, the board launches the sketch and it is ready to use. LD2 (yellow), on the other hand, blinks every time you press one of the P1÷P5 keys to access the related functions. The micro’s clock comes from the internal oscillator, which is based on quartz to get the precision needed.

In the project, the site the business card Arduino, we make use of:

  • A 60 RGB LED Neopixel LED ring controlled by Arduino through the dedicated communication bus;
  • A miniaturized PIR sensor with digital outputs dedicated to detecting people and notify our Arduino board with a logical level;
  • A sensor (hygrometer) on a breakout board equipped with fork probe to detect the soil’s humidity through the soil’s electric resistance according to it being dry, wet or very wet, therefore basically taking advantage of water electric conductivity, which is electrically conductive since it contains salts in a solution.

 

Soil hygrometer

The humidity sensor is a breakout board with both step and analogue outputs which, when interfaced with Arduino or another microcontroller, allows to detect the humidity percentage of the soil, for instance, in order to control an automated watering device; in our case, it is used to influence the LED Neopixel’s activation.

The assembly is actually composed of a PCB probe and breakout board based on the LM393 integrated (Fig. 2) which allows detecting the humidity percentage of the soil; when it is below a set threshold value, the DO output will show a high logic level, whilst the DO will output a low logic level whenever the percentage goes over the threshold value.

The circuit is basically composed of a voltage comparator (one of the two found on the LM393 integrated) and allows to carry out two different functions when the same event is detected; the event is the lowering of the resistance between pins + and – (i.e. A0 and GND), which basically corresponds to the fork electrode sensor touching the water contained in the soil when the water is enough to make the two electrodes of the sensor touch together. The comparator works in noninverting mode since it gets the reference voltage on the inverting input (pin 6) and the voltage to compare on the noninverting one; besides, it has no feedback, therefore no hysteresis, so the output switch from high-voltage to low-voltage takes place for the same voltage on the noninverting input which determines the passage from low-level to high-level.

 

Fig. 2

 

Since the reference voltage applied to pin 6 (inverting input of the comparator) comes from a trimmer mounted as a potentiometer, we can vary the reference as we please, so from 0 V up to the power voltage, therefore playing on the circuit sensibility to the maximum extent allowed.

The comparator output can run to its maximum potential although, when at low level, it doesn’t exactly go to 0 V (which is peculiar of rail-to-rail operational amplifiers) but it stays at a few hundreds of millivolts. The output is also an open-collector one, so it requires a pull-up resistor to reach the high level, which is integrated in the circuit in this specific case. However, in our case, the digital (step) output relating to the DO terminal is not used, since with Arduino we are going to read the A0, which is basically related to the terminals of the probe stuck into the flowerpot’s soil. The characteristics of our hygrometer are the following:

 

  • adjustable sensitivity via a trimmer;
  • power voltage: 3.3 V – 5 V;
  • digital and analogue outputs;
  • module dimensions: 30 x 60 mm;

The module’s pin layout is the following:

1) VCC: from 3,3 V to 5V

2) GND

3) DO: digital output (0 and 1)

4) AO: analogue output.

 

Please note that for the digital output, connected to the comparator, we can adapt the notification to the type of soil and plant we want to monitor, through the trimmer, remembering that more we put the slider next to the ground limit, the more humid the sole has to be in order to light the LED and vice versa (the LED turns off right before the soil gets on the drier side). However, we won’t be using that function in our application.

 

Movement sensor

We can now move on to the passive infrared sensor (miniature PIR module, code 2846-MINIPIRMOD) that you can see in Fig. 3 which combines a miniature PIR to a control electronics with output to be interfaced with the microcontroller, such as Arduino.

 

Fig. 3

 

The specifics of our passive infrared radar are:

  • power voltage (3.3 V – 15 V;
  • standby absorption: <50 µA;
  • output: 3.3 V high-level/0 V low-level;
  • detection distance: 3 – 5 m;
  • detection angle: circa 110° within 4 m;
  • dimensions: 28 x 13 mm (length x diameter);
  • working temperature: -20°C – +40°C

 

as for the sensor’s PCB pin layout, terminal 1 is the positive voltage (Vcc), 2 is the output, while the ground is on 3; basically, the power applies to the ends. The PIR also has a 10-second activation delay since it is first powered on.

 

Neopixel RING

Now we can move on to the visual element emitting the rotating colourful light, composed of a Neopixel LED ring with 60 RGB LEDs, which can be controlled individually, each of which is able to display 256 shades of their colour, thus determining a total of 60,777,216 colours. The data channel for the communication is a One-Wire serial and can be controlled by a microcontroller such as Arduino, PIC, mbed etc. You can set the refresh frequency as you prefer, in order to make some light effects almost unnoticeable. More rings can be connected in cascade to create various effects. For managing our ring, our business card Arduino is based on the dedicated NeoPixel library. A peculiarity of the Neopixel LEDs is that they can be connected in cascade so that the data line passes from one LED to the next one, however, the price to pay is that, after a certain number of LEDs, the managing speed decreases dramatically, therefore if you need to create matrixes to display quick graphics, you have to employ many lines with a few LEDs each. Neopixel is basically a solution that entails the integration of a driver and the related RGB LED in an SMD case, therefore allowing to directly control each LED. The power for the Neopixel LEDs is 5 V; the communication speed tops at 800 Kbps. The control protocol on the Neopixel system calls for 3-byte packets to be sent in a 24-bit string, each of which contains the lighting status of each base colour (first the eight beat of the green, then the red bits and finally the green bits).

 

The technical features of the Neopixel ring are shown below:

  • LED number: 60;
  • LED type: 5050;
  • chip: WS2812B;
  • power: 5 Vcc;
  • external diameter: 158 mm;
  • thickness: 3 mm.

 

How it works

With that said, let’s see how our circuit works: if we connect our fork sensor, composed of a printed circuit of such a shape that it has two engraved electrodes coming almost up to the prongs, which we are then going to stick into the soil, between terminals + and – (i.e. A0 and GND), the soil’s humidity will determine a certain resistance between the aforementioned terminals, which will create a voltage divider with the internal resistance of the breakout board. The divider ratio will determine the voltage applied to the comparator’s input, therefore, reference voltage from the trimmer being equal, the moister the soil is, the lower the voltage at which the comparator’s output to will switch will be. The latter is at low level (therefore lighting on the LD1 LED) when the soil is very wet and the resulting resistance is such that they keep the voltage on pin 5 of the U1b at a lower level than the value applied to pin 6 by the trimmer; DO terminal is under the same conditions.

 


On the other hand, when the soil starts to dry out, the water percentage sensibly drops and voltage between A0 and GND increases, until it goes over the reference voltage of the comparator, therefore making the output switching from low-level to high-level; now the LED turns off, to indicate that we have to add water.

 

The Firmware

Let’s now see how the system works, which is very simple, since Arduino is in control of everything: the firmware runs on a loop waiting for the digital I/O 2 line to detect the logic level provided by the mini PIR when it detects a person getting closer; in this case, everything activates and the Arduino microcontroller reads the voltage found on the A5 analogue input, dedicated to the humidity sensor, which is directly proportional to the electric resistance detected between the fork sensor contacts that are stuck into the soil and therefore inversely proportional to the quantity of water found in the soil itself.

Listing 1

#include <Adafruit_NeoPixel.h>
#define PIXEL_PIN 9 // Digital IO pin connected to the NeoPixels.
#define HUM_PIN A5
#define PIR_PIN 2
#define PIXEL_COUNT 60
// Parameter 1 = number of pixels in strip, neopixel stick has 8
// Parameter 2 = pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
// NEO_RGB Pixels are wired for RGB bitstream
// NEO_GRB Pixels are wired for GRB bitstream, correct for neopixel stick
// NEO_KHZ400 400 KHz bitstream (e.g. FLORA pixels)
// NEO_KHZ800 800 KHz bitstream (e.g. High Density LED strip), correct for neopixel stick
Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800);
bool oldState = HIGH;
int showType = 8;
int hum = 1;
void setup() {
pinMode(PIR_PIN, INPUT);
strip.begin();
strip.show(); // Initialize all pixels to ‘off’
//Initialize serial and wait for port to open:
Serial.begin(9600);
delay (2000);
// prints title with ending line break
Serial.println(“RGB vase by Boris”);
}
void loop() {
int humRAW=analogRead(HUM_PIN);
hum=map(humRAW,390,1000, 1,5);
Serial.print(“ValueRAW= “);Serial.print(humRAW);Serial.print(“ Value= “);Serial.println(hum);
int pirvalue=digitalRead(PIR_PIN);
Serial.print(“PIR= “);Serial.println(pirvalue);
if (pirvalue==1){
rainbowCycle(5);
}
else
{
colorWipe(strip.Color(0, 0, 0), 50);
}
}
// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
for(uint16_t i=0; i<strip.numPixels(); i++) {
strip.setPixelColor(i, c);
strip.show();
delay(wait);
}
}
// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle(uint8_t wait) {
uint16_t i, j;
for(j=0; j<256*50; j++) { // 50 cycles of all colors on wheel
for(i=0; i< strip.numPixels(); i++) {
switch(hum){
//case 0: strip.setPixelColor(i, Wheel0(((i * 256 / strip.numPixels()) + j) & 255));
// break;
case 1: strip.setPixelColor(i, Wheel1(((i * 256 / strip.numPixels()) + j) & 255));
break;
case 2: strip.setPixelColor(i, Wheel2(((i * 256 / strip.numPixels()) + j) & 255));
break;
case 3: strip.setPixelColor(i, Wheel3(((i * 256 / strip.numPixels()) + j) & 255));
break;
case 4: strip.setPixelColor(i, Wheel4(((i * 256 / strip.numPixels()) + j) & 255));
break;
case 5: strip.setPixelColor(i, Wheel5(((i * 256 / strip.numPixels()) + j) & 255));
break;
}
}
strip.show();
delay(wait);
}
}
// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
WheelPos = 255 - WheelPos;
if(WheelPos < 85) {
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
}
if(WheelPos < 170) {
WheelPos -= 85;
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
WheelPos -= 170;
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel1(byte WheelPos) {
WheelPos = 255 - WheelPos;
if(WheelPos < 85) {
return strip.Color(0, 0, WheelPos * 3);
}
if(WheelPos < 170) {
WheelPos -= 85;
return strip.Color(0, 0, WheelPos * 3);
}
WheelPos -= 170;
return strip.Color(0, 0, WheelPos * 3);
}
// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
/*uint32_t Wheel1(byte WheelPos) {
WheelPos = 255 - WheelPos;
if(WheelPos < 85) {
return strip.Color(0, WheelPos * 3, WheelPos * 3);
}
if(WheelPos < 170) {
WheelPos -= 85;
return strip.Color(0, WheelPos * 3, WheelPos * 3);
}
WheelPos -= 170;
return strip.Color(0, WheelPos * 3, WheelPos * 3);
}*/
uint32_t Wheel2(byte WheelPos) {
//WheelPos = 255 - WheelPos;
if(WheelPos < 85) {
return strip.Color(0, 255 - WheelPos * 3, WheelPos * 3);
}
if(WheelPos < 170) {
WheelPos -= 85;
return strip.Color(0, 255 - WheelPos * 3, WheelPos * 3);
}
WheelPos -= 170;
return strip.Color(0, 255 - WheelPos * 3, WheelPos * 3);
}
uint32_t Wheel3(byte WheelPos) {
//WheelPos = 255 - WheelPos;
if(WheelPos < 85) {
return strip.Color(0, 255 - WheelPos * 3, 0);
}
if(WheelPos < 170) {
WheelPos -= 85;
return strip.Color(0, 255 - WheelPos * 3, 0);
}
WheelPos -= 170;
return strip.Color(0, 255 - WheelPos * 3, 0);
}
uint32_t Wheel4(byte WheelPos) {
//WheelPos = 255 - WheelPos;
if(WheelPos < 85) {
return strip.Color(255 - WheelPos * 3, WheelPos * 3, 0);
}
if(WheelPos < 170) {
WheelPos -= 85;
return strip.Color(255 - WheelPos * 3, WheelPos * 3, 0);
}
WheelPos -= 170;
return strip.Color(255 - WheelPos * 3, WheelPos * 3, 0);
}
uint32_t Wheel5(byte WheelPos) {
//WheelPos = 255 - WheelPos;
if(WheelPos < 85) {
return strip.Color(255 - WheelPos * 3, 0, 0);
}
if(WheelPos < 170) {
WheelPos -= 85;
return strip.Color(255 - WheelPos * 3, 0, 0);
}
WheelPos -= 170;
return strip.Color(255 - WheelPos * 3, 0, 0);
}

 

The value is compared with the thresholds set by firmware and, based on the outcome of the comparison, the Neopixel LEDs are commanded to light on sequentially, in order to obtain the rotating light, since they are diodes mounted on a 60 RGB LED ring; the colour effect depends on the outcome of the comparison, that is the ratio between the humidity level provided by the sensor and the thresholds set in the sketch. To be specific, if the voltage corresponds to high humidity (low resistance) the light emitted by the Neopixel LEDs is blue, while if the value is equal to the intermediate humidity threshold (medium resistance) a green light is displayed; finally, if the voltage corresponds to low humidity (almost dry or dry soil) a red light will be displayed, which we must read as a warning signal launched by our “thirsty” plant.


There are actually some intermediate colours that can be obtained by turning four coloured segments in the LED coloured circle, therefore we have the following combinations:

  • dry soil = rotating circle with red light;
  • barely dry soil = rotating circle with alternating red and green light;
  • soil with optimal humidity = rotating circle with green light only;
  • soil with more than optimal humidity = rotating circle divided into green and blue light;
  • soil too wet = rotating circle with blue light only.

 

Let’s rewrite the sketch, which you can find in its entirety in list 1; here, you can see that first, we include the library managing the Neopixel LEDs and implementing the related serial communication protocol. Then, we move on to defining the pins used on Arduino, which are:

#define PIXEL_PIN    9  

  

to set the digital I/O pin 9 as the data channel to send commands to the Neopixel LED ring, on line DI.

Then we have the definition of the analogue input to read the humidity sensor:

#define HUM_PIN A5

 

as you can see, it is assigned to input 5 of Arduino’s ADC. 

Finally, we have the definition of input dedicated to reading the output status of the passive infrared movement sensor: 

#define PIR_PIN 2

 

Another relevant detail of the sketch is the definition of the number of Neopixel LEDs we have and which must be controlled, which is done using the following instruction:

#define PIXEL_COUNT 60

 

This number is important because Arduino uses it to set the data transmission speed on pin D9 in order to get a refresh that is compatible with our eye persistence, therefore quick enough.

Communication with the LED ring is initially set by turning all the LEDs of and then controlling them based on the reading from A9.

In the setup, we first set the pin D9 mode which will act as input:

pinMode(PIR_PIN, INPUT);

 

The serial port is also initialized at 9.600 baud in order to print, if we open the Serial Monitor, the working conditions.

In the loop, we then see the A5 analogue input being assigned and the related reading of the humidity sensor:

int humRAW=analogRead(HUM_PIN);

 

To which we will assign a connection after the comparison with the set thresholds.

The scrolling speed of the Neopixel LEDs can be set using the instruction:

rainbowCycle(5);

 

where rainbowCycle is the rainbow feature of the Neopixel and 5 is the parameter passed to it in order to define speed: by changing it, temporization changes, which means that by decreasing the number, rotation slows down and vice versa.

Let’s conclude with the code section regarding humidity thresholds and corresponding actions on the Neopixel LEDs:

 

switch(hum){       

case 1: strip.setPixelColor(i, Wheel1(((i * 256 / strip.numPixels()) + j) & 255));

                break;

case 2: strip.setPixelColor(i, Wheel2(((i * 256 / strip.numPixels()) + j) & 255));

                break;

case 3: strip.setPixelColor(i, Wheel3(((i * 256 / strip.numPixels()) + j) & 255));

                break;

case 4: strip.setPixelColor(i, Wheel4(((i * 256 / strip.numPixels()) + j) & 255));

                break;

case 5: strip.setPixelColor(i, Wheel5(((i * 256 / strip.numPixels()) + j) & 255));

                break;

}

 

From openstore

3D4040 – The big 3D printer – 40x40x40 cm

Bi-Card, the electronic business card

Mini PIR Sensor Module

Soil Humidity Sensor

RING WITH 60 LED RGB WS2812 AND DRIVER INTEGRATED

Compact switching power supply 5 Vdc / 3 A micro USB output

About Boris Landoni

Boris Landoni is the technical manager of Open-Electronics.org. Skilled in the GSM field, embraces the Open Source philosophy and its projects are available to the community.

Leave a Reply

Your email address will not be published. Required fields are marked *