Serial monitor command input with code

Hello everyone. I'm working with a ph probe from DFRobot.
DFRobot code comes with a calibration option that is triggered, when an user inputs a command thru the monitor serial text box. An user needs to write enterph and press enter or send button in order to enter into calibration mode.

I have my arduino connected to a raspberry pi, where I have the main program running in python and when a user presses a button in there, I want to access it calibration mode in the arduino code.

So far I have my arduino reading and detecting thru serial when the button is pressed, but I can't figure out how to "simulate" the user writing the command in the text box from arduino serial monitor.

So basically, I would like the user to press calibrate ph button in my raspberry pi and that will trigger the "enterph" command in my arduino.

I tried different Serial.print but nothing seems to make arduino trigger that command.

I've been trying to find similar problems to mine and almost found it but they were talking about a different board instead of the raspberry and the commands wouldn't work for me.

This is the code I have so far in my arduino.

Thanks in advance and hopefully I was clear enough with my expplanation.

//
//
//
//
//



#include "DFRobot_PH.h"
#include <GravityTDS.h>     // For EC sensor
#include <OneWire.h>        // For water temp sensor DS18B20
#include <DallasTemperature.h>  // For water temp sensor DS18B20

const int TdsSensorPin = A0; // TDS sensor analog pin
const int watempsensor = 10;  // Water temperature sensor digital pin

// PH sensor
#define PH_PIN A1
float voltage,phValue;
DFRobot_PH ph;
// Ph sensor

// Water temp sensor begin
OneWire oneWire(watempsensor);
DallasTemperature wasensor(&oneWire);
float Celcius = 0;
//float Fahrenheit=0;
// Water temp sensor end

GravityTDS gravityTds;
float temperature = 0, ppm500 = 0, ec = 0, ppm700 = 0;
String r = "test";
int tempindexserial = 0;

void setup() {
  Serial.begin(115200);
  ph.begin();
  gravityTds.setPin(TdsSensorPin);
  gravityTds.setAref(5.0);       //reference voltage on ADC, default 5.0V on Arduino UNO
  gravityTds.setAdcRange(1024);  //1024 for 10bit ADC;4096 for 12bit ADC
  gravityTds.begin();           //initialization
  wasensor.begin();
}

void loop() {
  
 ecphread();


  
}

void ecphread() {
  float actualec = 0, actualph = 0;
  if (tempindexserial == 0){
     if(Serial.available()){         //From RPi to Arduino
      char tempchar = Serial.read();
      delay(50);
      //tempchar = Serial.read();
      r = "enterph\n";
      Serial.print(r);
      tempindexserial = 1;
      delay(50);
      } 
  }
  wasensor.requestTemperatures();
  Celcius = wasensor.getTempCByIndex(0);
  //Fahrenheit=wasensor.toFahrenheit(Celcius);
  temperature = Celcius;  //add your temperature sensor and read it chnage to Fahrenheit if prefer F
  gravityTds.setTemperature(temperature);  // set the temperature and execute temperature compensation
  gravityTds.update();  //sample and calculate
  ppm500 = gravityTds.getTdsValue();  // then get the value
  ec = gravityTds.getTdsValue() / 500; // ec value
  ppm700 = ec * 700;                  // ppm700 value
  static unsigned long timepoint = millis();
    if(millis()-timepoint>1000U){                  //time interval: 1s
        timepoint = millis();
        //temperature = readTemperature();         // read your temperature sensor to execute temperature compensation
        voltage = analogRead(PH_PIN)/1024.0*5000;  // read the voltage
        phValue = ph.readPH(voltage,temperature);  // convert voltage to pH with temperature compensation
    }
    ph.calibration(voltage,temperature);           // calibration process by Serail CMD

  actualec = ec;
  actualph = phValue;
  Serial.print("E");
  Serial.println(actualec);
  Serial.print("P");
  Serial.println(actualph);
  Serial.print("W");
  Serial.println(temperature);  



}

Please post the sketch that does the calibration when user enters enterph in the Serial monitor

In order to do what you want the Pi has to send that command over a Serial link to the Arduino instead of it coming from the Serial monitor

Hello, thanks for the quick reply.
I see. At the moment I'm only sending a simple 'a' instead of the command itself from the pi.

This is the .cpp that comes with the DFRobot code

/*
 * file DFRobot_PH.cpp * @ https://github.com/DFRobot/DFRobot_PH
 *
 * Arduino library for Gravity: Analog pH Sensor / Meter Kit V2, SKU: SEN0161-V2
 *
 * Copyright   [DFRobot](http://www.dfrobot.com), 2018
 * Copyright   GNU Lesser General Public License
 *
 * version  V1.0
 * date  2018-04
 */


#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

#include "DFRobot_PH.h"
#include <EEPROM.h>

#define EEPROM_write(address, p) {int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) EEPROM.write(address+i, pp[i]);}
#define EEPROM_read(address, p)  {int i = 0; byte *pp = (byte*)&(p);for(; i < sizeof(p); i++) pp[i]=EEPROM.read(address+i);}

#define PHVALUEADDR 0x00    //the start address of the pH calibration parameters stored in the EEPROM


DFRobot_PH::DFRobot_PH()
{
    this->_temperature    = 25.0;
    this->_phValue        = 7.0;
    this->_acidVoltage    = 2032.44;    //buffer solution 4.0 at 25C
    this->_neutralVoltage = 1500.0;     //buffer solution 7.0 at 25C
    this->_voltage        = 1500.0;
}

DFRobot_PH::~DFRobot_PH()
{

}

void DFRobot_PH::begin()
{
    EEPROM_read(PHVALUEADDR, this->_neutralVoltage);  //load the neutral (pH = 7.0)voltage of the pH board from the EEPROM
    Serial.print("_neutralVoltage:");
    Serial.println(this->_neutralVoltage);
    if(EEPROM.read(PHVALUEADDR)==0xFF && EEPROM.read(PHVALUEADDR+1)==0xFF && EEPROM.read(PHVALUEADDR+2)==0xFF && EEPROM.read(PHVALUEADDR+3)==0xFF){
        this->_neutralVoltage = 1500.0;  // new EEPROM, write typical voltage
        EEPROM_write(PHVALUEADDR, this->_neutralVoltage);
    }
    EEPROM_read(PHVALUEADDR+4, this->_acidVoltage);//load the acid (pH = 4.0) voltage of the pH board from the EEPROM
    Serial.print("_acidVoltage:");
    Serial.println(this->_acidVoltage);
    if(EEPROM.read(PHVALUEADDR+4)==0xFF && EEPROM.read(PHVALUEADDR+5)==0xFF && EEPROM.read(PHVALUEADDR+6)==0xFF && EEPROM.read(PHVALUEADDR+7)==0xFF){
        this->_acidVoltage = 2032.44;  // new EEPROM, write typical voltage
        EEPROM_write(PHVALUEADDR+4, this->_acidVoltage);
    }
}

float DFRobot_PH::readPH(float voltage, float temperature)
{
    float slope = (7.0-4.0)/((this->_neutralVoltage-1500.0)/3.0 - (this->_acidVoltage-1500.0)/3.0);  // two point: (_neutralVoltage,7.0),(_acidVoltage,4.0)
    float intercept =  7.0 - slope*(this->_neutralVoltage-1500.0)/3.0;
    //Serial.print("slope:");
    //Serial.print(slope);
    //Serial.print(",intercept:");
    //Serial.println(intercept);
    this->_phValue = slope*(voltage-1500.0)/3.0+intercept;  //y = k*x + b
    return _phValue;
}


void DFRobot_PH::calibration(float voltage, float temperature,char* cmd)
{
    this->_voltage = voltage;
    this->_temperature = temperature;
    strupr(cmd);
    phCalibration(cmdParse(cmd));  // if received Serial CMD from the serial monitor, enter into the calibration mode
}

void DFRobot_PH::calibration(float voltage, float temperature)
{
    this->_voltage = voltage;
    this->_temperature = temperature;
    if(cmdSerialDataAvailable() > 0){
        phCalibration(cmdParse());  // if received Serial CMD from the serial monitor, enter into the calibration mode
    }
}

boolean DFRobot_PH::cmdSerialDataAvailable()
{
    char cmdReceivedChar;
    static unsigned long cmdReceivedTimeOut = millis();
    while(Serial.available()>0){
        if(millis() - cmdReceivedTimeOut > 500U){
            this->_cmdReceivedBufferIndex = 0;
            memset(this->_cmdReceivedBuffer,0,(ReceivedBufferLength));
        }
        cmdReceivedTimeOut = millis();
        cmdReceivedChar = Serial.read();
        if (cmdReceivedChar == '\n' || this->_cmdReceivedBufferIndex==ReceivedBufferLength-1){
            this->_cmdReceivedBufferIndex = 0;
            strupr(this->_cmdReceivedBuffer);
            return true;
        }else{
            this->_cmdReceivedBuffer[this->_cmdReceivedBufferIndex] = cmdReceivedChar;
            this->_cmdReceivedBufferIndex++;
        }
    }
    return false;
}

byte DFRobot_PH::cmdParse(const char* cmd)
{
    byte modeIndex = 0;
    if(strstr(cmd, "ENTERPH")      != NULL){
        modeIndex = 1;
    }else if(strstr(cmd, "EXITPH") != NULL){
        modeIndex = 3;
    }else if(strstr(cmd, "CALPH")  != NULL){
        modeIndex = 2;
    }
    return modeIndex;
}

byte DFRobot_PH::cmdParse()
{
    byte modeIndex = 0;
    if(strstr(this->_cmdReceivedBuffer, "ENTERPH")      != NULL){
        modeIndex = 1;
    }else if(strstr(this->_cmdReceivedBuffer, "EXITPH") != NULL){
        modeIndex = 3;
    }else if(strstr(this->_cmdReceivedBuffer, "CALPH")  != NULL){
        modeIndex = 2;
    }
    return modeIndex;
}

void DFRobot_PH::phCalibration(byte mode)
{
    char *receivedBufferPtr;
    static boolean phCalibrationFinish  = 0;
    static boolean enterCalibrationFlag = 0;
    switch(mode){
        case 0:
        if(enterCalibrationFlag){
            Serial.println(F(">>>Command Error<<<"));
        }
        break;

        case 1:
        enterCalibrationFlag = 1;
        phCalibrationFinish  = 0;
        Serial.println();
        Serial.println(F(">>>Enter PH Calibration Mode<<<"));
        Serial.println(F(">>>Please put the probe into the 4.0 or 7.0 standard buffer solution<<<"));
        Serial.println();
        break;

        case 2:
        if(enterCalibrationFlag){
            if((this->_voltage>1322)&&(this->_voltage<1678)){        // buffer solution:7.0{
                Serial.println();
                Serial.print(F(">>>Buffer Solution:7.0"));
                this->_neutralVoltage =  this->_voltage;
                Serial.println(F(",Send EXITPH to Save and Exit<<<"));
                Serial.println();
                phCalibrationFinish = 1;
            }else if((this->_voltage>1854)&&(this->_voltage<2210)){  //buffer solution:4.0
                Serial.println();
                Serial.print(F(">>>Buffer Solution:4.0"));
                this->_acidVoltage =  this->_voltage;
                Serial.println(F(",Send EXITPH to Save and Exit<<<")); 
                Serial.println();
                phCalibrationFinish = 1;
            }else{
                Serial.println();
                Serial.print(F(">>>Buffer Solution Error Try Again<<<"));
                Serial.println();                                    // not buffer solution or faulty operation
                phCalibrationFinish = 0;
            }
        }
        break;

        case 3:
        if(enterCalibrationFlag){
            Serial.println();
            if(phCalibrationFinish){
                if((this->_voltage>1322)&&(this->_voltage<1678)){
                    EEPROM_write(PHVALUEADDR, this->_neutralVoltage);
                }else if((this->_voltage>1854)&&(this->_voltage<2210)){
                    EEPROM_write(PHVALUEADDR+4, this->_acidVoltage);
                }
                Serial.print(F(">>>Calibration Successful"));
            }else{
                Serial.print(F(">>>Calibration Failed"));
            }
            Serial.println(F(",Exit PH Calibration Mode<<<"));
            Serial.println();
            phCalibrationFinish  = 0;
            enterCalibrationFlag = 0;
        }
        break;
    }
}

And this is the library that also comes with the code jus in case you also need it.

/*
 * file DFRobot_PH.h * @ https://github.com/DFRobot/DFRobot_PH
 *
 * Arduino library for Gravity: Analog pH Sensor / Meter Kit V2, SKU: SEN0161-V2
 *
 * Copyright   [DFRobot](http://www.dfrobot.com), 2018
 * Copyright   GNU Lesser General Public License
 *
 * version  V1.0
 * date  2018-04
 */

#ifndef _DFROBOT_PH_H_
#define _DFROBOT_PH_H_

#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

#define ReceivedBufferLength 10  //length of the Serial CMD buffer

class DFRobot_PH
{
public:
    DFRobot_PH();
    ~DFRobot_PH();
    void    calibration(float voltage, float temperature,char* cmd);  //calibration by Serial CMD
    void    calibration(float voltage, float temperature);
    float   readPH(float voltage, float temperature); // voltage to pH value, with temperature compensation
    void    begin();   //initialization

private:
    float  _phValue;
    float  _acidVoltage;
    float  _neutralVoltage;
    float  _voltage;
    float  _temperature;

    char   _cmdReceivedBuffer[ReceivedBufferLength];  //store the Serial CMD
    byte   _cmdReceivedBufferIndex;

private:
    boolean cmdSerialDataAvailable();
    void    phCalibration(byte mode); // calibration process, wirte key parameters to EEPROM
    byte    cmdParse(const char* cmd);
    byte    cmdParse();
};

#endif

Which pins on the Arduino are you using to communicate with the Pi ?

Hi,
Can you post a circuit diagram of your project, showing the controller inter-connections?

What model Arduino are you using?

Thanks.. Tom... :smiley: :+1: :coffee: :australia:

Hello, I have them connected thru usb cable.

Hello Tom, is this what you are looking for?
I’m using a copy of arduinoUno.
They only allow me to put one picture at a time.

I have data tds connected to A0, data for ph to A1 and data for temperature to pin 10.

Everything connected to the pi thru usb cable.

Not sure this will help, but this is the one I found that they were looking to do the same thing but with different hardware. They got it figure out.

Hello guys, I found the solution. After @UKHeliBob mentioned I needed to send the command directly from the pi. I tried to just do that and send a string with the full command including \n at the end of it and it triggered calibration mode.

So basically I send this from my pi

sensors.write(b"enterph\n")

And then I read a string from my arduino like this,

r = Serial.readString();

That triggered calibration mode as if an user did the input in the serial monitor.

Thanks again for your help.

Francisco