}

Isolated EC Probe Interface API Reference

Introduction

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

An electrically isolated I2C sensor device, a waterproof temperature sensor, and an electrical conductivity probe. It measures the conductivity of a solution and converts it into Siemens (S) total dissolved solids and salinity. The firmware allows for single or dual-point calibration with temperature compensation.

Characteristics

  • EC range: 0.1 - 12.88 mS/cm
  • Accuracy: ± 5%
  • Temperature range: -55 - 125 C
  • Interface: I2C
  • Current use: ~10mA peak, low idle current ~1mA
  • Voltage range: 3.3 - 5.0V

Connections

I2C Connections

If you use the Qwiic connector, it is keyed and can only be inserted one way.

  • Black = GND
  • Red = 3.3/5 V
  • Blue = SDA
  • Yellow = SCL

A 2.54mm through-hole header is available and it is also castellated to allow for attached to another board. The pins are as follows:

EC Probe Interface Master device
GND Ground connection
3.3/5v 3.3 - 5 V power source
SDA SDA
SCL SCL

EC Probe Connections

A BNC connector is used to connect the conductivity probe to the EC Probe Interface. Ensure the connector is fully inserted and the twist-lock is fully locked.

Probe Selection

Any 2-electrode probe with a BNC connector can be used.

Temperature Probe Connections

The temperature probe comes with a 3-wire connector that can only be connected one way.

I2C Bus Pull-ups

There only needs to be one device with active pull-up resistors. Each board comes with the resistors active. Several boards can typically be connected with active resistors, however if connection problems are present, choose one board to keep the resistors active and disable to rest.

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 pad 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.

solder_jumper

Getting Started

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

  • Arduino IDE: go to the library manager (Sketch / Include Library / Manage Libraries...) and search for Isolated EC Probe Interface.

  • PlatformIO: install the library using the library manager (PlatformIO / PlatformIO Home / Libraries) and search for Isolated EC Probe Interface.

  • Particle.io: search for Isolated EC Probe Interface in the Libraries section of the IDE.

  • Raspberry Pi: clone the GitHub repo. The library is located in the python/RaspberryPi directory. Have a look at the README for instructions. Be sure to read the section below for instructions.

  • Rust: Download/install/documentation for the crate

Raspberry Pi

Before you can begin, you will need to enable software I2C. The Pi's hardware I2C implementation has a clock-stretching bug that will prevent it from working reliably. For reliable communication, you need to start the I2C-GPIO system using the following commnads. From a terminal, type:

  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.

  3. ctrl + x to exit, y to save, and enter to confirm the filename.

  4. reboot

The shell Example

An interactive shell interface is provided and is a quick and easy way to get started using the device. You will find the equivalent commands in the code area below when applicable. Upload it to your device, start a serial terminal and you will get a > prompt where you can enter commands and receive a response like a terminal 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 recover it.

Class Initialization

For C++, these options are available in the begin method.

  • Raspberry Pi Python: You can optionally pass the I2C address and/or bus.
    • Default: ec = uFire_EC()
    • Custom I2C Address: ec = uFire_EC(address=0x4C)
    • I2C System Bus: ec = uFire_EC(i2c_bus=3)
    • I2C System Bus Address: ec = uFire_EC(i2c_bus=3, address=0x4C)
  • Rust: Always pass the I2C system bus, and I2C address.
    • Default: let mut ec = EcProbe::new("/dev/i2c-3", 0x3c);

If you are using a Raspberry Pi 4, it creates the I2C-GPIO device as i2c-7 rather than i2c-3 like a Raspberry Pi 3 does. So you'll need to start the class using this:

ec = uFire_EC(7)

Calibration

There are two options to calibrate the device; single or dual point.

Single Point

Benefits
  • only requires one point to calibrate
Disadvantages
  • less accurate
  • accuracy decreases as the farther away you get from the calibration point

Steps to calibrate

  1. Select a calibration solution in the middle of the expected range of measurements.
  2. reset the device to remove any previous calibration data.
  3. Submerge the probe in the calibration solution. Make sure there are no air bubbles on the probe's surface.
  4. Observe the values and wait for them to stabilize.
  5. Call calibrateProbe to perform the calibration.

After, you can use getCalibrateOffset to get the calibration data the device generated. As long as there is calibration data, it will be automatically used for subsequent measurements. setCalibrateOffset can be used to set a user-selected value.

Dual Point

Benefits
  • accurate over the low and high range of points
Disadvantages
  • requires two points to calibrate

Steps to calibrate

  1. Select a calibration solution near the low and high end of expected measurements.
  2. reset the device to remove any previous calibration data.
  3. Submerge the probe in the low calibration solution. Make sure there are no air bubbles on the probe's surface.
  4. Observe the values and wait for them to stabilize.
  5. Call calibrateProbeLow to perform the calibration.
  6. Repeat steps 3 - 4 for the high solution, then calling calibrateProbeHigh.
  7. The device will automatically begin to use the calibration data once the high and low points are determined.

After calibration, the calibration data is accesible as a pair of low/high points by calling getCalibrateHighReference/getCalibrateLowReference and getCalibrateLowReading/getCalibrateHighReading.

All four points can be set directly, without the device measuring anything, by calling setDualPointCalibration.

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

Conductivity naturally changes with temperature.

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 a standard formula which is implemented in the device's firmware. By default, 25 C is the temperature all measurements are compensated to.

To set the temperature used for compensation, call setTempConstant and pass the temperature to use.

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

Measurement Time

Each EC measurement takes 750 ms for version 2 devices and 500 ms for version 3. A temperature measurement takes 750ms.

Blocking Measurement Time

The library uses delay to wait for the device to finish taking the measurement. This can be configured by called setBlocking(false);. You can then continue work in your application whiling waiting. To update all the measured values, call readData

Troubleshooting

The most common issues are with calibration:

  • if you are getting erroneous values, call reset and see if the measurements return to a more reasonable value
  • make sure your measurement solution isn't out of range of the device

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].

Summary

Members Descriptions
class uFire_EC A test class.
class uFire_EC_JSON
class uFire_EC_MP

class uFire_EC {#classu_fire___e_c}

A test class.

A more elaborate class description.

uFire_EC Class

Summary

Members Descriptions
public float S EC in Siemens
public float mS Salinity EC in milli-Siemens
public long uS EC in micro-Siemens
public long raw
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 tempC Temperature in C
public float tempF Temperature in F
public bool begin(uint8_t address,TwoWire & wirePort) A normal member taking two arguments and returning an integer value.
public float measureEC(float temp,float temp_constant)
public float measureTemp()
public void setTemp(float temp_C)
public float calibrateProbe(float solutionEC,float tempC)
public float calibrateProbeLow(float solutionEC,float tempC)
public float calibrateProbeHigh(float solutionEC,float tempC)
public void setDualPointCalibration(float refLow,float refHigh,float readLow,float readHigh)
public void reset()
public void setTempConstant(float b)
public float getTempConstant()
public void setTempCoefficient(float tempCoef)
public float getTempCoefficient()
public float getCalibrateHighReference()
public float getCalibrateLowReference()
public float getCalibrateHighReading()
public float getCalibrateLowReading()
public void setCalibrateOffset(float offset)
public float getCalibrateOffset()
public uint8_t getVersion()
public uint8_t getFirmware()
public void setI2CAddress(uint8_t i2cAddress)
public bool connected()
public void writeEEPROM(uint8_t address,float value)
public float readEEPROM(uint8_t address)
public void setBlocking(bool)
public bool getBlocking()
public void readData()

Members

public float S {#classu_fire___e_c_1a09f3f8d3690baa52b821aaf471ef3f9e}

EC in Siemens

public float mS {#classu_fire___e_c_1a9794af675c73024a9064b530c949bafc}

Salinity EC in milli-Siemens

public long uS {#classu_fire___e_c_1ab51cc45b8253661d1820fa5acda2b995}

EC in micro-Siemens

public long raw {#classu_fire___e_c_1a5e055844b56dd7ce5aa56934f07aa47d}

public long PPM_500 {#classu_fire___e_c_1ad3d12244f884ecf5d1594dacda970f3c}

Parts per million using 500 as a multiplier

public long PPM_640 {#classu_fire___e_c_1ab7b446741a0800174e54538c3efe43de}

Parts per million using 640 as a multiplier

public long PPM_700 {#classu_fire___e_c_1ae853daf2b369f4eefa7430f9bea840fd}

Parts per million using 700 as a multiplier

public float salinityPSU {#classu_fire___e_c_1ac8f4d425c0b9d07ce300f4dbb3e9dce6}

Salinity measured practical salinity units

public float tempC {#classu_fire___e_c_1a91f4d1284d6965276ba83975b68302de}

Temperature in C

public float tempF {#classu_fire___e_c_1a65773cd8094f4de703bb888221cce9ae}

Temperature in F

public bool begin(uint8_t address,TwoWire & wirePort) {#classu_fire___e_c_1ae29894e0e97f3128714056a0223b7f49}

A normal member taking two arguments and returning an integer value.

Parameters

  • a an integer argument.

  • s a constant character pointer.

Returns

The test results

See also: QTstyle_Test(), ~QTstyle_Test(), testMeToo() and publicVar()

public float measureEC(float temp,float temp_constant) {#classu_fire___e_c_1a16134d666547d608f586b2c484bcde12}

public float measureTemp() {#classu_fire___e_c_1addf0516ed5a15eacd064a108e99f3b82}

public void setTemp(float temp_C) {#classu_fire___e_c_1a9fa16006f7af460fedc90f593e343063}

public float calibrateProbe(float solutionEC,float tempC) {#classu_fire___e_c_1a432018740cab65b37f00b84601b07edc}

public float calibrateProbeLow(float solutionEC,float tempC) {#classu_fire___e_c_1a36afdf9daf2a289f6a64e68b72c9429c}

public float calibrateProbeHigh(float solutionEC,float tempC) {#classu_fire___e_c_1a68733cc69c690e31b1b7e27a22a2a8d7}

public void setDualPointCalibration(float refLow,float refHigh,float readLow,float readHigh) {#classu_fire___e_c_1a6efb5980058f1b0ca968030f41c72f8d}

public void reset() {#classu_fire___e_c_1aabc19ae9f264c6e2ec15a3c6c1791fbc}

public void setTempConstant(float b) {#classu_fire___e_c_1a9097dbc7ec30617c33f343194831249e}

public float getTempConstant() {#classu_fire___e_c_1af33e01beb13df9dcef0704f41cc1fba3}

public void setTempCoefficient(float tempCoef) {#classu_fire___e_c_1a40bed1a812453e689d79b78eb379a323}

public float getTempCoefficient() {#classu_fire___e_c_1a1fa13ba6ea5d333d000ad2e07cd7a8e8}

public float getCalibrateHighReference() {#classu_fire___e_c_1a95035d13de8811e7b23cc6265e065732}

public float getCalibrateLowReference() {#classu_fire___e_c_1a394be731f3b959e95df159279879fb4c}

public float getCalibrateHighReading() {#classu_fire___e_c_1ad81ac68c703de6f10b5dc096dc9f2fec}

public float getCalibrateLowReading() {#classu_fire___e_c_1a9f5fd09c507b7e8b9b23bf7a5f147837}

public void setCalibrateOffset(float offset) {#classu_fire___e_c_1aa5057443f7daa9056ff48c4e15f36c76}

public float getCalibrateOffset() {#classu_fire___e_c_1aebae2378d5f5da7f9f7fc86af3be1c17}

public uint8_t getVersion() {#classu_fire___e_c_1ab6d9026f88bdd3a956c24d270c665fb7}

public uint8_t getFirmware() {#classu_fire___e_c_1a3645a1ac86afb0ebc97ecc4e45e41362}

public void setI2CAddress(uint8_t i2cAddress) {#classu_fire___e_c_1a875d21021629507328c4c6d65c961603}

public bool connected() {#classu_fire___e_c_1a71e2fc0418feddc52715864944554fc0}

public void writeEEPROM(uint8_t address,float value) {#classu_fire___e_c_1a96707d2e738a9108b0787be8817ff57f}

public float readEEPROM(uint8_t address) {#classu_fire___e_c_1ab8ff1acfd617fa1617c93d57f5e0fc9d}

public void setBlocking(bool) {#classu_fire___e_c_1a7f0eb5ab0688f83235780fe6a3ee82c6}

public bool getBlocking() {#classu_fire___e_c_1a5daa337a69f4ef014d78856e5ed708ad}

public void readData() {#classu_fire___e_c_1a7459d4b700a78c07a6d3358a72a3b531}

class uFire_EC_JSON {#classu_fire___e_c___j_s_o_n}

Summary

Members Descriptions
public float value
public inline uFire_EC_JSON()
public void begin(uFire_EC * ec)
public String processJSON(String json)

Members

public float value {#classu_fire___e_c___j_s_o_n_1a729353d4dd862aef0c1ed6b460c60f93}

public inline uFire_EC_JSON() {#classu_fire___e_c___j_s_o_n_1a4fc2ee785552bffc4e3cf7cc021fdb5b}

public void begin(uFire_EC * ec) {#classu_fire___e_c___j_s_o_n_1af1a828073cb645c861fc31287ccba284}

public String processJSON(String json) {#classu_fire___e_c___j_s_o_n_1a903f37ad6ddf453fea290900ae523aee}

class uFire_EC_MP {#classu_fire___e_c___m_p}

Summary

Members Descriptions
public float value
public inline uFire_EC_MP()
public void begin(uFire_EC * ec)
public String processMP(String json)

Members

public float value {#classu_fire___e_c___m_p_1a1756a6d81cbcd913d53e4ecb27ef4608}

public inline uFire_EC_MP() {#classu_fire___e_c___m_p_1afd783330acc1261e2781c9daed14efb8}

public void begin(uFire_EC * ec) {#classu_fire___e_c___m_p_1a5e9188811ae30eb3645f6f222f24e6af}

public String processMP(String json) {#classu_fire___e_c___m_p_1a8d7380d31afc258d43173667f3b4e7a0}

Generated by Moxygen