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 Modbus TCP master library - Networking, Protocols, and Devices - Arduino Forum )
I have also tried, amongst others, the following troubleshooting steps :
- I can telnet to the inverter on port 502 from the computer from a client like putty and from windows telnet.
- 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)
- I can telnet from PC to both arduinos .
- 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
#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.!