Introduction
Measure Electrical Conductivity in Siemens, Total Dissolved Solids in PPM, Salinity in PSU and PPT.
Monitor hydroponic nutrient levels, salinity levels in aquariums or the ocean, saltwater pools, soil salinity, water quality etc.
It uses the standard Arduino Wire library to interface with the device. It’s operating principle is based on sending a very short-duration DC pulse from one probe pin and measuring the conductivity on the other pin. The conductivity is then converted to a temperature compensated Siemen. Salinity is also derived from the measure and is in PSU, PPT, and PPM.
Characteristics
- EC range: ~0.06 - ~200mS depending on probe
- Salinity range: 2 - 42
- Temperature range: -2 - 35C
- Interface: I2C
- Current use: ~10mA peak, low idle current ~1mA
- Voltage range: 2.7 - 5.5V
Connections
I2C Connections
The connection to the device is as follows:
EC Salinity Probe | Master device |
---|---|
GND | GND |
SCL | SCL |
SDA | SDA |
VCC | 2.7 - 5V |
Temperature Probe Connections
The temperature probe comes with a 3-wire header. The VCC pin is labeled with a triangle:
EC Salinity Probe | Temperature Probe |
---|---|
+ | (triangle |
D | |
- |
EC Probe Connections
The EC probe has two pins and can be connected either way.
Probe Selection
Any 2-electrode probe can be attached to the device.
A probe with a K constant of:
- 0.1K can measure from 0.06 - 199.9 uS
- 1K from 0 - 1999 uS
- 10K from 0 - 200 mS
Getting Started
To start developing for the device, you need to install the library. Two are provided, one for the Arduino framework, and the other for python3 on the Raspberry Pi.
If you are using the Arduino IDE, you can go to the library manager (Sketch / Include Library / Manage Libraries…) and search for pH_Probe. Examples are included.
If you are using PlatformIO, you can install the library using the library manager (PlatformIO / PlatformIO Home / Libraries) and search for pH Probe. Examples are included.
For Raspberry Pi 3, you can clone the GitHub repo. Before you can run anything, you will need to enable software I2C, as the Pi’s hardware implementation has a clock-stretching bug that will prevent it from working with the pH probe.
sudo nano /boot/config.txt
and scroll to the bottom- Add
dtoverlay=i2c-gpio,i2c_gpio_sda=<pin>,i2c_gpio_scl=<pin>
, replacing<pin>
with whatever pin you’d like to use. Refer here for the pin functions, you will need to use the orange GPIO xx labels in the picture to locate the pins. As an example, to use GPIO 17 as SDA and GPIO 27 as SCL, your line will look like thisdtoverlay=i2c-gpio,i2c_gpio_sda=17,i2c_gpio_scl=27
Alternatively, you can choose to use the existing I2C pins, but using a software implementation of I2C, by pastingdtoverlay=i2c-gpio
. If you go this route, you will need to edit line #4 fromph = phprobe(3)
, toph = phprobe(1)
. ctrl + x
to exit,y
to save, andenter
to confirm the filename.- Reboot
From inside repo folder, execute sudo python3 shell.ph
and you should be presented with a >
prompt as described below.
The shell Example
An interactive shell interface is provided with both frameworks and is a quick and easy way to get started using the device. You will find the equivalent commands in the code area to the right when applicable. Upload it to your master device and start a serial terminal. You will be presented with a >
prompt where you can enter commands and receive a response, similar to a shell command line or REPL. It is often quicker to experiment with things this way rather than rewriting, compiling, and uploading new versions every time.
Changing the I2C Address
If needed, the I2C address can be changed in programatically by calling setI2CAddress()
. The device will permanently change it’s address to the passed value and continue to use it after a power reset. If you forget the new address, you will need to use an I2C bus scanner to locate it again.
Calibration
#include <ECSalinity.h>
EC_Salinity ec;
float calibrationSolution_mS = 2.77;
ec.setK(10.0);
ec.calibrateProbe(calibrationSolution_mS, ec.tempCoefEC);
from ecsalinity import ecsalinity
ec = ecsalinity(3)
calibrationSolution_mS = 2.77
ec.setK(10.0)
ec.calibrateProbe(calibrationSolution_mS, ec.tempCoefEC)
k 10.0
cal 2.77
When the device is powered for the first time, it will be uncalibrated. There are two calibration options: single and dual or double point. Single point determines a percent difference between actual readings and expected readings, then uses it to make adjustments. Double point uses two points, a high and low, to determine the adjustment to make. The choice of single or double depends on the expected use. A small range might be better measured by single point calibration whereas a large range may be more accurate with double point.
Before any measurements can be made, to include measurements to calibrate the probe, the cell constant (K) must be specified. This number is typically 0.1, 1.0, or 10.0. The exact value may be found on the probe itself (9.988 for example). After K has been set, you can expect to see values being returned. It will not be accurate and must be calibrated.
For best results, the probe should be cleaned with distilled water and then placed in the solution for 5-10 minutes before the probe is used. It shouldn’t be placed on the bottom or side of the solution container. Note that any turbidity, air bubbles, large particles, etc will effect readings. An unstable temperature will decrease accuracy as well.
When calibrating the probe, it is important to consider the expected temperature range. EC measurements are very temperature dependent, effecting the results by approximately 2% per degree C. The probe should be calibrated at the median expected temperature.
Likewise, the probe should be calibrated in the median expected EC range. For example, if you are planning to measure the salinity of an aquarium, you might expect readings ±5 from 35PPT (equivalent to 53mS). So a 53mS solution for calibration would be appropriate, whereas a hydroponic calibration might be 2.77mS or lower.
Another consideration is the placement of the probe. When the probe sends out a pulse of electricity, it leaves the probe in 360 degrees. If it is near a metal surface, you will experience fringing effects. The probe should be calibrated in an environment as similar as possible to the location it will be deployed in.
Single Point
float solutionEC = 53.0;
ec.calibrationProbe(solutionEC, ec.tempCoefSalinity);
solutionEC = 53.0
ec.calibrationProbe(solutionEC, ec.tempCoefSalinity)
cal 53.0
For this method of calibrating, submerge the probe and wait for the readings to stabilize. Then call calibrateProbe()
. The calibration information will be stored in EEPROM and is the percent difference from the measured value and the expected value.
Dual Point
Two calibration solutions are required, the low and high values you expect to measure between.
- Determine the lowest and highest measurement you expect. For example, the lowest level you might measure would be 50 mS and the highest might be 58 mS. These points will be referred to as
referenceLow
andreferenceHigh
- Put the EC probe in a calibration solution at
referenceLow
and wait for readings to stabilize, callcalibrateProbeLow()
. Do the same for referenceHigh by calling ‘calibrateProbeHigh’. - By default, the device does not use dual points. A call to
useDualPoint()
must be made to enable it each time the device is powered.
You can also set all four values directly using setDualPointCalibration()
.
float solutionECLow = 53.0;
float solutionECHigh = 58.0;
ec.calibrateProbeLow(solutionECLow, ec.tempCoefSalinity);
ec.calibrateProbeHigh(solutionECHigh, ec.tempCoefSalinity);
ec.useDualPoint(true);
solutionECLow = 53.0
solutionECHigh = 58.0
ec.calibrateProbeLow(solutionECLow, ec.tempCoefSalinity)
ec.calibrateProbeHigh(solutionECHigh, ec.tempCoefSalinity)
ec.useDualPoint(True)
low 53.0
high 58.0
dp 1
getCalibrateHigh
and getCalibrateLow
can be used
to get the currently set reference values.
Each call to measureEC
will use the calibration to adjust
the reading. It can be disabled by ec.useDualPoint(false);
Use
float tempC = ec.measureTemp();
tempC = ec.measureTemp()
temp
Once the probe has been calibrated, a reading can be taken. The device will use
the most recent temperature measurement obtained from measureTemp
if temperature
compensation is enabled.The probe should be placed in the solution to be measured and measureEC
called to start a measurement.
After the measurement is taken, the following class variables are updated:
uS
mS
S
PPM_500
PPM_640
PPM_700
salinityPSU
salinityPPT
salinityPPM
tempC
tempF
Temperature Coefficients
float pureWaterCompensation = 0.0455;
ec.measureEC(pureWaterCompensation);
ec.measureEC();
ec.measureSalinity();
pureWaterCompensation = 0.0455
ec.measureEC(pureWaterCompensation)
ec.measureEC()
ec.measureSalinity()
ec
sal
If the solution to be measured is saltwater, use measureSalinity()
,
if it is freshwater, use measureEC()
. A custom temperature
coefficient can be used by passing it to measureEC()
.
Temperature Compensation
byte tempConstant = 25;
ec.setTempConstant(tempConstant);
ec.setTempConstant(0xFF);
tempConstant = 25
ec.setTempConstant(tempConstant)
ec.setTempConstant(0xFF)
tc 1 25
tc 0
tc 1 255
To set the temperature used for compensation, call
setTempConstant()
and pass the temperature to use. To use the
actual temperature, pass 0xFF.
Accuracy
ec.setAccuracy(21);
ec.setAccuracy(21)
acc 21
The accuracy of the device can be adjusted by modifying setAccuracy
.
By default, 9 measurements are taken. A running median sort is applied and
the middle third of the nine measurements are averaged together to provide the
final result. Any number of measurements can be taken as long as it is evenly
divisible by 3. The least number of measures possible is 3.
Measurement Time
Each individual EC measurement takes 10ms. If the default accuracy is set to 9,
a call to measureEC
will return in about 90ms. A temperature measurement
takes 750ms.
More Help
If you have any questions, find a bug, or have any suggestions on improvements, go to this project’s GitHub page and submit an Issue or Pull Request.
Class Members
public float S
EC in Siemens
public float mS
EC in milli-Siemens
public float uS
EC in micro-Siemens
public long PPM_500
Parts per million using 500 as a multiplier
public long PPM_640
Parts per million using 640 as a multiplier
public long PPM_700
Parts per million using 700 as a multiplier
public float salinityPSU
Salinity measured practical salinity units
public float salinityPPT
Salinity measured parts per thousand
public float salinityPPM
Salinity measured parts per million
public float tempC
Temperature in C
public float tempF
Temperature in F
Class Functions
public float measureEC(float tempCoefficient)
Starts an EC measurement.
float mS = EC_Salinity::measureEC(ec.tempCoefEC);
ms = ec.measureEC(ecsalinity.tempCoefEC)
The device starst an EC measurement. The accuracy can be specified in EC_Salinity::setAccuracy.
Parameters
tempCoefficient
the coefficient used to compensate for temperature.
uS, mS, S, tempC, tempF, PPM_500, PPM_640, PPM_700, salinityPPM, salinityPPT, and salinityPSU are updated
Returns
milli-Siemens
public float measureEC()
Convenience function to measure EC in freshwater.
float mS = EC_Salinity::measureEC();
ec
Calls EC_Salinity::measureEC(EC_Salinity::tempCoefEC)
Returns
EC in mS
public float measureSalinity()
Convenience function to measure salinity.
float PSU = EC_Salinity::measureSalinity();
sal
Calls EC_Salinity::measureEC(EC_Salinity::tempCoefSalinity)
Returns
salinity in PSU
public float measureTemp()
Starts a temperature measurement.
float tempC = EC_Salinity::measureTemp();
tempC = ec.measureTemp()
temp
tempC and tempF are updated
Returns
temperature in C
public void calibrateProbe(float solutionEC,float tempCoef)
Calibrates the connected probe and saves the result in EEPROM.
EC_Salinity::calibrateProbe(2.77, EC_Salinity::tempCoefEC);
ec.calibrateProbe(2.77, ecsalinity.tempCoefEC)
cal 2.77
Parameters
solutionEC
the EC of the calibration solution in mStempCoef
the coefficient used to calibrate the probe
offset will be saved in the device’s EEPROM and used automatically thereafter
public void calibrateProbeLow(float solutionEC,float tempCoef)
Calibrates the dual-point values for the low reading and saves them in the devices’s EEPROM.
EC_Salinity::calibrateProbeLow(1.0, EC_Salinity::tempCoefEC);
ec.calibrateProbeLow(1.0, ecsalinity.tempCoefEC)
low 1.0
Parameters
solutionEC
the EC of the calibration solution in mStempCoef
the coefficient used to calibrate the probe
public void calibrateProbeHigh(float solutionEC,float tempCoef)
Calibrates the dual-point values for the high reading and saves them in the devices’s EEPROM.
EC_Salinity::calibrateProbeHigh(3.0, EC_Salinity::tempCoefEC);
ec:calibrateProbeHigh(3.0, ecsalinity.tempCoefEC)
high 3.0
Parameters
solutionEC
the EC of the calibration solution in mStempCoef
the coefficient used to calibrate the probe
public void calculateK(float solutionEC,float tempCoef)
Calculates the K value of the connected probe and saves it in EEPROM. Also essentially single-point calibrates the device.
EC_Salinity::calculateK(2.77, EC_Salinity::tempCoefEC);
ec.calculateK(2.77, ecsalinity.tempCoefEC)
calk 2.77
Parameters
solutionEC
the EC of the calibration solution in mStempCoef
the coefficient used to calibrate the probe
public void setDualPointCalibration(float refLow,float refHigh,float readLow,float readHigh)
Sets all the values for dual point calibration and saves them in the devices’s EEPROM.
EC_Salinity::setDualPointCalibration(1.0, 3.0, 0.9, 3.2);
ec.setDualPointCalibration(1.0, 3.0, 0.9, 3.2)
Parameters
refLow
the reference low pointrefHigh
the reference high pointreadLow
the measured low point in mSreadHigh
the measured high point in mS
public void setK(float k)
Updates the device with a new cell constant and saves it in EEPROM.
EC_Salinity::setK(1.121);
ec.setK(1.121)
k 1.121
Parameters
k
the new cell constant
public float getK()
Retrieves the cell constant from the device.
float k = EC_Salinity::getK();
k = ec.getK()
k
Returns
the cell constant
public void setAccuracy(byte b)
Configures the accuracy of the device.
EC_Salinity::setAccuracy(6);
ec.setAccuracy(6)
acc 6
The device maintains a running median of values. It throws out the top and bottom third of values, then averages the middle third together to return a single value. The accuracy increases with a high number. It must be evenly divisible by 3.
Parameters
b
accuracy of the device
public byte getAccuracy()
acc
Retrieves the accuracy configuration of the device.
Returns
accuracy
public void reset()
reset
Resets all the stored calibration information.
public void setTempConstant(byte b)
Configures device to use the provided temperature constant.
EC_Salinity::setTempConstant(25);
EC_Salinity::setTempConstant(0xFF); // use the actual tempeature
ec.setTempConstant(25)
ec.setTempConstant(255)
tc 1 25
tc 0
tc 1 255
By default, the temperature constant is set to 0xFF which instructs the actual temperature to be used for temperature compensation, however any number can be specified. To use the actual temperature, restore the value to 0xFF.
Parameters
b
the temperature to use for compensation
public byte getTempConstant()
tc
Retrieves the temperature constant.
Returns
the temperature to used for compensation
public void useTemperatureCompensation(bool b)
Configures device to use temperature compensation or not.
EC_Salinity::useTemperatureCompensation(true);
ec.useTemperatureCompensation(True)
tc 1
Parameters
b
true/false
public bool usingTemperatureCompensation()
Determines if temperature compensation is being used.
Returns
true if using compensation, false otherwise
public void useDualPoint(bool b)
dp 1
Configures device to use dual-point calibration.
Parameters
b
true/false
public bool usingDualPoint()
dp
Determines if dual point calibration is being used.
Returns
true if using compensation, false otherwise
public float getCalibrateHigh()
high
Retrieves the dual-point calibration high value.
Returns
the dual-point calibration high value
public float getCalibrateLow()
low
Retrieves the dual-point calibration low value.
Returns
the dual-point calibration low value
public float getCalibrateHighReading()
Retrieves the dual-point calibration reading high value.
Returns
the dual-point calibration high value
public float getCalibrateLowReading()
Retrieves the dual-point calibration reading low value.
Returns
the dual-point calibration low value
public void setCalibrateOffset(float offset)
Sets the single point offset value.
Parameters
offset
single point offset value
public float getCalibrateOffset()
cal
Retrieves the single point offset value.
float calibrateOffset = EC_Salinity::getCalibrateOffset();
Returns
single point offset value
public byte getVersion()
Retrieves the firmware version of the device.
Returns
version of firmware
public void setI2CAddress(uint8_t address)
Changes the i2c address of the device. It will use the new address immediately and continue to use it even after a power reset.
Parameters
address
new i2c address
Generated by Moxygen