Hi there, I am quite new to Arduino and have had some success modifying my sketch from reading the various documents.
I am working with the DF Robot PH sensor sketch, the sketch takes commands from the serial monitor to start calibration for example "enterph", "calph" and "exitph". I have been able to set up MQTT subscribe/publish without any issues to get the data to home assistant. What i would like to do is sent the "enterph" via MQTT to the esp32 to start the calibration.
Is there a way to just take the MQTT message and write "enterph" to the command so the library part starts the calibration or do i need something more complex like writing to a byte that the cpp then reads?
The main sketch code is below.
#include <WiFiClient.h>
#include <WiFiServer.h>
#include <WiFiUdp.h>
/*
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
MQTT Publish
"Greenhouse/Water temperature" -> this is the message topic for water temperature
"Greenhouse/Water PH" -> this is the message topic for water PH
MQTT Subscribe
"ESP32/Output"
version V1.0 Working
date 22.06.2023
*/
#include "DFRobot_ESP_PH.h"
#include "EEPROM.h"
#include <OneWire.h>
#include <DallasTemperature.h>
#include <PubSubClient.h>
#include "WiFi.h"
#include "DHT.h"
String command;
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
#define DHTPIN 26 // Digital pin connected to the DHT sensor
#define DHTTYPE DHT11 // DHT 11
float voltage, phValue, temperature = 25;
DHT dht(DHTPIN, DHTTYPE);
#define SENSOR_PIN 25 // ESP32 pin GIOP25 connected to DS18B20 sensor's DATA pin
OneWire oneWire(SENSOR_PIN);
DallasTemperature DS18B20(&oneWire);
float tempC; // temperature in Celsius
const char* ssid = "secret";
const char* password = "secret";
const char* mqtt_server = "192.168.2.160";
WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;
// Variables to hold sensor readings
float temp;
float hum;
void setup() {
Serial.begin(115200);
//EEPROM.begin(32);//needed to permit storage of calibration value in eeprom
ph.begin();
DS18B20.begin();
setup_wifi();
//set up the MQTT connection
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
while (!client.connected()) {
String client_id = "esp32-client-";
client_id += String(WiFi.macAddress());
Serial.printf("The client %s is connecting to the broker\n", client_id.c_str());
if (client.connect(client_id.c_str(), "homeassistant", "vae6OoGh0aequaisohj2au5yey3exiey1im0sei0eih5keengethooY6ap5uC4ee")) {
client.publish("outTopic", "hello world");
client.subscribe("esp32/output");
//DHT Temp and humidity reading start
dht.begin();
}
}
}
void setup_wifi() {
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Hello Paul please wait while connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.print("IP address = ");
Serial.println(WiFi.localIP());
}
void callback(char* topic, byte* message, unsigned int length) {
Serial.print("Message arrived on topic: ");
Serial.print(topic);
Serial.print(". Message: ");
String messageTemp;
for (int i = 0; i < length; i++) {
Serial.print((char)message[i]);
messageTemp += (char)message[i];
}
Serial.println();
if (String(topic) == "esp32/output") {
Serial.print("Changing output to ");
if(messageTemp == "enterph"){
Serial.write("ENTERPH");
}
}
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Please wait while attempting MQTT connection...");
//setup_wifi();
String client_id = "esp32-client-";
client_id += String(WiFi.macAddress());
// Attempt to connect
if (client.connect(client_id.c_str(), "homeassistant", "vae6OoGh0aequaisohj2au5yey3exiey1im0sei0eih5keengethooY6ap5uC4ee")) {
Serial.println("connected");
// Subscribe
client.subscribe("esp32/output");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void loop()
{
if (!client.connected()) {
reconnect();
}
client.loop();
long now = millis();
if (now - lastMsg > 5000) {
lastMsg = now;
// Convert the value to a char array for water temp
char tempString[8];
dtostrf(tempC, 1, 2, tempString);
Serial.print("Water temperature: ");
Serial.println(tempString);
client.publish("Greenhouse/Water temperature", tempString);
// Convert the value to a char array for PH
char PHString[8];
dtostrf(phValue, 1, 2, PHString);
Serial.print("Water PH: ");
Serial.println(PHString);
client.publish("Greenhouse/Water PH", PHString);
// Convert the value to a char array humidity
char humString[8];
dtostrf(hum, 1, 2, humString);
Serial.print("Humidity: ");
Serial.println(humString);
client.publish("Greenhouse/Humidity", humString);
// Convert the value to a char array for air temperature
char airtempString[8];
dtostrf(temp, 1, 2, airtempString);
Serial.print("Air temperature: ");
Serial.println(airtempString);
client.publish("Greenhouse/Air temperature", airtempString);
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(tempC, 1);
Serial.println("^C");
phValue = ph.readPH(voltage, temperature); // convert voltage to pH with temperature compensation
Serial.print("pH:");
Serial.println(phValue, 4);
// New DHT sensor readings
hum = dht.readHumidity();
// Read temperature as Celsius (the default)
temp = dht.readTemperature();
// Check if any reads failed and exit early (to try again).
if (isnan(temp) || isnan(hum)) {
Serial.println(F("Failed to read from DHT sensor!"));
//return;
}
DS18B20.requestTemperatures(); // send the command to get temperatures
tempC = DS18B20.getTempCByIndex(0); // read temperature in °C
//client.publish("Greenhouse/EC", "2.5");
}
}
ph.calibration(voltage, temperature); // calibration process by Serail CMD
}
The cpp is here:
/*
* file DFRobot_ESP_PH.cpp * @ https://github.com/GreenPonik/DFRobot_ESP_PH_BY_GREENPONIK
*
* Arduino library for Gravity: Analog pH Sensor / Meter Kit V2, SKU: SEN0161-V2
*
* 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.0
* date 2019-05
*/
#include "Arduino.h"
#include "DFRobot_ESP_PH.h"
#include "EEPROM.h"
#define PH_3_VOLTAGE 2010
DFRobot_ESP_PH::DFRobot_ESP_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_ESP_PH::~DFRobot_ESP_PH()
{
}
void DFRobot_ESP_PH::begin()
{
//check if calibration values (neutral and acid) are stored in eeprom
this->_neutralVoltage = EEPROM.readFloat(PHVALUEADDR); //load the neutral (pH = 7.0)voltage of the pH board from the EEPROM
if (this->_neutralVoltage == float() || isnan(this->_neutralVoltage))
{
this->_neutralVoltage = 1500.0; // new EEPROM, write typical voltage
EEPROM.writeFloat(PHVALUEADDR, this->_neutralVoltage);
EEPROM.commit();
}
this->_acidVoltage = EEPROM.readFloat(PHVALUEADDR + sizeof(float)); //load the acid (pH = 4.0) voltage of the pH board from the EEPROM
if (this->_acidVoltage == float() || isnan(this->_acidVoltage))
{
this->_acidVoltage = 2032.44; // new EEPROM, write typical voltage
EEPROM.writeFloat(PHVALUEADDR + sizeof(float), this->_acidVoltage);
EEPROM.commit();
}
}
float DFRobot_ESP_PH::readPH(float voltage, float temperature)
{
// 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;
}
void DFRobot_ESP_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_ESP_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_ESP_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_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;
}
byte DFRobot_ESP_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_ESP_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 > PH_8_VOLTAGE) && (this->_voltage < PH_6_VOLTAGE))
{ // 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 > PH_5_VOLTAGE) && (this->_voltage < PH_3_VOLTAGE))
{ //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: //store calibration value in eeprom
if (enterCalibrationFlag)
{
Serial.println();
if (phCalibrationFinish)
{
if ((this->_voltage > PH_8_VOLTAGE) && (this->_voltage < PH_5_VOLTAGE))
{
EEPROM.writeFloat(PHVALUEADDR, this->_neutralVoltage);
EEPROM.commit();
}
else if ((this->_voltage > PH_5_VOLTAGE) && (this->_voltage < PH_3_VOLTAGE))
{
EEPROM.writeFloat(PHVALUEADDR + sizeof(float), this->_acidVoltage);
EEPROM.commit();
}
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;
}
}
The .h is here
/*
* file DFRobot_ESP_PH.h * @ https://github.com/GreenPonik/DFRobot_ESP_PH_BY_GREENPONIK
*
* Arduino library for Gravity: Analog pH Sensor / Meter Kit V2, SKU: SEN0161-V2
*
* 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
*/
#ifndef _DFROBOT_ESP_PH_H_
#define _DFROBOT_ESP_PH_H_
#include "Arduino.h"
#define PHVALUEADDR 0x00 //the start address of the pH calibration parameters stored in the EEPROM
#define PH_8_VOLTAGE 1122
#define PH_6_VOLTAGE 1478
#define PH_5_VOLTAGE 1654
#define PH_3_VOLTAGE 2010
#define ReceivedBufferLength 10 //length of the Serial CMD buffer
class DFRobot_ESP_PH
{
public
DFRobot_ESP_PH();
~DFRobot_ESP_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:
public
float _phValue;
float _acidVoltage;
float _neutralVoltage;
float _voltage;
float _temperature;
char _cmdReceivedBuffer[ReceivedBufferLength]; //store the Serial CMD
byte _cmdReceivedBufferIndex;
public
//private:
boolean cmdSerialDataAvailable();
void phCalibration(byte mode); // calibration process, wirte key parameters to EEPROM
byte cmdParse(const char *cmd);
byte cmdParse();
};
#endif