Reading SMA inverters, e.g. STP5000TL via MODBUS

Moderators: grovkillen, Stuntteam, TD-er

Post Reply
Message
Author
s0170071
Normal user
Posts: 36
Joined: 21 Oct 2017, 20:49

Reading SMA inverters, e.g. STP5000TL via MODBUS

#1 Post by s0170071 » 04 Mar 2018, 16:02

Hi there,
a question thats often asked but almost never answered is how to read the current output power of SMA inverters.
If you have a model with ethernet connection (SMA calls it speedwire :)) then there is a solution for you.
I share my proof of concept code right now so it doesn't get lost. I will also add an ESPEasy plugin to the playground later.

No need to grab the numbers from the web interface or buy an expensive home manager. Use MODBUS /TCP. Its like a serial interface (e.g. RS232) but over TCP/IP. Put a request in a packet, send it to <yourSMAIP> port,502 and wait for the return packet. Note: you have to turn on the TCP server of your inverter. Its off by default. In order to do that with your "sunny explorer" software (Windows, https://www.sma.de/en/service/downloads.html). Log in as installer and click your way through it.

There is quite a number of registers to read from, I was just interested in reg 40200 which holds the currently generated power. Find the register description here: https://www.sma.de/en/products/solarinv ... 000tl.html


Code: Select all

#include <ESP8266WiFi.h>
const char request[12] = {0, 1, 0, 0, 0, 6, 0x7e, 4, 0x9d, 7, 0, 1};
/*
  get SMA STPx000TL Modbus ("sunspec") datasheet here: https://www.sma.de/en/products/solarinverters/sunny-tripower-5000tl-12000tl.html
  Request 12 bytes:
  00 01 (Transaction id)
  00 00 (Protocol ID)
  00 06 (bytes following / length: 6)
  7e (unit ID 126 / is always 126 no matter what you configured)
  04 (Function code: read register)
  9d 07 (register 40199 (actual power)) note: according to datasheet: use register number-1 (40200-1)
  00 01  (words to read: 0001)
*/
const char* SMAInverterIP     = "192.168.1.41"; // adapt that...
const char* ssid     = "YOURSSID";
const char* password = "YOURPWD";

WiFiClient client;

unsigned int sendRequest() {

  if (!client.connect(SMAInverterIP, 502)){ //MODBUS port is always 502 
    Serial.println("connection failed") ;
    return 0; 
  }
  
  client.write(&request[0], sizeof(request));
  Serial.print("sending: ");  for (int i = 0; i < sizeof(request); i++) {
    Serial.print(request[i], HEX);
    Serial.print(" ");
  }
  return 1; 
}

unsigned int getData()
{

  unsigned long timeout = millis();
  while (client.available() < 11) {
    delay(1); // important to service the tcp stack
    if (millis() - timeout > 5000) {
      Serial.println(">>> Client Timeout !");
      client.stop();
      return 0;
    }
  }

  // Read all the lines of the reply from server and print them to Serial
  uint16_t watts = 0;
  int bytesToReceive = client.available();
  /*
    Response 11 bytes:
    00 01 (Transaction id)
    00 00 (Protocol ID)
    00 05 (length 5)
    7e (unit ID 126)
    04 (Function code: read register)
    02 (byte count 2)
    00 eb ( Data / Power in 10W, e.g. (235 *10 Watts))
  */
  uint16_t high,low;
  Serial.print(" >>  receiving: ");;
  for (int a = 0; a < bytesToReceive - 2; a++) {
    Serial.print(client.read(), HEX);  Serial.print(" ");
  }
  high = client.read();  Serial.print(high, HEX);  Serial.print(" ");
  low = client.read();  Serial.print(low, HEX);  Serial.println();
  watts = 10* ((high << 8) + low) ;
  Serial.print(watts); Serial.println( " W");
  return watts;

}

void setup() {
  Serial.begin(115200);
  Serial.println("\n\nboooot...\n\n");

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}




void loop() {
  if (sendRequest())
    getData();
  delay(500);
} 

TD-er
Core team member
Posts: 8739
Joined: 01 Sep 2017, 22:13
Location: the Netherlands
Contact:

Re: Reading SMA inverters, e.g. STP5000TL via MODBUS

#2 Post by TD-er » 04 Mar 2018, 16:46

There is also a list of other plugins on my "list" which need Modbus.
For example the Senseair CO2 modules, Eastron power modules and some more.
Therefore I wanted to have a separate Modbus layer, comparable with how I2C is currently done in ESPeasy.
For this, I had this bookmark staged: http://en.trialcommand.com/blog/esp8266 ... libraries/ (not sure if it is usable)
And also part of Modbus already implemented in this plugin test of myself: https://github.com/TD-er/ESPEasy/commit ... e/senseair

s0170071
Normal user
Posts: 36
Joined: 21 Oct 2017, 20:49

Re: Reading SMA inverters, e.g. STP5000TL via MODBUS

#3 Post by s0170071 » 05 Mar 2018, 07:17

For a start we could inplement support for reading and writing single registers. The protocol itself is fairly simple- there is not even a checksum. What took me the most effort was figuring out that the slave only reponds if you ask not only the register but also the correct amount of bytes to read... And sometimes you have to read whole blocks at once.
I need to look at the I2C implementation.

Post Reply

Who is online

Users browsing this forum: No registered users and 93 guests