Make Your Own pH and Salinity Monitoring System

Make Your Own pH and Salinity Monitoring System © CC BY-NC

Real-time pH and salinity monitoring with LED indicators.

  • 30 respects

Components and supplies

Apps and online services

About this project

In this project, we will be making a pH and salinity/conductivity monitoring system with LED indicators. The pH and salinity sensors from Atlas Scientific are used. Operation is via I2C protocol and readings are displayed on the Arduino serial monitor.

The LEDs are turned on if the sensor readings go out of the predefined limits. In this case, the limits are as follows: If the conductivity reading goes over 500 μS/cm, the yellow LED will turn on; if the pH reading goes over 10, the red LED will turn on. The use of LEDs offers a demonstration of how sensor readings can be used to trigger other hardware. You can modify this project to include other EZO sensors such as the temperature (RTD), oxidation-reduction potential (ORP) and dissolved oxygen (DO).


  • Real-time pH and salinity readings.
  • Can be expanded to include more types of Atlas's sensors.
  • Ability to use sensor readings to control other hardware.
  • Minimum programming skills needed unless you plan on modifying the project.

Step 1: Pre- assembly Requirements

a) Calibrate the sensors. Each sensor has a unique calibration process. Refer to the following: pH calibration, salinity calibration. If you are using other sensors refer to their respective datasheet which can be found on the Atlas Scientific website.

b) Set sensors' protocol to I2C. Each sensor needs a unique I2C address. In accordance with the sample code for this project, the following addresses are used: pH sensor address is 99 and salinity sensor address is 100. For information on how to change between protocols and assign addresses, refer to this LINK.

The calibration and the switch to I2C MUST be done before implementing the sensors into this project.

Step 2: Assemble Hardware

Connect the hardware as shown in the schematic above.

You can use either an Arduino UNO or a STEMTera board. The STEMTera board was used in this project for its compact design where the Arduino is combined with the breadboard.

The 220Ω resistors limit the current to the LEDs, preventing them from blowing out.

The Inline Voltage Isolator isolates the pH circuit from the salinity circuit, thus protecting it from any electrical interference (noise) that may originate from the salinity sensor. For more information on isolators refer to this LINK.

Datasheets: EZO pH, EZO EC, Inline Voltage Isolator

Step 3: Load Program Onto Arduino

The code for this project makes use of a customized library and header file for the EZO circuits in I2C mode. You will have to add them to your Arduino IDE in order to use the code. The steps below include the process of making this addition to the IDE.

a) Download Ezo_I2c_lib, a zip folder from GitHub onto your computer.

b) On your computer, open the Arduino IDE (You can download the IDE from HERE if you do not have it). In the IDE, go to Sketch -> Include Library -> Add.ZIP Library -> Select the Ezo_I2c_lib folder you just downloaded. The appropriate files are now included.

c) Copy the code from pH_EC_led_indicator onto your IDE work panel. You can also access it from the Ezo_I2c_lib zip folder downloaded above.

d) Compile and upload the pH_EC_led_indicator code to your Arduino Uno or StemTera board.

e) In your IDE, go to Tools -> Serial Monitor or press Ctrl+Shift+M on your keyboard. The serial monitor will open. Set the baud rate to 9600 and select "Carriage return"

The pH and EC reading should now be outputting to the serial monitor.


  • The initial pH and EC of water are measured.
  • Some NaCl (salt) is added to the water, the conductivity reading rises and as soon as it crosses 500μS/cm the yellow LED turns on.
  • Then some pH UP solution is poured into the beaker, the pH increases and upon crossing 10 and the red LED turns on.
  • Finally, some pH DOWN solution is added and the pH decreases. When the reading is less than 10, the red LED turns off.


pH-salinity monitor codeC/C++
/*This code was written for the Instructable "MAKE YOUR OWN PH AND SALINITY MONITORING SYSTEM WITH LED INDICATORS" (Link:
and "Make Your Own pH and Salinity Monitoring System" (Link:
Testing was done using an Arduino UNO.
The code allows you to monitor in real-time, pH and EC. You can modify it to observe other parameters such as DO, temperature and ORP.  It works 
with Atlas Scientific's EZO circuits. The sensors must be calibrated and switched to I2C mode before using this code as it does not have the capability 
of allowing the user to send commands to the circuits. The readings of the sensors are displayed on the Arduino serial monitor. 
There are two LEDs which functions as a warning system. They are turned on when the readings go out of the defined limits.
These LEDs offer a simple demonstration of how you can utilize sensor readings to trigger other hardware.
Once you have uploaded the code to your Arduino, open the serial monitor, set the baud rate to 9600 and append "Carriage return"*/

#include <Ezo_i2c.h> //include the EZO I2C library (EZO_i2c.h is customized header file for Atlas Scientific's EZO circuits in I2C mode. Link:
#include <Wire.h>    //include arduinos i2c library

Ezo_board PH = Ezo_board(99, "PH");       //create a PH circuit object, who's address is 99 and name is "PH"
Ezo_board EC = Ezo_board(100, "EC");      //create an EC circuit object who's address is 100 and name is "EC"
int PH_led = 10;                           //define pin for pH led
int EC_led = 9;                           //define pin for EC led

bool reading_request_phase = true;        //selects our phase

uint32_t next_poll_time = 0;              //holds the next time we receive a response, in milliseconds
const unsigned int response_delay = 1000; //how long we wait to receive a response, in milliseconds

void setup() {
  Wire.begin();                           //start the I2C
  Serial.begin(9600);                     //start the serial communication to the computer at baud rate of 9600
  pinMode(PH_led, OUTPUT);                //set pin of pH led as output
  pinMode(EC_led, OUTPUT);                //set pin for EC led as output

void loop() {
  if (reading_request_phase) {                          //if were in the phase where we ask for a reading

    //send a read command. we use this command instead of PH.send_cmd("R");
    //to let the library know to parse the reading

    next_poll_time = millis() + response_delay;         //set when the response will arrive
    reading_request_phase = false;                      //switch to the receiving phase
  else {                                                //if were in the receiving phase
    if (millis() >= next_poll_time) {                   //and its time to get the response

      receive_reading(PH);                              //get the reading from the PH circuit
      if(PH.get_last_received_reading() > 10) {                       //test condition against pH reading
        digitalWrite(PH_led,HIGH);                      //if condition true, led on
        digitalWrite(PH_led,LOW);                       //if condition false, led off
      Serial.print("  ");

      receive_reading(EC);                              //get the reading from the EC circuit
      if (EC.get_last_received_reading() > 500.00) {                  //test condition against EC reading
        digitalWrite(EC_led,HIGH);                      //if condition true, led on
        digitalWrite(EC_led,LOW);                       //if condition false, led off

      reading_request_phase = true;                     //switch back to asking for readings

void receive_reading(Ezo_board &Sensor) {               // function to decode the reading after the read command was issued

  Serial.print(Sensor.get_name()); Serial.print(": ");  // print the name of the circuit getting the reading

  Sensor.receive_read_cmd();                                //get the response data and put it into the [Sensor].reading variable if successful

  switch (Sensor.get_error()) {                         //switch case based on what the response code is.
    case Ezo_board::SUCCESS:
      Serial.print(Sensor.get_last_received_reading());               //the command was successful, print the reading

    case Ezo_board::FAIL:
      Serial.print("Failed ");                          //means the command has failed.

    case Ezo_board::NOT_READY:
      Serial.print("Pending ");                         //the command has not yet been finished calculating.

    case Ezo_board::NO_DATA:
      Serial.print("No Data ");                         //the sensor has no data to send.


pH-salinity monitor wiring diagram
Ph ec wiring diagram qscta9nvth


Similar projects you might like

DIY pH Dosing Pump

by Atlas Scientific

  • 28 respects

Arduino pH Sensor Calibration

by Atlas Scientific

  • 10 respects

DIY Benchtop pH Meter

Project tutorial by Atlas Scientific

  • 25 respects

Water Quality Monitoring and Notification System

Project showcase by emmanuel ani

  • 170 respects

Solar-Powered Compost Monitoring System and Database

Project showcase by kkim20

  • 59 respects
Add projectSign up / Login