System for Calibrating Dogbone RFID Moisture Sensors using Decagon 5TM Conductivity Sensor and I2C Communication

Author: Brett Stoddard

Hello  Everyone! 

This last week I’ve been working on getting a system to log data that I will use to calibrate the Smartrac Dogbone RFID moisture sensing tags in soil

Abstract and Objectives

This blog post describes a system to log data that I will use to calibrate the Smartrac Dogbone RFID moisture sensing tags in soil using a Decagon 5TM moisture sensor. The goal of this system is to log both 5TM’s electric permittivity readings (ε) alongside Dogbone’s moisture sensor levels over a long period of time to make a relationship and eventually properly calibrate the Dogbone tags to the current industry standard, dielectric permittivity. 

Using a 2GB SD card, this system will be able to record 82 million data points, more than enough for our system (each data point takes up around 26 bytes and 2*230/(26) = 82*106 ). The period that the measurements are taken at can be changed easily, but is currently set at 10 minutes which gives a solid resolution but is still small enough to analyze easily. Theoretically, measurements could be taken with a minimum period of 5 seconds. The logged data points will be saved as a CSV file because those can be read by Excel which will make analyzing data fairly trivial. 




After encountering a few problems, the system that I settled on was two Arduinos that would communicate over I2C. I was forced to do this because the “SDI Library” that is needed to communicate with the 5TM soil sensor I was using is incompatible with the “SoftwareSerial” that was critical for debugging and testing the code.

I2C communication was originally developed for and is usually used for multiple chips on the same embedded electronic system to communicate over the same bus. It’s useful for when tasks need to be split between multiple Arduinos. I2C is implemented in Arduino using the Wire library. For this situation, the slave Arduino was the one reading data from the TM5 sensor. The nice thing about I2C is that it is relatively trivial to add additional sensors to any sensors to a setup in case we want to make multiple readings at the same time. The code for implementing this setup was written by following this tutorial

One Arduino was set as a slave and read the data from the 5TM sensor. I followed Chet’s Decagon 5TM sensor guide to set this up. The master Arduino had the GPS logger, and RFID reader shields on it to record the values. The RFID reader shield uses pins 2 and 3; the GPS SD logger pins 13, SCL, and SCA; and I2C pins GND, A4 and A5 on the master Arduino. The 5TM sensor used pins 6, 5V, and GND; and I2C pins GND, A4 and A5 on the slave Arduino. The hardware diagram shown below illustrates this.


The code for this system will be posted in the examples folder of my RFID Github library under the title “Calibrator example”.


Last night, the first data set was collected using this setup over the course of 16 hours. Below is the graph (made in Excel) that shows the Dogbone moisture values (units not named) vs the 5TM conductivity measurements (dielectric permittivity, ε). There was a recorded R^2 value of .75 which means there was a moderately high correlation between the two. As one can see from the graph, over time the 5TM’s electron permittivity decreased slowly as the soil slowly dried out. Longer-term tests where the soil has time to go from saturated to dry will be key for properly calibrating the Dogbone tags to the current industry standard, dielectric permittivity.

The x-axis has units of number of 10 minute intervals

The x-axis has units of number of 10 minute intervals

Toward Comparing RFID Moisture Performance with Industry Standards: Decagon

Author: Chet Udell




Our previous experiments have shown the RFID moisture sensor tags are in-fact reading gradual changes in soil moisture content. The next step is to compare the performance, consistency, and resolution of these tags to industry standard equipment to see how it measures up using Decagon Devices soil moisture sensors. In this post, Chet gets a 5TM Soil Moisture and Temperature Sensor chatting directly with an Arduino to deploy in experiments, and eventually integrate into the battery of available Internet of Ag sensors.


In order to compare the performance, consistency, and resolution of the RFID moisture tags, we hope to conduct some comparative experiments between these and Decagon’s popular soil moisture sensors, namely the 5TM (soil moisture + temp). Decagon’s readers can be pricey and we want to use these sensors in very specific ways, so the objective here is to get the sensors talking directly with an Arduino. The following method can be used to read any Decagon soil moisture sensor over the SDI-12 serial protocol. For more info on SDI-12, visit here. Why the 5TM? The 5TM determines volumetric water content (VWC) by measuring the dielectric constant of the soil (or other media) using capacitance/frequency domain technology. Signal filtering minimizes salinity and textural effects, making the 5TM accurate in most soils and soilless media. Factory calibrations are included for mineral soils, potting soils, rockwool, and perlite. – from

Materials and Methods

What you’ll need:

  1. Download the above library, unzip. Rename the file “SDISerial” and place in the folder: <Arduinno root folder> / libraries
  2. Following the instructions on the library GitHub page (image included here), clip the 1/8 inch jack off of the Decagon sensor (ouch), strip off the leads to reveal a white, red, and “shield” wires. Solder each wire to a 0.1in pitch male header to use in a breadboard.
  3. Connect your arduino up to a breadboard and the 5TM lines White => 5V, Red => DATA_PIN, Shield => GND
  4. DATA_PIN MUST be connected to a pin with a hardware interrupt (for Uno, P2 or P3).
  5. Use the below code and you’ll get soil moisture and temp readings (in Celsius).
  6. Your output will look like the below screen print


As you’ll see from the below code and printout, the SDISerial library enables the arduino to send commands to the 5TM to procure data. Now, we can employ these sensors in almost any Arduino application! This is done by creating an instance of SDISerial connection(DATA_PIN); and then starting the serial connection using connection.begin();

You can then use the function connection.sdi_query() to send various commands to the 5TM. This function uses 2 parameters: (command, timeout-duration)

connection.sdi_query(“?M!”,1000); This sends a message to query the first device on the bus – which in use seems to refresh the values of the sensor readings, but does not return the sensor reading itself. Instead, it returns a message that tells you the maximum wait before the measurement is ready. timeout set for one second.

connection.sdi_query(“?I!”,1000); will get sensor info and timeout if no response in 1 second

connection.sdi_query(“?D0!”,1000); will query the 5TM for sensor data



Hookup on a Mega, similar to the Uno




Resulting output
Tested on UNO R3.
Sketch was built with Arduino 1.6.12
Dependency: Joran Beasley SDISerial Library
Accessed May 26, 2017 here:

download and rename folder "SDISerial" and place in  "<ARDUINO_ROOT>/libraries"

Tested with the with the 5TM Soil Moisture and Temp Sensor:

the WHITE wire goed to 5V. however you could also connect it to a pin and drive power only when you wanted it
the RED wire is the DATA_PIN. - you must hook it up to a pin that can process interrupts (see link below)  
the remaining "shield" wire must be connected to ground

#include <SDISerial.h>
#include <string.h>
#define DATA_PIN 2
SDISerial connection(DATA_PIN);
char output_buffer[125]; // just for uart prints
char tmp_buffer[4];
char* resp; // Pointer to response char

//initialize variables
void setup(){
      Serial.begin(9600);//so we can print to standard uart
      //small delay to let the sensor do its startup stuff
      delay(3000);//3 seconds should be more than enough
      char* sensor_info = connection.sdi_query("?I!",1000); // get sensor info
      //print to uart
      sprintf(output_buffer,"Sensor Info: %s",sensor_info?sensor_info:"No Response");

//main loop
void loop(){

   //print to uart
    Serial.println("Begin Command: ?M!");   
    //send measurement query (M) to the first device on our bus
    resp = connection.sdi_query("?M!",1000);//1 second timeout
    //this really just returns a message that tells you the maximum wait before the measurement is ready
    sprintf(output_buffer,"RECV: %s",resp?resp:"No Response Recieved!!");
    delay(1000);//sleep for 1 seconds before the next command
    //print to uart
    Serial.println("Begin Command: ?D0!");
    resp = connection.sdi_query("?D0!",1000);//1 second timeout
    sprintf(output_buffer,"RECV: %s",resp?resp:"No Response Recieved!!");
    delay(3000);//sleep for 10 seconds before the next read