Detection of rs485 disconnection with rs485 to ttl module

Hello.
I have a npk soil sensor that is connected to an esp with rs485 communication by an rs485 to ttl module and sends the data read from the sensor to the mqtt server. I want when the wired connection between the sensor and the ESP is interrupted, the disconnection is detected and the mqtt server is notified. When I disconnect the wired connection from the sensor, the last data read from the sensor is repeatedly sent to me by the rs485 module to TTL. How can I solve this problem and not receive data in response when I disconnect the sensor.

The chip of this module is max485.

That's a problem with your code that you didn't post for us to see.

When you send out the modbus message to the NPK sensor, your code (or modbus library) should detect that there was no response from the sensor and report back accordingly.

Sorry I forgot to send the code
For example, for the ph parameter, I check that if these registries are received from the sensor, it will send the data. But when I disconnect the sensor, it still enters this condition, but repeatedly until I connect the sensor and new data is sent to me.

if (ph_values[0] == 0x02 && ph_values[1] == 0x03 && ph_values[2] == 0x02)


//Rev 1.4
//Uptime added
//Web OTA Added
//Ni read bug fix
//The reset operation was not performed when it was turned on without a sensor fixed

#include <SoftwareSerial.h>
#include <WiFiUdp.h>
#include <ESP8266mDNS.h>
#include <Wire.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <ArduinoOTA.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <AsyncElegantOTA.h>


#define WIFI_SSID "Moaven-Greenhouse"
#define WIFI_PASS "38300710ali"
const char* ssid = WIFI_SSID;
const char* password = WIFI_PASS;
const char* mqttServerName = "";
const int   mqttport = 1883;         
const char* mqttuser = "";
const char* mqttpass = "";
String prefix= "" ;
const char* clientID = "";

IPAddress local_IP(192,168,43,10);
IPAddress gateway(192,168,43,1);
IPAddress subnet(255,255,255,0);
IPAddress primaryDNS(8,8,8,8);
IPAddress secondaryDNS(8,8,4,4);

AsyncWebServer server(80);

WiFiClient wclient;                        
PubSubClient client(wclient);

#define RE 5
#define DE 4
#define PUB_DELAY 50


const byte ph[] = {0x02, 0x03, 0x00, 0x06, 0x00, 0x01, 0x64, 0x38}; // Soil PH Sensor
byte ph_values[11];


const byte ni[] = {0x02, 0x03, 0x00, 0x1F, 0x00, 0x01, 0xB5, 0xFF}; // Multi Sensor: Nitrogen
const byte phos[] = {0x02, 0x03, 0x00, 0x1E, 0x00, 0x01, 0xE4, 0x3F};
const byte pot[] = {0x02, 0x03, 0x00, 0x20, 0x00, 0x01, 0x85, 0xF3};
//const byte pot[] = {0x01, 0x03, 0x00, 0x20, 0x00, 0x01, 0x85, 0xC0};
const byte moist[] = {0x02, 0x03, 0x00, 0x12, 0x00, 0x01, 0x24, 0x3C};
const byte temp[] = {0x02, 0x03, 0x00, 0x13, 0x00, 0x01, 0x75, 0xFC};
const byte ec[] = {0x02, 0x03, 0x00, 0x15, 0x00, 0x01, 0x95, 0xFD};

byte pot_values[11];
byte moist_values[11];
byte phos_values[11];
byte ni_values[11];
byte ec_values[11];
byte temp_values[11];

String topic = "";
String message = "";
int cnt=10;

long Day=0;
int Hour =0;
int Minute=0;
int Second=0;
int HighMillis=0;
int Rollover=0;



SoftwareSerial mod;

 
void setup()
{
  Serial.begin(115200); 
  mod.begin(9600, SWSERIAL_8N1, 14, 12, false, 256);
  pinMode(RE, OUTPUT);
  pinMode(DE, OUTPUT);
  
  Serial.print("Connecting to ");
  Serial.println(ssid);
  
  //config wifi with optional settings
  
//  if(!WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS))
//  {
//    Serial.println("STA Failed to configure");
//  }

  
  
  WiFi.begin(ssid, password);
     
  
     
   while (WiFi.status() != WL_CONNECTED){
    ESP.wdtFeed();            
    ESP.wdtDisable();                     
    delay(500);
    Serial.print(".");
    delay(500);
    cnt--;
   if(cnt==0){
    ESP.wdtDisable();
    #ifdef SOFT_WATCHDOG
    ESP.wdtEnable(0);
    #endif  
    while(1);
  }
  delay(1000);
}

  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
    request->send(200, "text/plain", "Hi! I am ESP8266.");
  });

  AsyncElegantOTA.begin(&server);    // Start ElegantOTA
  server.begin();
  Serial.println("HTTP server started");
  
  client.setServer(mqttServerName, mqttport);
  client.setCallback(onMessageArrived);

   while (!client.connected()){
    
      
    delay(1000);
    Serial.println("Connecting To Server ...");
    if (client.connect(clientID, mqttuser, mqttpass, toCharArray(prefix + "/Will"), 1, true, toCharArray("Bye"), true))
    {
      Serial.println("Connected To Server");
      
    }  
   
    else 
    {
      Serial.print("failed with state ");
      Serial.print(client.state());
      delay(2000);
       
   }
}
  Serial.println('\n');
  Serial.println("Connection established!");  
  Serial.print("IP address:\t");
  Serial.println(WiFi.localIP());         //192.168.43.215

  
  
  ArduinoOTA.onStart([]() {
    String type;
    if (ArduinoOTA.getCommand() == U_FLASH) {
      type = "sketch";
    } else { // U_FS
      type = "filesystem";
    }

    // NOTE: if updating FS this would be the place to unmount FS using FS.end()
    Serial.println("Start updating " + type);
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("\nEnd");
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) {
      Serial.println("Auth Failed");
    } else if (error == OTA_BEGIN_ERROR) {
      Serial.println("Begin Failed");
    } else if (error == OTA_CONNECT_ERROR) {
      Serial.println("Connect Failed");
    } else if (error == OTA_RECEIVE_ERROR) {
      Serial.println("Receive Failed");
    } else if (error == OTA_END_ERROR) {
      Serial.println("End Failed");
    }
  });
  ArduinoOTA.begin();
  Serial.println("Ready");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  
  
 
 }
 
void loop()
{  
uptime(); //Runs the uptime script located below the main loop and reenters the main loop
print_Uptime();
ESP.wdtEnable(5000);
if (!client.connected()) {
 
  reconnect();
  } else {
   ArduinoOTA.handle();
  client.loop();
 String IP = WiFi.localIP().toString() ;
client.publish(toCharArray("/angizeh/security_system/24/1/IP:"), toCharArray(String(clientID) +"/"+WiFi.localIP().toString()));
client.publish(toCharArray("/angizeh/security_system/24/1/Uptime:"), toCharArray("Uptime:"+String(Day)+":"+String(Hour)+":"+String(Minute)+":"+String(Second)));
Serial.println("IP: " +IP);

multi_sensor_ph_detect();
multi_sensor_ni_detect();
multi_sensor_phos_detect();
multi_sensor_pot_detect();
multi_sensor_moist_detect();
multi_sensor_temp_detect();
multi_sensor_ec_detect();

  }
}


  
void multi_sensor_ph_detect(){
  while (true){
    digitalWrite(DE, HIGH);
    digitalWrite(RE, HIGH);
    delay(100);
    if (mod.write(ph, sizeof(ph)) == 8)
    {
      mod.flush();
      digitalWrite(DE, LOW);
      digitalWrite(RE, LOW);
      mod.readBytes(ph_values, 7);
     // Serial.print("Multi PH Values : ");
      for (byte i = 0; i < 7; i++)
      {
      // Serial.print(ph_values[i], HEX);
        Serial.print(" ");
      }
      Serial.println();
    }
    if (ph_values[0] == 0x02 && ph_values[1] == 0x03 && ph_values[2] == 0x02){
      float ph_reg3and4 = ((ph_values[3] << 8) + ph_values[4]);
      ph_reg3and4 = ph_reg3and4/100;
      if (ph_reg3and4 > -1 && ph_reg3and4 < 15){
        Serial.print("PH : "+(String)ph_reg3and4+"");
        Serial.println();
        delay(1000);
        client.publish(toCharArray("/angizeh/security_system/24/1/PH"), toCharArray(String(ph_reg3and4)));
        Serial.println("Published");
        break;
      }
    }else{
      Serial.print("PH cant measure");
    break;
    }
  }
}


void multi_sensor_phos_detect(){
  while (true){
    digitalWrite(DE, HIGH);
    digitalWrite(RE, HIGH);
    delay(100);
    if (mod.write(phos, sizeof(phos)) == 8)
    {
      mod.flush();
      digitalWrite(DE, LOW);
      digitalWrite(RE, LOW);
      mod.readBytes(phos_values, 7);
     // Serial.print("Multi PHOS Values : ");
      for (byte i = 0; i < 7; i++)
      {
       // Serial.print(phos_values[i], HEX);
        Serial.print(" ");
      }
      Serial.println();
    }
    if (phos_values[0] == 0x02 && phos_values[1] == 0x03 && phos_values[2] == 0x02){
      float phos_reg3and4 = ((phos_values[3] << 8) + phos_values[4]);
      if (phos_reg3and4 > -1 && phos_reg3and4 < 1000){
        Serial.print("PHOS : "+(String)phos_reg3and4+" mg/kg");
        Serial.println();
        delay(1000);
        client.publish(toCharArray("/angizeh/security_system/24/1/PHOS"), toCharArray(String(phos_reg3and4)));
        Serial.println("Published");
        break;
      }
    }else{
      Serial.print("PHOS cant measure");
    break;
    }
  }
}

void multi_sensor_pot_detect(){
  while (true){
    digitalWrite(DE, HIGH);
    digitalWrite(RE, HIGH);
    delay(100);
    if (mod.write(pot, sizeof(pot)) == 8)
    {
      mod.flush();
      digitalWrite(DE, LOW);
      digitalWrite(RE, LOW);
      mod.readBytes(pot_values, 7);
      //Serial.print("Multi POT Values : ");
      for (byte i = 0; i < 7; i++)
      {
       // Serial.print(pot_values[i], HEX);
        Serial.print(" ");
      }
      Serial.println();
    }
    if (pot_values[0] == 0x02 && pot_values[1] == 0x03 && pot_values[2] == 0x02){
      float pot_reg3and4 = ((pot_values[3] << 8) + pot_values[4]);
      if (pot_reg3and4 > -1 && pot_reg3and4 < 10000){
        Serial.print("POT : "+(String)pot_reg3and4+" mg/kg");
        Serial.println();
        delay(1000);
        client.publish(toCharArray("/angizeh/security_system/24/1/POT"), toCharArray(String(pot_reg3and4)));
        Serial.println("Published");
        break;
      }
    }else{
      Serial.print("POT cant measure");
    break;
    }
  }
}

void multi_sensor_ec_detect(){
  while (true){
    digitalWrite(DE, HIGH);
    digitalWrite(RE, HIGH);
    delay(100);
    if (mod.write(ec, sizeof(ec)) == 8)
    {
      mod.flush();
      digitalWrite(DE, LOW);
      digitalWrite(RE, LOW);
      mod.readBytes(ec_values, 7);
     // Serial.print("Multi EC Values : ");
      for (byte i = 0; i < 7; i++)
      {
      //  Serial.print(ec_values[i], HEX);
        Serial.print(" ");
      }
      Serial.println();
    }
    if (ec_values[0] == 0x02 && ec_values[1] == 0x03 && ec_values[2] == 0x02){
      float ec_reg3and4 = ((ec_values[3] << 8) + ec_values[4]);
      if (ec_reg3and4 > -1 && ec_reg3and4 < 10000){
        Serial.print("EC : "+(String)ec_reg3and4+" us/cm");
        Serial.println();
        delay(1000);
        client.publish(toCharArray("/angizeh/security_system/24/1/EC"), toCharArray(String(ec_reg3and4)));
        Serial.println("Published");
        break;
      }
    }else{
      Serial.println("EC cant measure");
    break;
    }
  }
}


void multi_sensor_moist_detect(){
  while (true){
    digitalWrite(DE, HIGH);
    digitalWrite(RE, HIGH);
    delay(100);
    if (mod.write(moist, sizeof(moist)) == 8)
    {
      mod.flush();
      digitalWrite(DE, LOW);
      digitalWrite(RE, LOW);
      mod.readBytes(moist_values, 7);
      //Serial.print("Multi MOIST Values : ");
      for (byte i = 0; i < 7; i++)
      {
       // Serial.print(moist_values[i], HEX);
        Serial.print(" ");
      }
      Serial.println();
    }
    if (moist_values[0] == 0x02 && moist_values[1] == 0x03 && moist_values[2] == 0x02){
      float moist_reg3and4 = ((moist_values[3] << 8) + moist_values[4]);
      moist_reg3and4 = moist_reg3and4/10;
      if (moist_reg3and4 > -1 && moist_reg3and4 < 105){
        Serial.print("MOIST : "+(String)moist_reg3and4+"%");
        Serial.println();
        delay(1000);
        client.publish(toCharArray("/angizeh/security_system/24/1/MOIST"), toCharArray(String(moist_reg3and4)));
        Serial.println("Published");
        break;
      }
    }else{
      Serial.print("MOIST cant measure");
    break;
    }
  }
}

void multi_sensor_temp_detect(){
  while (true){
    digitalWrite(DE, HIGH);
    digitalWrite(RE, HIGH);
    delay(100);
    if (mod.write(temp, sizeof(temp)) == 8)
    {
      mod.flush();
      digitalWrite(DE, LOW);
      digitalWrite(RE, LOW);
      mod.readBytes(temp_values, 7);
       //Serial.print("Multi TEMP Values : ");
      for (byte i = 0; i < 7; i++)
      {
      // Serial.print(temp_values[i], HEX);
        Serial.print(" ");
      }
      Serial.println();
    }
    if (temp_values[0] == 0x02 && temp_values[1] == 0x03 && temp_values[2] == 0x02){
      float temp_reg3and4 = ((temp_values[3] << 8) + temp_values[4]);
      temp_reg3and4 = temp_reg3and4/10;
      if (temp_reg3and4 > -1 && temp_reg3and4 < 100){
        Serial.print("TEMP : "+(String)temp_reg3and4+"°C");
        Serial.println();
        delay(1000);
        client.publish(toCharArray("/angizeh/security_system/24/1/Temperature"), toCharArray(String(temp_reg3and4)));
        Serial.println("Published");
        break;
      }
    }else{
      Serial.print("TEMP cant measure");
    break;
    }
  }
}

void multi_sensor_ni_detect(){
  while (true){
    digitalWrite(DE, HIGH);
    digitalWrite(RE, HIGH);
    delay(100);
    if (mod.write(ni, sizeof(ni)) == 8)
    {
      mod.flush();
      digitalWrite(DE, LOW);
      digitalWrite(RE, LOW);
      mod.readBytes(ni_values, 7);
       //Serial.print("Multi NI Values : ");
      for (byte i = 0; i < 7; i++)
      {
       //Serial.print(ni_values[i], HEX);
        Serial.print(" ");
      }
      Serial.println();
    }
    if (ni_values[0] == 0x02 && ni_values[1] == 0x03 && ni_values[2] == 0x02){
       float ni_reg3and4 =((ni_values[3] << 8) + ni_values[4]);
        Serial.print("NI : "+(String)ni_reg3and4+" mg/kg");
        Serial.println();
        delay(1000);
        client.publish(toCharArray("/angizeh/security_system/24/1/NI"), toCharArray(String(ni_reg3and4)));
        Serial.println("Published");
        break;
      
    }else{
      Serial.print("NI cant measure");
    break;
    }
  }
}


boolean reconnect() {
   while (WiFi.status() != WL_CONNECTED){
    ESP.wdtFeed();            
    ESP.wdtDisable();                     
    delay(500);
    Serial.print(".");
    delay(500);
    cnt--;
  if (client.connect(clientID, mqttuser, mqttpass, toCharArray(prefix + "/Will"), 1, true, toCharArray("Disconnected"), true)) {
    client.setCallback(onMessageArrived);
  return client.connected();
  }
   if(cnt==0){
    ESP.wdtDisable();
    #ifdef SOFT_WATCHDOG
    ESP.wdtEnable(0);
    #endif  
    while(1);
  }
  delay(1000);

}
}

char* toCharArray(String str) {
  return &str[0];
}

void onMessageArrived(char* t, byte* m, unsigned int length) {
  topic = String(t);
  message = String((char*)m);
  message = message.substring(0, length);

  if (message == "HELLO") {
    Serial.println("Hello client");
    client.publish(toCharArray(prefix + "/server"), toCharArray("HELLO"));
    Serial.println("Hello server");
  }
}
void uptime(){
  //** Making Note of an expected rollover *****//   
if(millis()>=3000000000){ 
HighMillis=1;

}
//** Making note of actual rollover **//
if(millis()<=100000&&HighMillis==1){
Rollover++;
HighMillis=0;
}

long secsUp = millis()/1000;

Second = secsUp%60;

Minute = (secsUp/60)%60;

Hour = (secsUp/(60*60))%24;

Day = (Rollover*50)+(secsUp/(60*60*24));  //First portion takes care of a rollover [around 50 days]
                       
}
void print_Uptime(){
  
  Serial.print(F("Uptime: ")); // The "F" Portion saves your SRam Space
  Serial.print(Day);
  Serial.print(F("  Days  "));
  Serial.print(Hour);
  Serial.print(F("  Hours  "));
  Serial.print(Minute);
  Serial.print(F("  Minutes  "));
  Serial.print(Second);
  Serial.println(F("  Seconds"));
}

After sending the data via MQTT change the current NPK values to some 'out of range' number such as -1.
Before sending the next MQTT message check to see if the values are still stuck at -1.

There are better ways, but you will need to understand how the NPK library behaves when communication fails.

The OP isn't using any NPK library. It's the same old NPK software with the canned modbus messages that is seen whenever the NPK sensor is mentioned in these forums.

There are no checks in your code to see if you get a response from the sensor. You check to see if 8 bytes are written and then assume that you get a response.

How should I check if the sensor responds or not?

You could use the available() function to see if any bytes have been received.

Thanks for your help Mark
I have another question

If several soil sensors are connected as modbus, how can I determine which sensor is disconnected?

For example, I request the ph value with the following registries with address number 2

const byte ph[] = {0x02, 0x03, 0x00, 0x06, 0x00, 0x01, 0x64, 0x38};

And I request the amount of ec with the following registries with address number 4

const byte ec2[] = {0x04, 0x03, 0x00, 0x15, 0x00, 0x01, 0x95, 0x9B};

If only the ph sensor is disconnected, the data will be transmitted through the ec sensor on the serial.

You know which sensor you are talking to by the address you are using. So you know which sensor isn't responding.

I changed the code as follows and the command if(Serial.available()){
I added to the loop, if there is data in the serial, the data will be sent to the server, otherwise, the check sensor message will be sent to the server.
Now I only receive the check sensor message.

void loop()
{  
uptime(); //Runs the uptime script located below the main loop and reenters the main loop
print_Uptime();
ESP.wdtEnable(5000);
if (!client.connected()) {
 
  reconnect();
  } else {
   ArduinoOTA.handle();
  client.loop();
 String IP = WiFi.localIP().toString() ;
client.publish(toCharArray("/angizeh/security_system/24/1/IP:"), toCharArray(String(clientID) +"/"+WiFi.localIP().toString()));
client.publish(toCharArray("/angizeh/security_system/24/1/Uptime:"), toCharArray("Uptime:"+String(Day)+":"+String(Hour)+":"+String(Minute)+":"+String(Second)));
Serial.println("IP: " +IP);

 if(Serial.available()){

multi_sensor_ph_detect();
multi_sensor_ni_detect();
multi_sensor_phos_detect();
multi_sensor_pot_detect();
multi_sensor_moist_detect();
multi_sensor_temp_detect();
multi_sensor_ec_detect();
    }
else{
      client.publish(toCharArray("/angizeh/security_system/24/1/Will"), toCharArray("Check Sensor"));
}
  }
}

That's not what you want. That command is checking to see if any bytes have been received over the hardware serial port. It's also not the place to perform the check.

Here's a piece of code that fits into your multi_sensor_ph_detect() function:

  uint32_t startTime;
  uint8_t i;

  // flush the receive buffer
  while (mod.available()) mod.read();

  // switch to transmit mode
  digitalWrite(DE, HIGH);
  digitalWrite(RE, HIGH);
  delay(2);

  // write out the modbus command bytes and wait for the transmission to finish
  mod.write(ph, sizeof(ph));
  mod.flush();

  // switch to receive mode 
  digitalWrite(DE, LOW);
  digitalWrite(RE, LOW);

  i = 0;
  startTime = millis();
  // wait for up to 500ms for a response
  while ( millis() - startTime <= 500UL ) {
    if (mod.available() && i<sizeof(ph_values) ) {
      ph_values[i++] = mod.read();
    }
  }

You should be able to see where to insert this in your code. You need it for each function that is requesting data from the NPK sensor.

You are carrying out some sanity checks on the received byte array. You should also check the CRC for completeness. However, note that if you have 2 of those NPK sensors, then your code will get a lot more complicated as your sanity checking code would become quite messy.

You should consider using an Arduino modbus library instead. It will handle all this for you.

Thank you Mark, my friend. My problem was solved with the code you sent

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