I am writingdeveloping a C# application using the EasyModbusEasyModbus library to poll severalmultiple Modbus RTU devices connected viabehind a single Modbus TCP Gateway.
The Problem: Normally The application works perfectly when the devices are online or when the gateway itself is disconnected (it properly throws a timeout exception). However, ifI am facing a critical issue with non-existent or offline Slave IDs.
If I query a Slave ID that is physically disconnected or missingsimply doesn't exist on the RS485 bus, I expectthe gateway does not throw a TimeoutExceptiontimeout or a Modbus Exception. HoweverInstead, my specific Gateway handles missing slaves by returningit intercepts the timeout and returns a perfectly valid Modbus TCP packet filled entirely with zeros0s ([0, 0, 0...]). Therefore, the code doesn't fall intoor sometimes repeats the catch block and assumesdata from the device is online and reading 0previous active Slave ID).
My Partial Workaround: For devices where I read multiple registers Since 0 is a completely normal value for some of my point sensors (e.g., quantity = 15normal state = 0, alarm = 1), I addedcannot distinguish between a logic to check if all values are 0. If they are, I assume the device is offline, because"Healthy Sensor reading 0" and a real device will have at least one non-zero configuration or time register"Missing Sensor returning fake 0s".
The Core Issue: To bypass this hardware limitation, I have some "Point Sensors" whereimplemented a "Ping" logic in C#. If I only needread a 0 from a point sensor, I immediately try to read quantity = 1a clearly invalid register. The normal address (no-alarm) state of this register is 0e. Since I don't have the manual for these sensorsg., I don't know any specific static address (like Baudrate or Firmware Version9999) to "ping" and expect a non-zero response.
How can I reliably differentiate between "Sensor is online and normal (returns 0)" and "Sensor is offline (Gateway returns fake 0)" under these circumstances? Is there a Modbus-level trick or standard register to ping when manuals are missing?
Here is my simplified code:
using EasyModbus;
using System;
namespace MyApp.Modbus
{
public class ModbusScanner
{
public void ScanDevice(string ip, int port, byte slaveId, int startAddress, int quantity)
{
ModbusClient modbusClient = new ModbusClient(ip, port)
{
UnitIdentifier = slaveId,
ConnectionTimeout = 1500
};
try
{
modbusClient.Connect();
// Gateway returns an array of 0s instead of throwing timeout ifIf Slavethe IDdevice is missing
int[] registers =truly modbusClient.ReadHoldingRegisters(startAddressonline, quantity);
if (quantity > 1)
{
// Workaround for multi-register devices
bool allZero = true;
foreach (int val in registers)
{
if (val != 0) { allZero = false; break; }
}
if (allZero)
{
it responds with 02 Illegal Data Address Console.WriteLine($"Slave ID {slaveId}which isI offlinecatch (Gatewayand sentconsider fakeas 0s"Alive").");
}
}
else if (quantity == 1)
{
// THE PROBLEM IS HERE:
// Single-register device.If Normalthe stategateway is 0.
// How do I know if it's offline or just reading normal 0lying, withoutit knowingreturns a static register to ping?
int regValue = registers[0];
}
}
catch (Exception ex)
{
// Thissuccessful catchread iswithout notany triggeredexception, byproving the gateway for missing slaves
Console.WriteLine($"Network Failure: {ex.Message}");
}
finally
{
device ifis (modbusClient.Connected)actually modbusClientoffline.Disconnect();
}
}
}
}
Here is a simplified version of my polling loop:
using System;
using System.Diagnostics;
public void PollSensors()
{
ModbusClient modbusClient = new ModbusClient("192.168.1.100", 502)
{
ConnectionTimeout = 1500
};
try
{
modbusClient.Connect();
// Let's say Slave ID 5 is currently disconnected
modbusClient.UnitIdentifier = 5;
// Read 1 register starting from address 0
int[] registers = modbusClient.ReadHoldingRegisters(0, 1);
if (registers.Length > 0 && registers[0] == 0)
{
try
{
// PING TEST: Try reading an invalid address to force an exception
modbusClient.ReadHoldingRegisters(9999, 1);
// If we reach here, the gateway swallowed the error. The device is offline.
throw new Exception("Gateway returned fake 0. Device is actually offline.");
}
catch (EasyModbus.Exceptions.ModbusException)
{
// Device threw "02 Illegal Address". It is physically online and healthy.
Debug.WriteLine("Sensor is online.");
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"Network Failure: {ex.Message}");
}
finally
{
if (modbusClient.Connected) modbusClient.Disconnect();
}
}```