Error when Arduino send data to MQTT

Hello everyone.

I am trying to send data from esp32 to Node-Red using MQTT and receive the output from Node-Red to trigger few relays. Initially when I tested the code without wiring the esp32 to any relay, it works fine(can send and receive data). I can see the data in Node-Red and serial monitor in Arduino IDE.

What I am trying to do is if my float switch is HIGH then Node-Red will send payload '2' when float switch is LOW then Node-Red will send payload '0'.

But after I wire the Arduino to the relay, I get error when there is any changes in float switch signal when my esp32 is sending data to Node-Red. The problem only occur when the float switch signal changes happen when the board is sending data to Node-Red. As you can see in the picture below

If you notice at the most bottom, when I try to make the float switch to LOW and Arduino was sending EC data to Node-Red, there is some error (unknown symbol) after that. So I had to manually reset the board for it to function again but this problem keep occurring. Can I know at what is the problem with my code? I am new to programing and the code was formed by me searching online and asking guidance from people online.

/*
  Title: Auto Dosage and Auto Flush using ESP32, Raspberry Pi and Node-Red

  Item Used
    1.  Wemos D1 R32 (ESP32 Development Board)
    2.  Raspberry Pi Model B 4GB Ram
    3.  DS18B20 - Waterproof temperature sensor
    4.  EC sensor - Electroconductivity sensor
    5.  Float sensor
    6.  1/2" 25W Solenoid Valve (NO) - Inlet Valve
    7.  1 1/2" 28W Solenoid Valve (NC) - Outlet Valve
    8.  5W Peristaltic Pump A - Pump used to transmit solution A to water tank
    9.  5W Peristaltic Pump B - Pump used to transmit solution B to water tank
    10. Submersible Pump - Pump to pump water to the plants

  Normal Process Flow
    1. Initial startup with inlet valve turned on with outlet valve,peristaltic pump and submersible pump turned off
    2. When float switch 1 is HIGH, submersible pump will turned on and EC sensor will take reading
        a) If EC below 2000, peristaltic pump for both solution will turned on. After EC reach setpoint, the peristaltic pump will stop
        b) If EC above 2000, peristaltic pump will not be triggered
    3. After 1 hours of the dosage addition, EC sensor will take reading again
        a) If EC below 2000, peristaltic pump for both solution will turned on. After EC reach setpoint, the peristaltic pump will stop
        b) If EC above 2000, peristaltic pump will not be triggered
    4. Step 3 is repeated every 1 hour

  Flushing Process
    1. Flush button will be pressed (Node-Red) and the signal will be sent to Wemos D1 R32
    2. The signal will turn open the outlet valve and turn off inlet valve and peristaltic pump
    3. When float switch 1 is LOW, submersible pump will turned off
    4. When float switch 2 is LOW, the Normal Process Flow is initiated
*/



//******Include Libraries******//
#include <OneWire.h> //OneWire Sensor Library for DS18B20 since the sensor is using a onewire interface
#include <DallasTemperature.h> //DS18B20 Library 
#include <PubSubClient.h> //Publish and Subscribe Library Using MQTT protocol
#include <WiFi.h> //WiFi Library

//******Constants (wont change)******//
//If there is changes on the pin of ESP32, then do change the number according to the pin used
//int is 2 byte(16 bit) from - 32768 to 32767
const int ONE_WIRE_BUS = 5; //Set DS18B20 pin
const int PPA = 26; //Set 3V relay In1 pin (Peristaltic Pump for Solution A)
const int PPB = 25; //Set 3V relay In2 pin (Peristaltic Pump for Solution B)
const int SV1 = 17; //Set 3V relay In1 pin (NO 1/2" Solenoid Valve)
const int SV2 = 16; //Set 3V relay In2 pin (NC 1 1/2" Solenoid Valve)
const int FS1 = 14; //Set float switch for turn on pump
const int FS2 = 27; //Set float switch for flush pump
const int Max_Distance = 100; //Set max distance for SN-JSN-SR04T(Ultrasonic Sensor)
const int SP = 13; //Set 3V relay In1 pin (Submersible pump)
const int EC = 34; //Set EC sensor pin

// long is 4 byte(32 bit) from -2,147,483,648 to 2,147,483,647. Used normally with millis() and micros()
unsigned long wifiConnectInterval = 500; //Give half a second delay for the Wemos to connect to WiFi
unsigned long wifiReconnectInterval = 2000; //Give 2 second for Wemos to reconnect to WiFi after if failed connection
unsigned long fs1Interval = 1000; //Take float switch 1 reading every 1 second
unsigned long fs2Interval = 1000; //Take float switch 2 reading every 1 second
unsigned long tempInterval = 5000; //Take temperature reading every 5 second
unsigned long ecInterval = 1000; //Take EC analog reading every 1 second

OneWire oneWire(ONE_WIRE_BUS); //Initialize DS18B20 sensor
DallasTemperature sensor(&oneWire); //Pass oneWire reference to Dallas Temperature

//******Variables (will change)******//
//Float is used when there is demical point value
int laststate = 0; //Initial state when ESP32 run
float watertemp = 0.00; //Store the water temperature value.
float ecValueInAdc = 0.00; //Store the EC analog value
float ecValueInVolt = 0.00; //Store the EC voltage value
float ecValue = 0.00; //Store the EC microsiemens value
unsigned long currentMillis = 0; //stores the value of millis() in each iteration of loop()
unsigned long previousFs1aMillis = 0; //will store the last time ultrasonic reading was updated
unsigned long previousFs1bMillis = 0; //will store the last time ultrasonic reading was updated after failed connection
unsigned long previousFs2aMillis = 0; //will store the last time ultrasonic reading was updated
unsigned long previousFs2bMillis = 0;
unsigned long previousWifiConnectMillis = 0; //will store the last time wifi was connected
unsigned long previousWifiReconnectMillis = 0; //will store the last time the wifi was reconnect after failed connection
unsigned long previousTempMillis = 0; //will store the last time temperature reading was updated
unsigned long previousTemp1Millis = 0; //will store the last time temperature reading was updated after failed connection
unsigned long previousEcMillis = 0; //will store the last time EC reading was updated
unsigned long previousEc1Millis = 0; //will store the last time EC reading was updated after failed connection

//******Set WiFi connection and MQTT******//
//Char is used when the data is in character or letter.
//Character literals are written in single quotes like this: 'A' and for multiple characters, strings use double quotes: "ABC"
const char* ssid = "xxxx"; //Your personal network SSID (User can change according to the wifi network user wish to connect)
const char* wifi_password = "xxxx"; //Your personal network password (User must change according to the wifi network user has connected)
const char* mqtt_server = "test.mosquitto.org"; //IP of MQTT broker. RasPi IP address as broker
const int mqttPort = 1883; //1883 is the listener port for the Broker
const char* mqtt_username = "xxxx"; // MQTT username
const char* mqtt_password = "xxxx"; // MQTT password
const char* clientID = "farm2"; //Your personal clientID. Can be anything
const char* fs1Topic = "fs1/test/farm"; //Topic used to publish float switch 1 reading. Topic name can be change according to own preferences
const char* fs2Topic = "fs2/test/farm"; //Topic used to publish float switch 2 reading.
const char* tempTopic = "temp/test/farm"; //Topic used to publish temperature reading
const char* ecTopic = "ec/test/farm"; // Topic used to publish EC analog value.

//******Initialise the client library******//
WiFiClient espClient;
PubSubClient client(espClient);

//******Subscribe Function******//
//Receive data from Node-Red through MQTT protocol
void callback(char* topic, byte* payload, unsigned int length)
{
  Serial.print("Message arrived in topic: ");
  Serial.println(topic); //Print the topic title that user subscribe when callback is call by ESP32
  //The purpose of this serial print is to troubleshoot whether the topic was called or not

  for (int i = 0; i < length; i++)
  {
    Serial.println((char)payload[i]);
  }
  int floatswitch1 = digitalRead(FS1);
  int floatswitch2 = digitalRead(FS2);

  if (payload[0] == '3') //Flush Process. When Flush button is pressed in Node-Red, Node-Red will send string '3'
  {
    digitalWrite(SV1, HIGH); //Inlet valve close
    digitalWrite(SV2, HIGH); //Outlet valve open
    digitalWrite(PPA, LOW); //Peristaltic pump A stop
    digitalWrite(PPB, LOW); //Peristaltic pump B stop
    digitalWrite(SP, LOW); //Submersible pump start
    Serial.println("Water is flushing out");
    laststate = 1;
  }
  if (laststate == 1 && floatswitch1 == 0)  //During Flush process, when float switch 1 is  LOW
  {
    digitalWrite(SV1, HIGH); //Inlet valve close
    digitalWrite(SV2, HIGH); //Outlet valve open
    digitalWrite(PPA, LOW); //Peristaltic pump A stop
    digitalWrite(PPB, LOW); //Peristaltic pump B stop
    digitalWrite(SP, HIGH); //Submersible pump stop
    Serial.println("Water is halfway flush out");
    laststate = 2;
  }
  if (laststate == 2 && floatswitch2 == 0) //During Flush process, when float switch 2 is  LOW
  {
    digitalWrite(SV1, LOW); //Inlet valve open
    digitalWrite(SV1, LOW); //Outlet valve close
    digitalWrite(PPA, LOW); //Peristaltic pump A stop
    digitalWrite(PPB, LOW); //Peristaltic pump B stop
    digitalWrite(SP, HIGH); //Submersible pump stop
    Serial.println("Restarting Initial Process");
    laststate = 3;
  }
  if (laststate == 0 || laststate == 3) //Initial Process. During initial startup or after Flush process ended
  {
    if (payload[0] == '0') //FLoat switch 1 is LOW
    {
      digitalWrite(SV1, LOW); //Inlet valve open
      digitalWrite(SV2, LOW); //Outlet valve close
      digitalWrite(PPA, LOW); //Peristaltic pump A stop
      digitalWrite(PPB, LOW); //Peristaltic pump B stop
      digitalWrite(SP, HIGH); //Submersible pump stop
      Serial.println("Water is filling in");
    }
    else if (payload[0] == '1') //EC is < 2000 and float switch 1 is HIGH 
    {
      digitalWrite(SV1, LOW); //Inlet valve open
      digitalWrite(SV2, LOW); //Outlet valve close
      digitalWrite(PPA, HIGH); //Peristaltic pump A start
      digitalWrite(PPB, HIGH); //Peristaltic pump B start
      digitalWrite(SP, LOW); //Submersible pump start
      Serial.println("Motor On and Auto Dosage On");
    }
    else if (payload[0] == '2') //EC is >= 2000 and float switch 1 is HIGH
    {
      digitalWrite(SV1, LOW); //Inlet valve open
      digitalWrite(SV2, LOW); //Outlet valve close
      digitalWrite(PPA, LOW); //Peristaltic pump A stop
      digitalWrite(PPB, LOW); //Peristaltic pump B stop
      digitalWrite(SP, LOW); //Submersible pump start
      Serial.println("Only Motor On");
    }
  }
}

//******Water Level for Submersible Pump operation******//
void fsinlet()// Float switch 1
{
  //if the time is >= 1 second, Wemos will get reading from ultrasonic sensor
  if (currentMillis - previousFs1aMillis >= fs1Interval)
  {
    int floatswitch1 = digitalRead(FS1);
    Serial.println(floatswitch1); //Print the float switch 1 reading on serial monitor

    //Publish to the MQTT Broker (topic = usTopic, defined at the beginning)
    if (client.publish(fs1Topic, String(floatswitch1).c_str()))
    {
      Serial.println("Float switch 1 value sent!");
      previousFs1aMillis += fs1Interval; //save the time when the reading was updated
    }

    //Again, client.publish will return a boolean value depending on whether it succeeded or not.
    //If the message failed to send, we will try again, as the connection may have broken.
    else
    {
      Serial.println("Float switch 1 value failed to send. Reconnecting to MQTT Broker and trying again");
      client.connect("ESP32CLIENT");
      client.subscribe("sub/test/opus");
      if (currentMillis - previousFs1bMillis >= fs1Interval) //This delay ensure that client.publish does not clash with client.connect call
      {
        client.publish(fs1Topic, String(floatswitch1).c_str());
        previousFs1bMillis += fs1Interval;
      }
    }
  }
}

//******Water Level for Flush Pump operation******//
void fsoutlet()// Float switch 2
{
  //if the time is >= 1 second, Wemos will get reading from ultrasonic sensor
  if (currentMillis - previousFs2aMillis >= fs2Interval)
  {
    int floatswitch2 = digitalRead(FS2);
    Serial.println(floatswitch2); //Print the float switch 2 reading on serial monitor

    //Publish to the MQTT Broker (topic = usTopic, defined at the beginning)
    if (client.publish(fs2Topic, String(floatswitch2).c_str()))
    {
      Serial.println("Float switch 2 value sent!");
      previousFs2aMillis += fs2Interval; //save the time when the reading was updated
    }

    //Again, client.publish will return a boolean value depending on whether it succeeded or not.
    //If the message failed to send, we will try again, as the connection may have broken.
    else
    {
      Serial.println("Float switch 2 value failed to send. Reconnecting to MQTT Broker and trying again");
      client.connect("ESP32CLIENT");
      client.subscribe("sub/test/opus");
      if (currentMillis - previousFs2bMillis >= fs2Interval) //This delay ensure that client.publish does not clash with client.connect call
      {
        client.publish(fs2Topic, String(floatswitch2).c_str());
        previousFs2bMillis += fs2Interval;
      }
    }
  }
}


//******Measure temperature of water in tank******//
void tempInTank()
{
  if (currentMillis - previousTempMillis >= tempInterval) //if the time >= 5 second, Wemos will get reading from DS18B20
  {
    sensor.requestTemperatures(); /*//call sensors.requestTemperatures() to issue a global temperature
                                    //request to all devices on the bus*/
    watertemp = sensor.getTempCByIndex(0); //Read data and store in watertemp variable
    Serial.print("Temperature: ");
    Serial.print(watertemp, 1); //The "1"  is to ensure the value printed is in 1 decimal point
    Serial.println("°C"); //To create the degree symbol hold ALT button while pressing on Num 0,1,7,6 then let go of all the button

    //Publish to the MQTT Broker (topic = tempTopic, defined at the beginning)
    if (client.publish(tempTopic, String(watertemp, 1).c_str())) //Publish to the MQTT Broker (topic = tempTopic, defined at the beginning)
    {
      Serial.println("Temperature sent!");
      previousTempMillis += tempInterval;
    }

    //Again, client.publish will return a boolean value depending on whether it succeeded or not.
    //If the message failed to send, we will try again, as the connection may have broken.
    else
    {
      Serial.println("Temperature failed to send. Reconnecting to MQTT Broker and trying again");
      client.connect("ESP32CLIENT");
      client.subscribe("sub/test/opus");
      if (currentMillis - previousTemp1Millis >= tempInterval)
      {
        client.publish(tempTopic, String(watertemp, 1).c_str());
        previousTemp1Millis += tempInterval;
      }
    }
  }
}

//******Measure EC level in the tank******//
void ecInTank()
{

  if (currentMillis - previousEcMillis >= ecInterval) //if the time >= 1 second, Wemos will get reading from EC sensor
  {
    ecValueInAdc = analogRead(EC); //Read data in analog format which is 0 - 4095 for 12 bit
    ecValueInVolt = (ecValueInAdc / 3000.00) * 2.50; //Convert analog to voltage (0V - 2.5V , 0 - 3000)
    ecValue = (ecValueInAdc / 3000.00) * 4440.00 * 1.20; //Convert analog to microsiemens (0 - 4440 , 0 - 3000). Correction ratio is 1.20
    //Serial.println(ecValueInVolt);
    Serial.println(ecValue);
    if (client.publish(ecTopic, String(ecValue).c_str())) //Publish to the MQTT Broker (topic = ecTopic, defined at the beginning)
    {
      Serial.println("EC sent!");
      previousEcMillis += ecInterval;
    }

    //Again, client.publish will return a boolean value depending on whether it succeeded or not.
    //If the message failed to send, we will try again, as the connection may have broken.
    else
    {
      Serial.println("EC failed to send. Reconnecting to MQTT Broker and trying again");
      client.connect("ESP32CLIENT");
      client.subscribe("sub/test/opus");
      if (currentMillis - previousEc1Millis >= ecInterval)
      {
        client.publish(ecTopic, String(ecValueInAdc).c_str());
        previousEc1Millis += ecInterval;
      }
    }
  }
}

//******Code that only run once******//
void setup()
{
  Serial.begin(9600); //Initialise the serial monitor
  sensor.begin(); //Start the DS18B20 sensor
  WiFi.begin(ssid, wifi_password);//Initialise WiFi connection
  pinMode(SV1, OUTPUT); //Set inlet valve pin as output
  pinMode(SV2, OUTPUT); //Set outlet pump pin as output
  pinMode(PPA, OUTPUT); //Set peristaltic pump pin as output
  pinMode(PPB, OUTPUT); //Set peristaltic pump pin as output
  pinMode(SP, OUTPUT); //Set submersible pump pin as output
  pinMode(FS1, INPUT_PULLUP);
  pinMode(FS2, INPUT_PULLUP);

  while (WiFi.status() != WL_CONNECTED) //If WiFi is not connected
  {
    currentMillis = millis(); /*//store the latest value of millis()
                                //While Wemos trying to connect to WiFi, give half a second delay*/
    if (currentMillis - previousWifiConnectMillis >= wifiConnectInterval)
    {
      Serial.println("Connecting to WiFi..");
      previousWifiConnectMillis += wifiConnectInterval;
    }
  }
  Serial.println("Connected to WiFi network");

  client.setServer(mqtt_server, mqttPort); //Sets the server details so that any data receives from Wemos will go to this server only.
  client.setCallback(callback); //Sets the message callback function.

  while (!client.connected()) //If MQTT is not connected
  {
    Serial.println("Connecting to MQTT...");
    if (client.connect("ESP32CLIENT"))
    {
      Serial.println("connected");
    }
    else
    {
      Serial.print("failed with state ");
      Serial.println(client.state()); /*//-4 : MQTT_CONNECTION_TIMEOUT - the server didn't respond within the keepalive time
                                        //-3 : MQTT_CONNECTION_LOST - the network connection was broken
                                        //-2 : MQTT_CONNECT_FAILED - the network connection failed
                                        //-1 : MQTT_DISCONNECTED - the client is disconnected cleanly
                                        //0 : MQTT_CONNECTED - the client is connected
                                        //1 : MQTT_CONNECT_BAD_PROTOCOL - the server doesn't support the requested version of MQTT
                                        //2 : MQTT_CONNECT_BAD_CLIENT_ID - the server rejected the client identifier
                                        //3 : MQTT_CONNECT_UNAVAILABLE - the server was unable to accept the connection
                                        //4 : MQTT_CONNECT_BAD_CREDENTIALS - the username/password were rejected
                                        //5 : MQTT_CONNECT_UNAUTHORIZED - the client was not authorized to connect*/
      if (currentMillis - previousWifiReconnectMillis >= wifiReconnectInterval)
      {
        previousWifiReconnectMillis += wifiReconnectInterval;
      }
    }
  }
  client.subscribe("sub/test/opus"); //Subscribe to this topic to receive data from Node-Red.
  //Can change topic name but ensure Node-Red also uses that same topic name
}

//******Code that will continously run as it loop******//
void loop()
{
  currentMillis = millis(); /*//capture the latest value of millis()
                              //this is equivalent to noting the time from a clock
                              //use the same time for all function to keep them synchronized*/
  client.loop(); /*//Function called to allow the client to process incoming messages
                   //To send publish data
                   //Makes a refresh of the connection.*/
  fsinlet(); //Call the function to run
  fsoutlet();
  tempInTank();
  ecInTank();
}

How exactly is the relay wired to teh ESP32 and how is the relay powered ?

The relay is powered by a DC Buck Converter from 12V to 3.3V since it is a 3V relay module. The relay is powering 2 submersible pump which is 240VAC, 2 peristaltic pump 12VDC and a solenoid valve 12V. The data pin of relay is connected to pin.

Pin 26 = Peristaltic Pump 1
Pin 25 = Peristaltic Pump 2
Pin 17 = Solenoid Valve
Pin 16 = Submersible Pump 1
Pin 13 = Submersible Pump 2

Below is the main wiring diagram

Below is the ESP32 board wiring

I hope I have answered your question. Please advice. Btw I change the ultrasonic sensor to float switch. I have not updated the wiring diagram for the float switch yet. Sorry

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.