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);
}