Now that we have all the parts in place, lets test out the sensor node. Download and install the required libraries:

Plant Friends source code over at GitHub:

RFM12B / RFM69 Transciever Library

DHT11 Library from Adafruit:

Low Power Library from Rocketscream:

After you have installed the proper libraries. Open sensor_node_test.ino from my source and upload it to the Moteino. (Don't put batteries in the sensor node yet!). Then open up your serial console and you should see the sensor node dumping the soil moisture, temperature, humidity and battery voltage values. Since we don't have batteries connected, it is reading the USB voltage which should be around 5 volts.

The soil moisture should show 0 as it is not connected to anything yet. Connect the soil probe to the sensor with some female dupont wires. When you hold the probe with your hand, you should see an ADC reading about 120 ish. Now is the time to make sure you have all the connections right and everything working properly!


The type of moisture sensor we have in the sensor node is a simple resistive sensor. Remember the beginner Arduino tutorial where you learn to read a potentiometer and analogue voltages? This is the same idea, but the potentiometer is the soil! We pass current into the soil and then read the voltage. Moist soil equals less resistance and dry soil equals more resistance. The common circuit that you usually encounter looks something like this:


There are a few problems with this design. First, it uses power all the time which wastes precious battery life. Second, passing direct current through the probes will introduce electrolysis which leads to corrosion of the metal on our probes. We can remedy these problems by alternating the current and only pass current through the probes when we need to take a reading.

The design in Plant Friends uses 3 I/O pins on the Moteino. One to read the voltage, the other two alternates between sourcing (+) and sinking (-) current. We set the pin modes only when we need to read the soil moisture thereby helping us conserve power.

Here is the Plant Friends soil moisture sensor circuit:


The 328p ADC has a 10bit resolution so the “moisture level” we get back will be a value between 0 to 1023. You'll notice when you touch the probe with your hands, the values changes. Try touching the probes with some damp paper towels. What you are seeing here is the resistance between the two probes ( 0 = lots of resistance, 1023 low resistance, basically a direct short). Here is a chart that I came up with after sticking the probe into various stuff:


0 : in air @ 24c

120 : skin

120 - 250 : dry soil

300 - 600 : moist soil

600 - 700 : soaked soil

700 > : in water @ 24c (almost direct short)

1021 > : direct short

Depending on the type of soil that you have, you'll need to calibrate what value corresponds “dry soil” and what is “wet soil” (I use generic potting soil I bought from the local hardware store). You'll also want to determine what value you want to trigger a “low moisture alert”. I recommend you do some testing and come up with your own chart for your setup. If you are lazy, my chart and values should be “good enough”.

Keep in mind the temperature and salinity of the soil will skew the readings as well. If the ADC level reads over 600, that means you are over-watering and drowning your plants. This actually does more damage than not watering them!


This device is very straightforward and easy to use thanks to the Adafruit library. There are more accurate sensors out there but for Plant Friends, this is good enough.


The battery pack has 4x AA batteries in series configuration. If you are using fresh alkaline batteries, this means a total of 6 volts (~1.5v x 4). If you are using newly charged NiMh rechargeables, this means 4.8v (~1.2v x 4). In order to read voltages higher than VIN (Moteino is 3.3v), we'll need to use a voltage divider to bring down the voltage to a level that our Moteino can read. The two 10k ohm resistors create a 1:2 voltage divider, effectively dividing the voltage down in half; (1.5v x 4) / 2 = 3v for alkaline and (1.2v x 4) / 2 = 2.4v for NiMh.

Usually you'll find a voltage divider to be hooked up like so:


In this configuration, the resistor divider will continuously consume regardless of what the Moteino is doing. To conserve power, R2 is connected to an I/O pin on instead of ground. Similar to the soil moisture sensor, we'll use the I/O pin to sink current when we want to read the battery voltage.


A single depleted alkaline cell will read ~0.5 volts. So 0.5 x 4 = 2 volts for our battery pack. For NiMh rechargeable, 0.9v for a single cell and 3.6v for our battery pack. The low dropout regulator in the Moteino drops out at ~625mV above Vout ( 3.3v ), which means the regulator will go out of regulation at approximately 3.925 volts. This depends on the current draw but to simplify things and be on the safe side, the sensor node code sets 4 volts to be the low battery threshold. This might seem high but for rechargeable batteries, 0.9-1.0v per cell is the lowest voltage you want to go. Depleting the cells further will damage the batteries.


The Moteino sends data via the RF transceiver. It is identified by its' node ID number. This number has to be unique! Node ID 1 is reserved for the gateway only. The network ID has to be the same as the gateway ID. In my code, you can see the network ID is 23. After the sensor node collects the data, it transmits it to the base station.

The most obvious way to transmit sensor data would be something like “soil moisture: 250” or “temperature: 24” as separate messages. This will work OK. However, the transceiver consumes about 18ma every time it does a transmit. Although we only have 4 small pieces of data (soil moisture, humidity, temperature, battery voltage), we can pool all the data into one string and efficiently transmit everything in one go. This also has the benefit of chronologically synchronizing all the sensor data when it gets inserted into the database on the Pi.

The Plant Friends sensor node uses a custom data format. Nothing fancy, just something that is organized and easily interpreted when the data gets to the base station. The method uses colons to deliminate each data type:

Node ID : Error Level : Soil Moisture : Temperature : Humidity : Battery

Node ID – The unique numerical identification number of the sensor node.

Error Level – This is to tell the base station if an error is encountered on the node. For example, error level 0 means everything is ok. Error level 1 means low soil moisture and error level 4 means low battery. Error level 41 means soil moisture low and low battery! This can be expanded to mean different things.

Soil Moisture – Integer value from the ADC (0 – 1023).

Temperature – Temperature value in float. Will be interpreted as Celsius. Fahrenheit will be converted at the mobile app.

Humidity – Relative humidity value in float. Will be interpreted as a percentage.

Battery Voltage – The raw ADC value (0 - 1023) is calculated into a floating point voltage value.

An example of what a sensor node will transmit: 12:0:560:32:45:5.23

What it means:

The data is from sensor node 12.

Error level: 0. everything is working fine.

Soil moisture level is at 560.

Temperature is 32c.

Relative humidity is 45%.

The battery voltage is 5.23 volts.

Once the data gets to the base station, the raspi splits it up and inserts it into the MySQL database. This will be explained a bit more once we build the base station.


With the example code, the sensor node is taking readings and transmitting data continuously. You'll be right to assume our batteries would only last a few days. Remember, we are lazy so changing out batteries is the last thing we want to do.

Soil moisture changes very very very slowly, so the node only needs to take a reading once in awhile. After the sensor node is done collecting and transmitting data, it goes into a low power state (sleep) for a set amount of time, wake up and repeats the process.

The Low Power Library by Rocket Scream does just that. It combines all the low power commands for the 328p chip and puts it in one library so it is easy to use.

The library only allows you to put the MCU to sleep maximum 8 seconds at a time. We can easily fix that by putting the Moteino to sleep multiple times in a loop.

Open up the sensor_node.ino file, you can see the sleep cycle is defined as 450. 450x8 (seconds) = 3600 seconds = 1 hour. By turning sensors on when needed and taking readings every hour, 24 times a day, will make the batteries last months instead of days! I am able to get 4 – 5 months of battery life with this setting. You can go more aggressive and only take a reading every 1.5 – 2 hours which will make the batteries last even longer. ;)

In the sensor_node.ino file, the sleep cycle is somewhat defined dynamically. Whenever an alert is generated or when the node fails to receive and ack from the gateway, the sleep cycle is halved. Before we can play with the sensor node some more, we'll need to get the base station up and running.


1. Intro & BOM

2. Sensor Node Hardware

3. Sensor Node Software

4. Sensor Node Enclosure

5. Basestation Hardware & Software

6. Basestation Enclosure

7. The Mobile App

8. Notes & Thoughts

PreviousNext Page