Sedning a "Serial Monitor" command via Nextion

Hello friends.

I try to get the example from the lib to work: GitHub - GreenPonik/DFRobot_ESP_PH_BY_GREENPONIK: Read PH on ESP32 by using Gravity: Analog pH Sensor / Meter Kit V2, SKU:SEN0161-V2

I am using an ESP32 and a Nextion Display.

The exampleCode:

/*
 * file DFRobot_ESP_PH_BY_GREENPONIK.ino
 * @ https://github.com/GreenPonik/DFRobot_ESP_PH_BY_GREENPONIK
 *
 * This is the sample code for Gravity: Analog pH Sensor / Meter Kit V2, SKU:SEN0161-V2
 * In order to guarantee precision, a temperature sensor such as DS18B20 is needed, to execute automatic temperature compensation.
 * You can send commands in the serial monitor to execute the calibration.
 * Serial Commands:
 *   enterph -> enter the calibration mode
 *   calph   -> calibrate with the standard buffer solution, two buffer solutions(4.0 and 7.0) will be automaticlly recognized
 *   exitph  -> save the calibrated parameters and exit from calibration mode
 * 
 * Based on the @ https://github.com/DFRobot/DFRobot_PH
 * Copyright   [DFRobot](http://www.dfrobot.com), 2018
 * Copyright   GNU Lesser General Public License
 *
 * ##################################################
 * ##################################################
 * ########## Fork on github by GreenPonik ##########
 * ############# ONLY ESP COMPATIBLE ################
 * ##################################################
 * ##################################################
 * 
 * version  V1.1
 * date  2019-06
 */

#include "DFRobot_ESP_PH.h"
#include "EEPROM.h"

DFRobot_ESP_PH ph;
#define ESPADC 4096.0   //the esp Analog Digital Convertion value
#define ESPVOLTAGE 3300 //the esp voltage supply value
#define PH_PIN 35		//the esp gpio data pin number
float voltage, phValue, temperature = 25;

void setup()
{
	Serial.begin(115200);
	EEPROM.begin(32);//needed to permit storage of calibration value in eeprom
	ph.begin();
}

void loop()
{
	static unsigned long timepoint = millis();
	if (millis() - timepoint > 1000U) //time interval: 1s
	{
		timepoint = millis();
		//voltage = rawPinValue / esp32ADC * esp32Vin
		voltage = analogRead(PH_PIN) / ESPADC * ESPVOLTAGE; // read the voltage
		Serial.print("voltage:");
		Serial.println(voltage, 4);
		
		//temperature = readTemperature();  // read your temperature sensor to execute temperature compensation
		Serial.print("temperature:");
		Serial.print(temperature, 1);
		Serial.println("^C");

		phValue = ph.readPH(voltage, temperature); // convert voltage to pH with temperature compensation
		Serial.print("pH:");
		Serial.println(phValue, 4);
	}
	ph.calibration(voltage, temperature); // calibration process by Serail CMD
}

float readTemperature()
{
	//add your code here to get the temperature from your temperature sensor
}

My problem is now that the code waits (to start the calibration)for a Serial Command.
From what i know, u can send Serial commands via nextion via print “command”.

So i made a button that does that. So what i found out now.

When i push the button i see this in the Serialmonitor:[1073478928:11,6,b2]. Nothing happens.

BUT!

when i push the button fast enouth, sometimes!, the codes jumps into the calibrationmode and gives me that in my Serialmonitor: >>>Enter PH Calibration Mode<<<
>>>Please put the probe into the 4.0 or 7.0 standard buffer solution<<<. So exactly that what i would expected.

So what now? Does the Nextion sends the command to fast or to slow? i am kinda confuces.

What i found out. I looked around in the cpp file of the lib and found this:

boolean DFRobot_ESP_PH::cmdSerialDataAvailable()
{
    char cmdReceivedChar;
    static unsigned long cmdReceivedTimeOut = millis();
    while (Serial2.available() > 0)
    {
        if (millis() - cmdReceivedTimeOut > 500U)
        {
            this->_cmdReceivedBufferIndex = 0;
            memset(this->_cmdReceivedBuffer, 0, (ReceivedBufferLength));
        }
        cmdReceivedTimeOut = millis();
        cmdReceivedChar = Serial2.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;
}

when i changes the 500U to something like 20U, it wasnt possible for me (even through pushing fast the button) to enter the calibration.

Anyone ideas?

Thank you

I don't know the ESP32, so what I say here might be wrong. I only see one Serial.begin in your code, I'm guessing this is for the serial monitor. Where is the Serial.begin for the Nextion?

I don't see anything in your code that communicates with a Nextion by any means I am aware of.

I don't know what you mean by 'Sending a "Serial Monitor" command via Nextion', to me 'sending via' something suggests whatever you are sending goes through the something, so 'sending via Nextion' suggests you send whatever the command is to the Nextion and the Nextion sends it to something else. I think that's unlikely to be what you meant, so please clarify.

I suggest you read my tutorial 'using Nextion displays with Ardino' and learn how to interface with a Nextion. Note that there's more than one way to do it, my methods don't use any Nextion libraries.

Hi
If you want to start using Nextion displays you must read at least the two following tutorials.

Using Nextion displays with Arduino

Tutorial on how to write code with Nextion and Arduino

At the second one there is a small sample of code on how to send commands via serial “How to send values and store them on Arduino.”

How to send values and store them on Arduino.

  1. As I have seen, you don’t have established a serial connection with Nextion and I am sure for this, because Nextion’s default Baud rate is 9600 and you start the Serial to 115200 <Serial.begin(115200);>

You had better leave the 115200 on the code for the esp32 in case it is used somewhere else and change the baud rate on Nextion following this:

How to initialize Nextion’s Serial baud rate:

  1. After that, you must create a floating numeric text component on a Nextion’s page with the Nextion Editor for sending the values from the PH
    In the above link you can find and this:
    How to change components’ attributes at Nextion from Arduino:

The text box should have the name t0 , if it is the first text box that you create at Nextion’s page
and you must add a command for sending the PH value to the text box after this piece of your code

phValue = ph.readPH(voltage, temperature); // convert voltage to pH with temperature compensation
 Serial.print("pH:");
 Serial.println(phValue, 4);

Add this

                Serial.print("t1.txt=\"");
                Serial.print(phValue);
                Serial.print("\"");
                Serial.print("\xFF\xFF\xFF"); // nextion ending command
  1. Now, you have to make 3 buttons for sending the three commands for calibrating the sensor.
    The 3 commands are written in the begin of your code
* This is the sample code for Gravity: Analog pH Sensor / Meter Kit V2, SKU:SEN0161-V2
 * In order to guarantee precision, a temperature sensor such as DS18B20 is needed, to execute automatic temperature compensation.
 * You can send commands in the serial monitor to execute the calibration.
 * Serial Commands:
 *   enterph -> enter the calibration mode
 *   calph   -> calibrate with the standard buffer solution, two buffer solutions(4.0 and 7.0) will be automaticlly recognized
 *   exitph  -> save the calibrated parameters and exit from calibration mode

If you write those commands to your serial port monitor software you are going to start the calibration of the sensor. Try it first from your serial port communication software because as I have seen in the library’s code from the file <DFRobot_ESP_PH.cpp>. The library waits the commands in capital letters

byte DFRobot_ESP_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;

After making the 3 buttons on Nextion’s page with HMI Editor,
write to each one’s < Touch Press Event > the command that you want to sent over Serial with this:

<print “ENTERPH”>
<print “EXITPH”>
<print “CALPH”>
NOTE: capital letters or small caps matter, try both. Do not check the box on the buttons Events.

Have in mind that esp32 has 3 serial Ports and maybe you must define a new Serial to communicate with Nextion separately from the first Serial RX0, TX0

ESP32 DevKit ESP32-WROOM GPIO Pinout

And

Also note that when all this is done, you must chance the library’s massages to be sent on Nextion’s format.

 Serial.println(F(">>>Enter PH Calibration Mode<<<"));
        Serial.println(F(">>>Please put the probe into the 4.0 or 7.0 standard buffer solution<<<"));

I believe that the baud rate of Nextion and esp32 is different and this is the problem you have to deal with.
Or the code on esp32 sends to much data that is not formatted for Nextion.
I am sure that the speed that you pressed the button doesn’t effect anything.

Good luck with your project and I hope this information helps you.

Thank you all very much your help. I realy apriciate the help.

I am still struggling with my problem.

How far i am: I created a button in my Nextion, that sends <print “ENTERPH”>

My code right now: (I know its not the best option, but till now i am using the NEXTION lib. But i am pretty sure my problem isnt related to the lib

#include "RTClib.h"
#include <Arduino.h>
#include <Nextion.h>
#include "DFRobot_ESP_PH.h"
#include <EEPROM.h>

DFRobot_ESP_PH ph;
#define ESPADC 4096.0   //the esp Analog Digital Convertion value
#define ESPVOLTAGE 3300 //the esp voltage supply value
#define PH_PIN 32		//the esp gpio data pin number
float voltage, phValue, temperature = 25;

NexButton measureIntSave              = NexButton(11, 6, "b2");

void measureIntSavePopCallback(void *ptr);

NexTouch *nex_listen_list[] =
{
  &measureIntSave,
  NULL
};

void measureIntSavePopCallback(void *ptr)
{

}

void setup()
{
	  nexInit();
	Serial2.begin(9800);
  Serial.begin(9600);
	EEPROM.begin(32);//needed to permit storage of calibration value in eeprom
	ph.begin();
}

void loop()
{
	static unsigned long timepoint = millis();
	if (millis() - timepoint > 1000U) //time interval: 1s
	{
		timepoint = millis();
		//voltage = rawPinValue / esp32ADC * esp32Vin
		voltage = analogRead(PH_PIN); // ESPADC * ESPVOLTAGE; // read the voltage
		Serial.print("voltage:");
		Serial.println(voltage, 4);

		//temperature = readTemperature();  // read your temperature sensor to execute temperature compensation
		//Serial.print("temperature:");
		//Serial.print(temperature, 1);
		//Serial.println("^C");

		phValue = ph.readPH(voltage, temperature); // convert voltage to pH with temperature compensation
		//Serial.print("pH:");
		//Serial.println(phValue, 4);
	}
	nexLoop(nex_listen_list);
	ph.calibration(voltage, temperature); // calibration process by Serail CMD
}

float readTemperature()
{
	//add your code here to get the temperature from your temperature sensor
}

My Serialconnection between my ESP32 and Nextion is Serial2.

I also changed the code that is listening it a Serial command is comming in the DFRobot.cpp to the right Serial port (Serial2):

boolean DFRobot_ESP_PH::cmdSerialDataAvailable()
{
    char cmdReceivedChar;
    static unsigned long cmdReceivedTimeOut = millis();
    while (Serial2.available() > 0)
    {
        if (millis() - cmdReceivedTimeOut > 500U)
        {
            this->_cmdReceivedBufferIndex = 0;
            memset(this->_cmdReceivedBuffer, 0, (ReceivedBufferLength));
        }
        cmdReceivedTimeOut = millis();
        cmdReceivedChar = Serial2.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;
}

The problem ist still: When i push the button, the “calibration” does not always start. Only sometimes.
I dont get it what causes the problem. I cant see any patterns.

Any proposals what i could try to find out whats the root of the problem?

In my opinion there could be two candidates. 1: the baudrate
2: cmdSerialDataAvailable()

but i dont know what to do

thank you

An obervation i made: My button is a touch press event.
I can trigger the start of the calibration by simply doing a "doubleclick (like on the PC when u open a file) on my Nextion button. The doubletap(click) works everytime. Strange..

But i still not see the problem

Hello Manuel,

My code right now: (I know its not the best option, but till now i am using the NEXTION lib. But i am pretty sure my problem isn't related to the lib

I don't use or know about the libraries, so the only help I can offer is if you want to use them have a look at Ray Livingston's versions of the Nextion libraries, he has fixed many of the bugs and knows how to use them
Ray Livingston's libraries

The problem with using the libraries is not just the libraries but who can help. If you use my methods I can help, if you use @Seithan's methods no doubt he can help. Ray has not, so far, chipped in with any advice here yet, but when it comes to the libraries he seems to be the expert on here.

@Manuel_o good morning.
As you have understated no - one in here uses library's for Nextion, the problems that can cause are bigger than any good.
You never know how the library can react.
You have a very small and easy project to manage and you don't need the hole mess of the library.

there is no double click mode in Nextion and in any library
take a look at the baud rate, i think that 9800 is not compatible value

nexInit();
	Serial2.begin(9800);
  Serial.begin(9600);

and maybe this is more valid

#define RXD2 16
#define TXD2 17
Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);

If I were you, i will remove the Nextion Library.
make a text box (t1.txt) and go to the code where the PH is Serial printed and add

                Serial2.print("t1.txt=\"");
                Serial2.print(phValue);
                Serial2.print("\"");
                Serial2.print("\xFF\xFF\xFF"); // nextion ending command

make a second text box t2.txt go to the code that send the messages with serial.print
and add

                 Serial2.print("t2.txt=\">>>Calibration Successful\"");                       
                 Serial2.print("\xFF\xFF\xFF"); // nextion ending command

that for display the messages on Nextion

Thank you again for the kind help.

Update so far:

I removed the Nextion lib
I added the 2 text boxes in my Nextion
I added the write baudrate to my Serial2 like you have recommended it:
I added the seding commands to the 2 textboxes.
I have a button that sends the command <<print “ENTERPH”>> in the tourch press event and
“Send Component ID” is unchecked so far

Here is the main.cpp

#include "RTClib.h"
#include <Arduino.h>
//#include <Nextion.h>
#include "DFRobot_ESP_PH.h"
#include <EEPROM.h>

DFRobot_ESP_PH ph;
#define ESPADC 4096.0   //the esp Analog Digital Convertion value
#define ESPVOLTAGE 3300 //the esp voltage supply value
#define PH_PIN 32 //the esp gpio data pin number
#define RXD2 16
#define TXD2 17
float voltage, phValue, temperature = 25;

//NexButton measureIntSave              = NexButton(11, 6, "b2");

//void measureIntSavePushCallback(void *ptr);
/*
NexTouch *nex_listen_list[] =
{
  &measureIntSave,
  NULL
};

void measureIntSavePushCallback(void *ptr)
{

}*/

void setup()
{
 // nexInit();
 Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);
  Serial.begin(9600);
 EEPROM.begin(32);//needed to permit storage of calibration value in eeprom
 ph.begin();
  //measureIntSave.attachPush(measureIntSavePushCallback);
}

void loop()
{
 static unsigned long timepoint = millis();
 if (millis() - timepoint > 1000U) //time interval: 1s
 {
 timepoint = millis();
 //voltage = rawPinValue / esp32ADC * esp32Vin
 voltage = analogRead(PH_PIN); // ESPADC * ESPVOLTAGE; // read the voltage
 //Serial.print("voltage:");
 //Serial.println(voltage, 4);

 //temperature = readTemperature();  // read your temperature sensor to execute temperature compensation
 //Serial.print("temperature:");
 //Serial.print(temperature, 1);
 //Serial.println("^C");

 //Serial.print("pH:");
 //Serial.println(phValue, 4);
      phValue = ph.readPH(voltage, temperature); // convert voltage to pH with temperature compensation
 }

      ph.calibration(voltage, temperature); // calibration process by Serail CMD
 //nexLoop(nex_listen_list);
}

float readTemperature()
{
 //add your code here to get the temperature from your temperature sensor
}

In the DFRobot.cpp i added the sedning commands that you recommended

My problem is unfortunely still there. When i push the button, nothing happens. When i push the button fast after another, the massage appears.

patterns of the problem i noticed (very strange).

First:When i change the (millis() - cmdReceivedTimeOut > 500U) value of the function boolean DFRobot_ESP_PH::cmdSerialDataAvailable() i can somehow manipulate the “timewindow” of how fast i have to push the buttons after another to get the message. When i increace the value from 500U to lets say 1500U i have more time between the multiple presses on the button to get the message

Second: I have done an experiment: I “modified” my Nextion command of the button to: print “ENTERPH”
print “ENTERPH”

So, sendingt the command double. The outcome was, that it now kinda works. When i push the button ONCE it shows the message. But not always. 8 times out of 10 it works and starts the calibration.

But this cant be the solution. Sedning the command twice. I wanna understand what causes the strange behavior.

I hope this hints and patterns of the behavior gives u guys an idea what causes this problem

thank you

Hello Manuel_o,

As you were modifying your project, I was also “playing” with your project, because I find it really interesting. In that time, I found out that the DF library waits for the newline character < \n > and uses it for the end command.

So, you must send a < print “ENTERPH” > followed by < printh 0A >.

Sorry that I din’t tell you earlier, but I was working on something. :frowning:

Hello Manuel_o,

I made some changes to both DFRobot_ESP_PH.cpp and DFRobot_ESP_PH_BY_GREENPONIK.ino . I also created a .HMI file to monitor and send commands for the PH meter.

If it is easy for you, try to test them, because I don’t have the equipment to do so(esp32, PH meter).

The .HMI file is for a 3.5" screen.
I kept the Serial to use it through USB and I have added a Serial2, two pins (RXD2 at 16 and TXD2 at 17).

I am curious to see if this is working.

DFRobot_ESP_PH_SEITHAN_mod.cpp (10.9 KB)

DFRobot_ESP_PH_BY_GREENPONIK_SEITHAN_mod.ino (3.33 KB)

PH_SEITHAN.zip (7.4 KB)

wow thank you so much time for your help and time.

In 2 days will my new calirbate solutions arive. I will test your setup then and let you know the outcome=)

One question comes still up.

When my Nextion-button sends this:
print "ENTERPH"
print "ENTERPH"
it works...

but
print "ENTERPH"
printh OA

doesnt work. Only the "doubel-fast-click" on the button starts the calibration

Any idea?

Thank you so much

Hello Seithan

Sorry to bother you again. Since you have looked into the DFRobot lib.

In this function:

float DFRobot_ESP_PH::readPH(float voltage)
{
    // Serial.print("_neutraVoltage:");
    // Serial.print(this->_neutralVoltage);
    // Serial.print(", _acidVoltage:");
    // Serial.print(this->_acidVoltage);
    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
    Serial.print("[readPH]... phValue ");
    Serial.println(this->_phValue);
    return this->_phValue;
}

Do you have an idea why there is this 1500/3? It doesnt make sense to me?

thank you

best regards

#define PH_8_VOLTAGE 1122
#define PH_6_VOLTAGE 1478
#define PH_5_VOLTAGE 1654
#define PH_3_VOLTAGE 2010


 this->_neutralVoltage = 1500.0; //buffer solution 7.0 at 25C

Output Voltage: 0~3.0V from
https://www.dfrobot.com/product-1782.html

A quick answer to this is a mathematical equation between the two ranges of sensors' output voltage (0 - 3V) and the voltage range of the analog read (usually, 0 - 5V) or as it is defined in some places in the library, 0 - 5000 mV.

All this is done, so we can get values from 0 - 14 for the Ph range when analog read voltage is between 0 - 5V.

Do not worry about that. :slight_smile:

Hello Seithan!

Just wanna let you know, that your scetch and HMI for ph measuring works perfectly=)

Keep up with the good work

Thank you

Hello Manuel,

I am happy to hear that my help has paid off and the project is working. I am thinking to fork the modyfied files to GitHub under the DFRobot_ESP_PH_BY_GREENPONIK, in order other people can find a version for Nextion.

Thank you for your kind words and for testing the files.

My compensation for my work is when I see the karma points on my profile increasing.

Sincerely,
-Thanasis Seitanis