Modbus TCP failed to read from Huawei Inverter

I'm trying to connect the MKR WiFi 1010 board via Modbus TCP to a solar inverter model SUN2000-5KTL-L1 with a meter DDSU666H using the ArduinoModbus Library (ArduinoModbus - Arduino Reference)

I'm trying to collect the registers ACTIVE_POWER (32080) and POWER_METER_ACTIVE_POWER (37113) . These addresses seem to be correct as I've tested a Python script to connect to the inverter and I can retrieve their values correctly. IP & Port is also correct (verified in Python).

I've tried many combinations and no luck. Not sure what's wrong but everything works fine until I try to get the registers (Wifi ok, Modbus TCP connection ok, but read from Modbus failed).

This is the last snippet I've tried and no luck.

    if (!modbusTCPClient.requestFrom(HOLDING_REGISTERS, 32080, 2)) {
      Serial.print("failed to read power! ");
      Serial.println(modbusTCPClient.lastError()); 
    } else {
      int16_t word1 = modbusTCPClient.read();
      int16_t word2 = modbusTCPClient.read();
      int32_t WATT = word1 << 16 | word2;                                             // bit math
     Serial.print("Active power: ");
     Serial.println(WATT);
    }

Any help would be much appreciated.

This is the documentation explaining the ACTIVE_POWER register in Huawei doc.
ACTIVE_POWER

use uint16_t

I read a Fronius inverter with a simple function which I wrote before Arduino made their modbus libraries

Wow, Big one! I'll look into it. Thanks a mill.

About this one in you code, I read in other places about ID = 240. Is it a common thing for the meter? Where did you get the value from?

const byte METER_UID = 240;

I also read that ID is not important with ArduinoModbus.

for Fronius the Smart Meter must be requested with a different device id

I've used part of your code and I get random readings, but most of them are error -11. When data is collected, value is correct (I can verify the value with a python script).

16:47:38.116 -> Error Counter: -11
16:47:52.607 -> Error Count: -11
16:47:58.206 ->  MB_reconnect
16:48:03.226 ->  MB_reconnect
16:48:42.467 -> Error Counter: 1
16:48:42.824 -> Data840
16:48:43.088 -> Data840
16:48:43.135 -> Data840
16:48:45.142 -> Error Counter: -11
16:48:53.846 -> Data838
16:48:54.175 -> Data838
16:48:54.815 -> Data837
16:48:56.806 -> Error Counter: -11
16:49:11.669 -> Error Count: -11

Could you please help on these errors. ModBus protocol is not my forte. This is the code below I've used.

#include <SPI.h>
#include <WiFiNINA.h> // for MKR WiFi 1010
#include <Arduino_MKRIoTCarrier.h>

char ssid[] = "MY_SSID";
char pass[] = "MY_PASSWD";

int status = WL_IDLE_STATUS;

IPAddress server(192, 168, 1, 37);
int port = 6607;

char buff[50];

// Fronius Symo Hybrid SunSpec Modbus

const byte METER_UID = 240;
const int MODBUS_CONNECT_ERROR = -10;
const int MODBUS_NO_RESPONSE = -11;

const byte FNC_READ_REGS = 0x03;
const byte FNC_WRITE_SINGLE = 0x06;
const byte FNC_ERR_FLAG = 0x80;

enum {
  MODBUS_DELAY,
  BATTERY_DATA,
  INVERTER_DATA,
  METER_DATA
};

WiFiClient modbus;
uint8_t requestId = 0;

void setup() {

  //Initialize serial and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // attempt to connect to WiFi network:
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);

    // wait 10 seconds for connection:
    delay(10000);

    // you're connected now, so print out the status:
    printWifiStatus();
  }

  const unsigned long GET_TIME_ATTEMPTS_TIMEOUT = 5000;

  unsigned long startMillis = millis();
  while (millis() - startMillis < GET_TIME_ATTEMPTS_TIMEOUT) {
    if (requestActivePower())
      return;
    delay(500);
  }
}

void loop() {
  requestSymoRTC();
}

void modbusClearData() {
  modbus.stop();
}

bool requestActivePower() {
  short regs[2];
  int res = modbusRequest(0, 32080, 2, regs);
  if (modbusError(res))
    return false;
  Serial.print("Data");
  Serial.println((unsigned short) regs[0] * 65536L + (unsigned short) regs[1]);
}

boolean modbusError(int err) {

  const byte ERROR_COUNT_ALARM = 8;

  static byte modbusErrorCounter = 0;
  static int modbusErrorCode = 0;

  if (modbusErrorCode != err) {
    modbusErrorCounter = 0;
    modbusErrorCode = err;
  }
  if (err == 0)
    return false;
  modbusErrorCounter++;
  switch (modbusErrorCounter) {
    case 1:
      Serial.print("Error Counter: ");
      Serial.println(err);
    break;
    case ERROR_COUNT_ALARM:
      Serial.print("Error Count: ");
      Serial.println(err);
      modbus.stop();
    break;
  }
  return true;
}

/*
 * return
 *   - 0 is success
 *   - negative is comm error
 *   - positive value is modbus protocol exception code
 *   - error 4 is SLAVE_DEVICE_FAILURE. Check if 'Inverter control via Modbus' is enabled.
 */
int modbusRequest(byte uid, unsigned int addr, byte len, short *regs) {

  const byte CODE_IX = 7;
  const byte ERR_CODE_IX = 8;
  const byte LENGTH_IX = 8;
  const byte DATA_IX = 9;

  int err = modbusConnection();
  if (err != 0)
    return err;

  byte request[] = {requestId++, 1, 0, 0, 0, 6, uid, FNC_READ_REGS, (byte) (addr / 256), (byte) (addr % 256), 0, len};
  modbus.write(request, sizeof(request));
  modbus.flush();

  int respDataLen = len * 2;
  byte response[max((int) DATA_IX, respDataLen)];

  while (true) {
    int readLen = modbus.readBytes(response, DATA_IX);
    if (readLen < DATA_IX) {
      return MODBUS_NO_RESPONSE;
    }
    switch (response[CODE_IX]) {
      case FNC_READ_REGS:
        break;
      case (FNC_ERR_FLAG | FNC_READ_REGS):
        return response[ERR_CODE_IX]; // 0x01, 0x02, 0x03 or 0x11
      default:
        return -3;
    }
    if ((uint8_t)(requestId - 1) != response[0]) {
      //sprintf(buff,F(" %d!=%d"), requestId - 1, (int) response[0])
      //Serial.println(buff);
      int l = response[LENGTH_IX];
      while (l > 0 && modbus.read() != -1) {
        l--;
      }
      continue; // while
    }
    readLen = modbus.readBytes(response, respDataLen);
    if (readLen < respDataLen)
      return -4;
    break;
  }
  for (int i = 0, j = 0; i < len; i++, j += 2) {
    regs[i] = response[j] * 256 + response[j + 1];
  }
  return 0;
}

int modbusConnection() {
  while (modbus.read() != -1); // clean the buffer
  if (!modbus.connected()) {
    modbus.stop();
    if (!modbus.connect(server, port))
      return MODBUS_CONNECT_ERROR;
    modbus.setTimeout(2000);
    Serial.println(F(" MB_reconnect"));
  }
  return 0;
}

void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}


you are going too fast. the inverter has other things to do than responding on modulus tcp. add some delay into loop()

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