Skip to content

Commit

Permalink
Add Meter Teros 11 soil moisture sensor, not tested
Browse files Browse the repository at this point in the history
First attempt to address #276
  • Loading branch information
aufdenkampe committed Aug 28, 2019
1 parent d85be2d commit eebc93b
Show file tree
Hide file tree
Showing 2 changed files with 292 additions and 0 deletions.
131 changes: 131 additions & 0 deletions src/sensors/MeterTeros11.CPP
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/*
*MeterTeros11.cpp - MODIFIED FOR new TEROS 11 sensor !!!
*This file is part of the EnviroDIY modular sensors library for Arduino
*
*Written by Anthony Aufdenkampe <[email protected]>, based on
*Initial library developement done by Sara Damiano ([email protected]).
*
*This file is for the Meter Teros 11 Advanced Soil Moisture probe
*It is dependent on the EnviroDIY SDI-12 library and the SDI12Sensors super class.
*
*Documentation for the SDI-12 Protocol commands and responses
*for the Meter Teros 11 can be found at:
* http://publications.metergroup.com/Integrator%20Guide/18224%20TEROS%2011-12%20Integrator%20Guide.pdf
*
* For Ea and VWC:
* Resolution is 0.001 m3/m3 (0.1% VWC) from 0 – 70% VWC
* Accuracy for Generic calibration equation: ± 0.03 m3/m3 (± 3% VWC) typ
* Accuracy for Medium Specific Calibration: ± 0.01 to 0.02 m3/m3 (± 1-2% VWC)
* Range is 0 – 1 m3/m3 (0 – 100% VWC)
*
* For Temperature:
* Resolution is 0.1°C
* Accuracy is ± 0.5°C, from - 40°C to 0°C
* Accuracy is ± 0.3°C, from 0°C to + 60°C
*
* Warm-up time in SDI-12 mode: 245ms typical, assume stability at warm-up
* Measurement duration: 25 ms to 50 ms
*
* Supply Voltage (VCC to GND), 4.0 to 15.0 VDC
* Digital Input Voltage (logic high), 2.8 to 3.9 V (3.6 typical)
* Digital Output Voltage (logic high), 3.6 typical
*/

#include "MeterTeros11.h"

bool MeterTeros11::addSingleMeasurementResult(void)
{
bool success = false;

// Set up the float variables for receiving data
float raw = -9999;
float ea = -9999;
float temp = -9999;
float VWC = -9999;

// Check a measurement was *successfully* started (status bit 6 set)
// Only go on to get a result if it was
if (bitRead(_sensorStatus, 6))
{
// MS_DBG(F(" Activating SDI-12 instance for"), getSensorNameAndLocation());
// Check if this the currently active SDI-12 Object
bool wasActive = _SDI12Internal.isActive();
// if (wasActive) {MS_DBG(F(" SDI-12 instance for"), getSensorNameAndLocation(),
// F("was already active!"));}
// If it wasn't active, activate it now.
// Use begin() instead of just setActive() to ensure timer is set correctly.
if (!wasActive) _SDI12Internal.begin();
// Empty the buffer
_SDI12Internal.clearBuffer();

MS_DBG(getSensorNameAndLocation(), F("is reporting:"));
String getDataCommand = "";
getDataCommand += _SDI12address;
getDataCommand += "D0!"; // SDI-12 command to get data [address][D][dataOption][!]
_SDI12Internal.sendCommand(getDataCommand);
delay(50); // It just needs this little delay
MS_DBG(F(" >>>"), getDataCommand);

uint32_t start = millis();
while (_SDI12Internal.available() < 3 && (millis() - start) < 1500) {}
MS_DBG(F(" Receiving results from"), getSensorNameAndLocation());
_SDI12Internal.read(); // ignore the repeated SDI12 address
// First variable returned is the raw count value. This gets convertd into dielectric ea
raw = _SDI12Internal.parseFloat();
if (raw < 0 || raw > 5000) raw = -9999;
if (raw != -9999)
{
ea = ((2.887e-9*(raw*raw*raw))-(2.08e-5*(raw*raw))+(5.276e-2 *raw)-43.39)*((2.887e-9*(raw*raw*raw))-(2.08e-5*(raw*raw))+(5.276e-2 *raw)-43.39);
}
// Second variable returned is the temperature in °C
temp = _SDI12Internal.parseFloat();
if (temp < -50 || temp > 60) temp = -9999; // Range is - 40°C to + 50°C
// the "third" variable of VWC is actually calculated (Topp equation for mineral soils), not returned by the sensor!
if (ea != -9999)
{
VWC = (4.3e-6*(ea*ea*ea))
- (5.5e-4*(ea*ea))
+ (2.92e-2 * ea)
- 5.3e-2 ;
VWC *= 100; // Convert to actual percent
}

//VWC = 3.879e-4*raw-0.6956; // equation for mineral soils

if (VWC < 0) VWC = 0;
if (VWC > 100) VWC = 100;

// String sdiResponse = _SDI12Internal.readStringUntil('\n');
// sdiResponse.trim();
// _SDI12Internal.clearBuffer();
// MS_DBG(F(" <<<"), sdiResponse);

// Empty the buffer again
_SDI12Internal.clearBuffer();

// De-activate the SDI-12 Object
// Use end() instead of just forceHold to un-set the timers
_SDI12Internal.end();

MS_DBG(F(" Dialectric E:"), ea);
MS_DBG(F(" Temperature:"), temp);
MS_DBG(F(" Volumetric Water Content:"), VWC);

success = true;
}
else
{
MS_DBG(getSensorNameAndLocation(), F("is not currently measuring!"));
}

verifyAndAddMeasurementResult(TM_EA_VAR_NUM, ea);
verifyAndAddMeasurementResult(TM_TEMP_VAR_NUM, temp);
verifyAndAddMeasurementResult(TM_VWC_VAR_NUM, VWC);

// Unset the time stamp for the beginning of this measurement
_millisMeasurementRequested = 0;
// Unset the status bits for a measurement request (bits 5 & 6)
_sensorStatus &= 0b10011111;

return success;
}
161 changes: 161 additions & 0 deletions src/sensors/MeterTeros11.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/*
*MeterTeros11.h
*This file is part of the EnviroDIY modular sensors library for Arduino
*
*Written by Anthony Aufdenkampe <[email protected]>, based on
*Initial library developement done by Sara Damiano ([email protected]).
*
*This file is for the Meter Teros 11 Advanced Soil Moisture probe
*It is dependent on the EnviroDIY SDI-12 library and the SDI12Sensors super class.
*
*Documentation for the SDI-12 Protocol commands and responses
*for the Meter Teros 11 can be found at:
* http://publications.metergroup.com/Integrator%20Guide/18224%20TEROS%2011-12%20Integrator%20Guide.pdf
*
* For Ea and VWC:
* Resolution is 0.001 m3/m3 (0.1% VWC) from 0 – 70% VWC
* Accuracy for Generic calibration equation: ± 0.03 m3/m3 (± 3% VWC) typ
* Accuracy for Medium Specific Calibration: ± 0.01 to 0.02 m3/m3 (± 1-2% VWC)
* Range is 0 – 1 m3/m3 (0 – 100% VWC)
*
* For Temperature:
* Resolution is 0.1°C
* Accuracy is ± 0.5°C, from - 40°C to 0°C
* Accuracy is ± 0.3°C, from 0°C to + 60°C
*
* Warm-up time in SDI-12 mode: 245ms typical, assume stability at warm-up
* Measurement duration: 25 ms to 50 ms
*
* Supply Voltage (VCC to GND), 4.0 to 15.0 VDC
* Digital Input Voltage (logic high), 2.8 to 3.9 V (3.6 typical)
* Digital Output Voltage (logic high), 3.6 typical
*/

// Header Guards
#ifndef MeterTeros11_h
#define MeterTeros11_h

// Debugging Statement
// #define MS_MeterTeros11_DEBUG

#ifdef MS_MeterTeros11_DEBUG
#define MS_DEBUGGING_STD "MeterTeros11"
#endif

// Included Dependencies
#include "ModSensorDebugger.h"
#undef MS_DEBUGGING_STD
#include "VariableBase.h"
#include "sensors/SDI12Sensors.h"

// Sensor Specific Defines
#define TM_NUM_VARIABLES 3
#define TM_WARM_UP_TIME_MS 250
#define TM_STABILIZATION_TIME_MS 50
#define TM_MEASUREMENT_TIME_MS 50

#define TM_EA_RESOLUTION 5
// adding extra digit to resolution for averaging
#define TM_EA_VAR_NUM 0

#define TM_TEMP_RESOLUTION 2
// adding extra digit to resolution for averaging
#define TM_TEMP_VAR_NUM 1

#define TM_VWC_RESOLUTION 3
// adding extra digit to resolution for averaging
#define TM_VWC_VAR_NUM 2

// The main class for the Decagon 5TM
class MeterTeros11 : public SDI12Sensors
{
public:
// Constructors with overloads
MeterTeros11(char SDI12address, int8_t powerPin, int8_t dataPin, uint8_t measurementsToAverage = 1)
: SDI12Sensors(SDI12address, powerPin, dataPin, measurementsToAverage,
"MeterTeros11", TM_NUM_VARIABLES,
TM_WARM_UP_TIME_MS, TM_STABILIZATION_TIME_MS, TM_MEASUREMENT_TIME_MS)
{}
MeterTeros11(char *SDI12address, int8_t powerPin, int8_t dataPin, uint8_t measurementsToAverage = 1)
: SDI12Sensors(SDI12address, powerPin, dataPin, measurementsToAverage,
"MeterTeros11", TM_NUM_VARIABLES,
TM_WARM_UP_TIME_MS, TM_STABILIZATION_TIME_MS, TM_MEASUREMENT_TIME_MS)
{}
MeterTeros11(int SDI12address, int8_t powerPin, int8_t dataPin, uint8_t measurementsToAverage = 1)
: SDI12Sensors(SDI12address, powerPin, dataPin, measurementsToAverage,
"MeterTeros11", TM_NUM_VARIABLES,
TM_WARM_UP_TIME_MS, TM_STABILIZATION_TIME_MS, TM_MEASUREMENT_TIME_MS)
{}
// Destructor
~MeterTeros11(){}

virtual bool addSingleMeasurementResult(void) override;
};


// Defines the Ea/Matric Potential Variable
class MeterTeros11_Ea : public Variable
{
public:
MeterTeros11_Ea(Sensor *parentSense,
const char *uuid = "",
const char *varCode = "SoilEa")
: Variable(parentSense,
(const uint8_t)TM_EA_VAR_NUM,
(uint8_t)TM_EA_RESOLUTION,
"permittivity", "faradPerMeter",
varCode, uuid)
{}
MeterTeros11_Ea()
: Variable((const uint8_t)TM_EA_VAR_NUM,
(uint8_t)TM_EA_RESOLUTION,
"permittivity", "faradPerMeter", "SoilEa")
{}
~MeterTeros11_Ea(){}
};


// Defines the Temperature Variable
class MeterTeros11_Temp : public Variable
{
public:
MeterTeros11_Temp(Sensor *parentSense,
const char *uuid = "",
const char *varCode = "SoilTemp")
: Variable(parentSense,
(const uint8_t)TM_TEMP_VAR_NUM,
(uint8_t)TM_TEMP_RESOLUTION,
"temperature", "degreeCelsius",
varCode, uuid)
{}
MeterTeros11_Temp()
: Variable((const uint8_t)TM_TEMP_VAR_NUM,
(uint8_t)TM_TEMP_RESOLUTION,
"temperature", "degreeCelsius", "SoilTemp")
{}
~MeterTeros11_Temp(){}
};


// Defines the Volumetric Water Content Variable
class MeterTeros11_VWC : public Variable
{
public:
MeterTeros11_VWC(Sensor *parentSense,
const char *uuid = "",
const char *varCode = "SoilVWC")
: Variable(parentSense,
(const uint8_t)TM_VWC_VAR_NUM,
(uint8_t)TM_VWC_RESOLUTION,
"volumetricWaterContent", "percent",
varCode, uuid)
{}
MeterTeros11_VWC()
: Variable((const uint8_t)TM_VWC_VAR_NUM,
(uint8_t)TM_VWC_RESOLUTION,
"volumetricWaterContent", "percent", "SoilVWC")
{}
~MeterTeros11_VWC(){}
};

#endif // Header Guard

0 comments on commit eebc93b

Please sign in to comment.