NAV Navbar
Logo
cpp python shell

Introduction

Measure Electrical Conductivity in Siemens, Total Dissolved Solids in PPM, and Salinity in PSU and PPT.

Monitor hydroponic nutrient levels, salinity in aquariums, pools, or soil.

Characteristics

Connections

I2C Connections

The connection to the device is as follows:

EC Salinity Probe Master device
GND GND
SCL SCL
SDA SDA
3.3/5v 3.3 - 5V

I2C Bus Pull-ups

Each device comes with 4.7k resistor pullups on the I2C bus. They pass through a 3-pad solder paste jumper. The outer pads are connected to the middle by thin traces. To disable the pullups, use a utility knife to cut both traces. To re-enable the pullups, connect all three pads together with solder.

Temperature Probe Connections

The temperature probe comes with a 3-wire header; any 3-wire DS18B20 will work. The VCC pin is labeled with a triangle:

EC Salinity Probe Temperature Probe
▲ (VCC
(Data) (pin 2)
(GND) (pin 3)

EC Probe Connections

EC probes have two pins and can be connected either way.

Probe Selection

Any 2-electrode probe can be attached to the device. It is recommended to only use the probes provided by uFire. They are designed to be inexpensive and replaceable after approximately six months to a year of light use. The probe can be kept submerged, however it will require cleaning and re-calibration more often. The temperature range of the probe is -20 - 80 C.

A probe with a K constant of:

Getting Started

To start developing for the device, you need to install this library for your board/platform.

Raspberry Pi

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. 1. sudo nano /boot/config.txt and scroll to the bottom 2. 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 this

dtoverlay=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 pasting dtoverlay=i2c-gpio. If you go this route, you will need to edit line #4 from

ph = phprobe(3), to ph = phprobe(1)

  1. ctrl + x to exit, y to save, and enter to confirm the filename.
  2. Reboot

The shell Example

An interactive shell interface is provided with all 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, start a serial terminal and 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 programatically by calling setI2CAddress(). The device will permanently change the address 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(1.0);
ec.calibrateDry();
ec.calibrateProbe(calibrationSolution_mS, ec.tempCoefEC);
from ecsalinity import ecsalinity
ec = ecsalinity(3)
calibrationSolution_mS = 2.77
ec.setK(1.0)
ec.calibrateDry()
ec.calibrateProbe(calibrationSolution_mS, ec.tempCoefEC)
k 1.0
dry
cal 2.77

When the device is powered for the first time, it will be uncalibrated. There are two calibration options: single and dual point. Single point determines a percent difference between actual readings and expected readings, then uses it to make adjustments. Dual point uses two points, a high and low, to determine the adjustment to make. The choice of single or dual 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 dual 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 setting K, you can optionally calibrate the probe to determine the reading it returns when it is dry. calibrateDry() will record the measurment and automatically be used for subsequent measurments. If the value is equal to or less than the dry value, -1 is returned. This indicates the probe is dry or also if it is unconnected.

For best results, the probe should be cleaned with distilled water or vinegar 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. Any turbidity, air bubbles, large particles, or unstable temperature will effect readings.

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 metal, 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.calibrateProbe(solutionEC, ec.tempCoefSalinity);
solutionEC = 53.0
ec.calibrateProbe(solutionEC, ec.tempCoefSalinity)
cal 53.0

For this method of calibration, submerge the probe and wait for the readings to stabilize. Then call calibrateProbe(). The calibration information will be stored in EEPROM.

Dual Point

Two calibration solutions are required, the low and high values you expect to measure between.

  1. 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 and referenceHigh
  2. Put the EC probe in a calibration solution at referenceLow and wait for readings to stabilize, then call calibrateProbeLow(). Do the same for referenceHigh by calling ‘calibrateProbeHigh()’.
  3. By default, the device does not use dual point, even if the values are provided. A call to useDualPoint(true) must be made to enable it. It will be saved in the configuration and used automatically.

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

Use

Once the probe has been calibrated, a reading can be taken.

After the measurement is taken, the following class variables are updated:

Temperature Compensation

byte tempConstant = 20;
ec.setTempConstant(tempConstant);
ec.useTemperatureCompensation(true);
tempConstant = 20
ec.setTempConstant(tempConstant)
ec.useTemperatureCompensation(True);
tc 1 20
tc 0

Conductivity naturally changes with temperature. When the temperature drops, the solution condences, molecules move closer together and allow a charge to more easily pass. The opposite occurs when the temperature increases.

Temperature compensation is used to calculate what the measured conductivity would be if it were measured at a different temperature. This is just an approximation and is determined by the temperature coefficient as explained below.

To set the temperature used for compensation, call setTempConstant() and pass the temperature to use; the temperature probe must be connected for this measurement. Calling measureEC() or measureSalinity() will also call measureTemp() before taking a measurement if usingTemperatureCompensation() has been set to true.

The values passed to setTempConstant() and useTemperatureCompensation() will be saved and used automatically.

Temperature Coefficients

float pureWaterCompensation = 0.0455;
ec.measureEC(pureWaterCompensation, true);
ec.measureEC();
ec.measureSalinity();
pureWaterCompensation = 0.0455
ec.measureEC(pureWaterCompensation, True)
ec.measureEC()
ec.measureSalinity()
ec
sal

Temperature coefficients are used in compensating for temperature. Values vary depending on the type of solution being measured and the source providing the numbers. In common usage, ultra-pure, freshwater, and saltwater have distinct values.

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().

Measurement Time

Each individual EC measurement takes 150ms. A temperature measurement takes 750ms.

More Help

If you have any questions, find a bug, or have any suggestions, go to this project’s GitHub page and submit an Issue or Pull Request. Or you can send an email to [email protected].

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, bool newTemp)

Starts an EC measurement.

float mS = EC_Salinity::measureEC(ec.tempCoefEC, true);
    ms = ec.measureEC(ecsalinity.tempCoefEC, True)

The device starst an EC measurement.

Parameters

uS, mS, S, tempC, tempF, PPM_500, PPM_640, PPM_700, salinityPPM, salinityPPT, and salinityPSU are updated

Returns

EC in mS


public float measureEC()

Convenience function to measure EC in freshwater and taking a new temperature measurement.

float mS = EC_Salinity::measureEC();
mS = ec.measureEC()
ec

Calls EC_Salinity::measureEC(EC_Salinity::tempCoefEC, true);

Returns

EC in mS


public float measureSalinity()

Convenience function to measure salinity and taking a new temperature measurement.

The PSU must be between 2 and 42; a value not within bounds will return -1. The temperature must be within -2 to 35, or -2 will be returned.

float PSU = EC_Salinity::measureSalinity();
PSU = ec.measureSalinity();
sal

Calls EC_Salinity::measureEC(EC_Salinity::tempCoefSalinity, true);

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

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


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


public void calibrateDry()

EC_Salinity::calibrateDry();
ec.calibrateDry()
dry

Determines the dry reading of the probe and saves the result in EEPROM. If subsequent measurements are taken that are less than the dry value, a -1 will be returned. This can be used to determine if the probe is not connected as well.


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


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


public float getK()

Retrieves the cell constant from the device.

float k = EC_Salinity::getK();
k = ec.getK()
k

Returns

the cell constant


public float getCalibrateDry()

float dry = EC_Salinity::getCalibrateDry();
dry = ec.getCalibrateDry()
dry

Retrieves the dry reading of the probe

Returns

dry reading


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 25 which will adjust the measured values to 25C. To use the actual temperature, set the value to 0xFF.

Parameters


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


public bool usingTemperatureCompensation()

tc

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


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


public float getCalibrateOffset()

Retrieves the single point offset value.

float calibrateOffset = EC_Salinity::getCalibrateOffset();
cal

Returns

single point offset value


public byte getVersion()

Retrieves the firmware version of the device.

Returns

version of firmware