Go Down

Topic: Solar Inverter interface with Modbus TCP: client.connect issues [SOLVED] (Read 915 times) previous topic - next topic

Watcher

Hi all,

I ve been trying to get data from an SMA sunnyboy solar inverter with the Modbus TCP protocol for some time now.
Theare are lots of libraries for modbus serial both master and slave as well as modbus tcp server/slave. However I was unable to locate a library for modbus tcp working as a client/master.

The following sketch was developed by the forum user Juraj for a similar application (different inverter brand) which apparently works fine. However in my case it mostly returns a connection failure .
(original post https://forum.arduino.cc/index.php?topic=511054.45 )

I have also tried, amongst others,  the following troubleshooting steps :

1. I can telnet to the inverter on port 502 from the computer from a client like putty and from windows telnet.
2. I cannot telnet connect from arduino with a standard telnet client sketch loaded. I tried this with two different arduino mega's each with its own ethernet shield and connected to different points  of the network with the same result. (to eliminate possibility of h/w problem)
3. I can telnet from PC to both arduinos .
4. While trying all the above once or twice I did manage to get the arduino to successfully telnet the inverter but 98% of the times it fails



Code: [Select]
#include <SPI.h>
#include <Ethernet.h>


IPAddress SMA_Address(192,168,10,5);
IPAddress ip (192,168,10,180);

EthernetClient modbus;

#define SMA_PORT 502

#define MODBUS_CONNECT_ERROR -10
#define MODBUS_NO_RESPONSE -11
#define SMA_UID 126
#define SD_CARD_CD_DIO 4

byte subnet[] = { 255, 255, 255, 0 }; 
byte mac[] = {0xDE, 0xFE, 0xBE, 0xFF, 0xFE, 0xED };
byte DNS[]={ 192, 168, 10, 254 };
byte gateway[] = { 192, 168, 10, 254 };     



void setup() {
 

Serial.begin(9600);
Ethernet.begin(mac, ip, gateway, subnet);   // start etehrnet interface
pinMode (53,OUTPUT);              // For compatibility with MEGA   
digitalWrite (53, HIGH);          // Disable hardware SS pin
pinMode (SD_CARD_CD_DIO, OUTPUT); // SD card enable pin
pinMode (10,OUTPUT);              // Set ethernet enable pin
digitalWrite (10, HIGH);     
}

void loop() {
 
  requestSMAModel();

  while (true) {}    // do nothing
}




int modbusRequest(byte uid, unsigned int addr, byte len, int *regs) {

 
  if (!modbus.connected()) {
//    modbus.stop();
    modbus.connect(SMA_Address, SMA_PORT);
    if (!modbus.connected()) {
      modbus.stop();
      return MODBUS_CONNECT_ERROR;
    }
  }
  byte request[] = {0, 1, 0, 0, 0, 6, uid, 3, (byte) (addr / 256), (byte) (addr % 256), 0, len};
  modbus.write(request, sizeof(request));
  modbus.flush();
  if (!available(modbus)) {
    modbus.stop();
    return MODBUS_NO_RESPONSE;
  }
  for (int i = 0; i < 7; i++) { // skip 7
    if (modbus.read() == -1)
      return -3;
    if (!available(modbus))
      return -1;
  }
  switch (modbus.read()) { // code
    case 3:
      break;
    case -1:
      return -4;
    case 0x83:
      return modbus.read(); // 0x01, 0x02, 0x03 or 0x11
    default:
      return -6;
  }
  if (!available(modbus))
    return -1;
  int l = modbus.read() / 2;
  int i = 0;
  while (true) {
    if (!available(modbus))
      return -1;
    byte hi = modbus.read();
    if (!available(modbus))
      return -1;
    byte lo = modbus.read();
    regs[i++] = hi * 256 + lo;
    if (i == len || i == l)
      break;
  }
  return 0;
}

boolean available(Stream& client) {
  for (int i = 0; i < 5000; i++) {
    if (client.available())
      return true;
    delay(1);
  }
  return client.available();
}



boolean requestSMAModel() {
  int regs[1];
  int res = modbusRequest(SMA_UID, 40086-1, 1, regs);
  //if (modbusError(res)) {  return false;}
  Serial.print("Register Content:");Serial.println(regs[0]);
  Serial.print("Result:");Serial.println(res);
  return true;
}



If anyone can spot anything or have any suggestions whatsoever, mostly welcome.!

Coding Badly


This looks important...

Quote
Question:

Why does Modbus crash after a few days?

Answer:

This is not a crash, but instead a reaction to when more than the maximum of four TCP/Modbus connections is made.

If an attempt is made to do so, the system waits for precisely two hours. Once this time has elapsed and an existing connection has been inactive for that period, this connection is removed from our inverter bridge.

The same applies to all devices making requests to Modbus that establish a Modbus/TCP connection to the inverter but are not removed properly under fault conditions, for example.

Because we do not have any appropriate criteria for this, the inverter or the data module installed in the inverter as a TCP server cannot actively terminate the connection.

Coding Badly


Assuming I am reading the source code correctly exactly zero time is given for the device to respond.  If there is no immediate response the connection is closed and an error code is returned.  Typical MODBUS timeouts are in the order of seconds; even for communications over ethernet.


Watcher

Assuming I am reading the source code correctly exactly zero time is given for the device to respond.  If there is no immediate response the connection is closed and an error code is returned.  Typical MODBUS timeouts are in the order of seconds; even for communications over ethernet.

Thanks for the response..
I can see your point. However the issue i am facing happens before the device gets asked anything.
I get a no connect message (-10) which is a result of modbus.connect failure.

Watcher

This looks important...

Interesting...  In my case of course there is only one device attempting to connect.

Quote
Τhe same applies to all devices making requests to Modbus that establish a Modbus/TCP connection to the inverter but are not removed properly under fault conditions, for example.
Not sure what "removed properly" means but the fact is that this is were the program exists even with no previous attempts to connect :

Code: [Select]
if (!modbus.connected()) {
//    modbus.stop();
    modbus.connect(SMA_Address, SMA_PORT);
    if (!modbus.connected()) {
      modbus.stop();
      return MODBUS_CONNECT_ERROR;
    }
  }


How come I can connect from a modbus simulator on my android device AND from the computer with telnet (port 502) but NOT from the arduino ?

Could this be some kind of ethernet (shield) timing issue ?


Coding Badly


If you have the means this is probably a good time to bring Wireshark into the picture.


Coding Badly


As far as I can tell, this is the only reasonable exit path from connect...

https://github.com/arduino/Arduino/blob/master/libraries/Ethernet/src/EthernetClient.cpp#L64

...which tells you nothing about why connect failed.


Is it possible the IP address or port (49152-65535) is blocked by a firewall?  Or restricted by the device?


Watcher

As far as I can tell, this is the only reasonable exit path from connect...

https://github.com/arduino/Arduino/blob/master/libraries/Ethernet/src/EthernetClient.cpp#L64

...which tells you nothing about why connect failed.


Is it possible the IP address or port (49152-65535) is blocked by a firewall?  Or restricted by the device?


No, there is no firewall between device and arduino. They are all connected on the same internal network (hence the IP addressing on the sketch above). On the same network (same switch) is the computer and the android device connected too from which , as  i said, I experience no connection issues to the inverter.

On the inverter itself the only related available settings are :

modbus tcp enable/disable
modbus udp enable/disable - set to disabled
port : 502 (default)

ie no ip blocking is available

Coding Badly


Try UDP and try Wireshark are the only suggestions I have left.

There really is not much diagnostics available from the EthernetClient code.


Watcher

Try UDP and try Wireshark are the only suggestions I have left.

There really is not much diagnostics available from the EthernetClient code.


OK, thanks...

I am not familiar with Wireshark , but I l ll try it out! :)

Watcher

Update: Used Wireshark to capture traffic between

Arduino IP : 192.168.10.180
Inverter IP : 192.168.10.5
PC IP         : 192.168.10.115
1. inverter and PC during a successful Telnet :port 502 attempt 



After the ARP discovery , a TCP connection is established

and..

2. inverter and arduino during a failed connect attempt




In this case after the ARP discovery, nothing happens.

Any ideas why ?


PS: Sorry for the small picture size.


pylon

Quote
After the ARP discovery , a TCP connection is established
Yes, but you have a double answer to the ARP request. You have two devices that claim to have the IP 192.168.10.5, one of them seems to be a Cisco Linksys device (the other probably your inverter), that may help you find the reason for your problems.

Juraj

Assuming I am reading the source code correctly exactly zero time is given for the device to respond.  If there is no immediate response the connection is closed and an error code is returned.  Typical MODBUS timeouts are in the order of seconds; even for communications over ethernet.
the waiting available() function is at the end of the sketch
You can't write an Arduino sketch if you didn't learn programming. Not the language, but the concepts of programming - algorithms and data types.

Watcher

Yes, but you have a double answer to the ARP request. You have two devices that claim to have the IP 192.168.10.5, one of them seems to be a Cisco Linksys device (the other probably your inverter), that may help you find the reason for your problems.
The Cisco Linksys device replying to ARP is the managed network switch

Not sure why that is replying... Probably based on its ARP table.
Maybe I should reboot the switch to update table ...



Watcher

UPDATE:

There was indeed an IP conflict in the network which caused all the problems.
Problem now solved.


Thank you  Juraj, Pylon & Coding Badly for all the help - Karma points added

@ Juraj : I intend to try and make some improvements on your modbus function now that it works... wil keep you posted...

Go Up