tobiasfaust / SolaxModbusGateway

Modbus RTU to MQTT Gateway
GNU General Public License v3.0
55 stars 17 forks source link

Just read total energy from inverter #19

Closed cob555 closed 4 months ago

cob555 commented 1 year ago

Hello. This is a nice project, but waaaaay to comprehensive for my needs. It would be enough, to read the total produced energy out and have this value displayed on a little LCD or 'even' on a HTML-page via asyncwebserver.

I have run the test-script on a ESP32 and got at least some answer from the inverter: "07" Not via the serial port (can't get the PC to the inverter), but on the LCD. The code was modified a bit and I don't even know if it can display the whole serial number of the inverter this way.

`#include

include

define RX 16 // UART2 RX

define TX 17 // UART2 TX

define RTS_pin 5 // RS485 Direction control

define RS485Transmit HIGH

define RS485Receive LOW

// set the LCD number of columns and rows int lcdColumns = 16; int lcdRows = 2;

//LCD SCL: Pin 22; SDA: Pin 21 // set LCD address, number of columns and rows // if you don't know your display address, run an I2C scanner sketch LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);

void setup(){ // initialize LCD lcd.init(); // turn on LCD backlight
lcd.backlight();

pinMode(RTS_pin, OUTPUT); digitalWrite(RTS_pin, RS485Receive);

// Start the built-in serial port, for Serial Monitor Serial.begin(115200); Serial.println("Test RS485 Connection");

lcd.setCursor(0, 0); lcd.print("Test RS485");

// Start the Modbus serial Port Serial2.begin(19200, SERIAL_8N1, RX, TX); delay(1000);

while(Serial2.available()) { Serial.print(Serial2.read(), HEX); Serial.print(" "); }

delay(1000);

} uint16_t Calc_CRC(uint8_t* message, uint8_t len) { //Calc the raw_msg_data_byte CRC code

uint16_t crc = 0xFFFF; for (int pos = 0; pos < len; pos++) { crc ^= (uint16_t)message[pos]; // XOR byte into least sig.byte of crc for (int i = 8; i != 0; i--) { // Loop over each bit if ((crc & 0x0001) != 0) { // If the LSB is set crc >>= 1; // Shift right and XOR 0xA001 crc ^= 0xA001; } else // Else LSB is not set crc >>= 1; // Just shift right } }

return crc; }

String Hex2String(uint8_t num) { char hexCar[2];

sprintf(hexCar, "0x%02X", num); return hexCar; }

void loop(){ byte request[] = {0x01, 0x03, 0x00, 0x00, 0x00, 0x07, // 0x0D - 14 stellen, Inverter + Modulname 0x00, 0x00 }; //

uint16_t crc = Calc_CRC(request, sizeof(request)-2); request[sizeof(request)-1] = highByte(crc); request[sizeof(request)-2] = lowByte(crc);

Serial.println("Schreibe Daten ...."); for(uint8_t i=0; i<sizeof(request); i++){ Serial.print(Hex2String(request[i]));Serial.print(' '); } Serial.println("");

digitalWrite(RTS_pin, RS485Transmit); Serial2.write(request, sizeof(request)); Serial2.flush(); digitalWrite(RTS_pin,RS485Receive);

delay(100); Serial.println("Lese Daten ....");

while(Serial2.available()) { Serial.print(Serial2.read(), HEX); Serial.print(" ");

lcd.setCursor(0, 1); lcd.print(Serial2.read(), HEX); } Serial.println(""); delay(2000);

}`

How would the request to the inverter has to be changed, to read the total energy? Is this even possible with this code?

Best regards, Mathias

tobiasfaust commented 1 year ago

Ver 3.1 has 40 instead of the 16, but the last position for the MIC is 128 which is after the 40, so after the first 40 are polled I assumed then the next 40 would be polled and so on until 128 was reached.

"position": [129, 130, 127, 128], "name": "ConsumeInEnergy", "realname": "ConsumeIn Energy", "datatype": "float", "factor": 0.01, "unit": "kWh"

Hi, To get all 128 values, i have to request 40 Register? Its Right? Precondition is Version 3.1 ?

"RequestLiveData": [ ["#ClientID", "0x04", "0x04", "0x00", "0x00", "0x28"] ],

Hex 0x28 -> decimal 40 -> expecting 80 returned values Hex 0x16 -> decimal 22 -> expecting 44 returned values

how is your current working register.h section? Its identical with https://github.com/tobiasfaust/SolaxModbusGateway/issues/19#issuecomment-1598827074 ??

btw: I‘m a little bit surprised anyway because by requesting 1 register you will get 2 values (2x 8bit -> a 16bit value) And i dont know what has happened to get 128 values by requesting only 22 (0x16) (should be 44 values get back) or 40 (0x28) register (should be 80 register get back)

kommando828 commented 1 year ago

how is your current working register.h section? Its identical with #19 (comment) ??

Its taken directly from the folder the last build and load to ESP32 which is running and the screenshots are of this so yes identical.

I‘m a little bit surprised anyway because by requesting 1 register you will get 2 value

This RS485 is new to me but from looking at the Solax pdf then the ID is held in 7 registers but each register holds 2 characters to give the 14 digit SN.

kommando828 commented 1 year ago

Its possible to upgrade the firmware?

Yes vis Solax support. I am on 1.42 but the PDF says 1.37 which matches the info ref the HA Solax integration Wiki. In the settings menu under about it gives you the firmware version

Maybe with a newer firmware modbus support is enabled by default?

I can't remember if my setting was enabled by default but it was a setting I looked at as soon as I got the inverter hooked up to AC and 100v DC. I also set the Modbus address to 1.

When my wire was the old network cable I got the flashing RX/TX lights to say the wiring was correct and working, but it wasn't working.

I have attached the latest manual for the XB33, some settings are not on the XB32 but its more complete than previous versions.

320101034604+X1-BOOST+G3.3+user+manual+20221108+EN.pdf

tobiasfaust commented 1 year ago

I‘m a little bit surprised anyway because by requesting 1 register you will get 2 value

This RS485 is new to me but from looking at the Solax pdf then the ID is held in 7 registers but each register holds 2 characters to give the 14 digit SN.

yes, 1 register holds 2 values. 1 character needs 8bit -> 1 value. So 1 register is able to hold 2 characters

kommando828 commented 1 year ago

Of course there is always the possibility Solax have not followed RS485 standards and the response is incorrect ie they are returning more registers than requested. E.g. would you expect an error message to be thrown back once a register poll goes past 64 registers. On your Solax if set the polling to outside the expected live data range do you get the same error message 'undefined'.

cob555 commented 1 year ago

I still don't get any response from the inverter. The Modbus-signal looks fine, 'crisp' edges and about +/-3V amplitude. No idea, why it was blinking simultaneously the other day, and that still seem a bit suspicious to me. Tx blinking first, and with a little delay Rx for the response makes more sense (the SDM120 behaves this way).

tobiasfaust commented 1 year ago

With the example sketch you can do anything by changing request string or whatever, standard or non-standard modbus protocols. But the most important fact is, your inverter must reply a valid and successfully answer ;)

cob555 commented 1 year ago

And your code also works with a RS485-converter without RTS-pin?

I tried to get some data from a SDM120 with this code, also with no success. However I'm not sure how to deal with the checksum-part of the code. SDM120 Neither a request with or without error check "0x71,0xCB" gives a response.

kommando828 commented 1 year ago

I had a RS485 Janitza meter arrive yesterday, hooked up my USB RS485 to PC and meter and got nothing. Tested voltage at the RS485 and got 0.73 volts, not good. Then the only tool left in the box, until replacements arrive, which is a RS485 to TCP/IP converter and hooked that up, PC could connect over LAN. Tested voltage at RS485 at converter and got 3V so your 3V should work.

Has your program connected successfully to any RS485 equipment, if not then I would use Tobias code.

cob555 commented 1 year ago

This is the code which works fine for the SDM120: https://github.com/masteripul/sdm120/blob/main/sdm120.ino If I change one of the read-registers to getRTU(0x0423); gives no response.

As mentioned, with Tobias code I don't get a response from the SDM120 either.

What hardware do you use for your testing?

kommando828 commented 1 year ago

I would not do it as it adds another variable and you want to reduce not increase the variables but what I used, as my inverter is outside on a wall, is a Hi-flying EW11. This connects to the RS485 and set as a server will broadcast Modbus on a LAN and then I used CAS to poll registers as per previous posts. Alternatively you can have a second EW11 on an RS485 master with the EW11 set as a client to convert the LAN signals back to RS485. But I have used them for years to connect outside inverters and they have their own foibles such as the WAN settings dialog box actually where you put the LAN settings. Once CAS showed the RS485 was working I then put the ESP32 connected directly to the Solax Boost RS485 wires.

kommando828 commented 1 year ago

Read post 1 in this closed issue.

https://github.com/tobiasfaust/SolaxModbusGateway/issues/1

Add a wire from the ref GND pin on the X1-Boost RJ45 to a GND pin on the RS485/TTL board and if the RS485 board supports it add a direction wire.

The ref GND will reduce noise on the RS485 signal.

cob555 commented 1 year ago

It's ALIVE! Finally a success, not with Tobias script, but with a "USB-Modbus-sniffer" and a proper Modbus-decoding-software mind you. And without a additional GND-connection, but since it doesn't hurt, and comes for free in a RJ45-cable, I will connect it later.

That's the response for 50 registers, starting at 0x400. Solax_Modbus_response_full

And here only the request for 'total yield' at register 423 (accidentally started reading at register 422, since the software is adding 1 to the decimal value of the hex-number, which got me a bit confused). Solax_Modbus_response_TotalYeald It show's the correct value of "31614" which is 3161.4kWh

Now I know, which request gives a correct response. The request generated by the ESP32 was way shorter, if memory serves me correct.

So far, so good. Only thing left, convincing the ESP32 to generate the correct request-string (easier said than done, I'm afraid)

tobiasfaust commented 1 year ago

Your first schreenshot shows your polling is the Same like the „MIC“ settings. That live registers start at 0x0400 too.

Please exchange the Same request string in example sketch, it should answer the same

0x01 0x04 0x04 0x00 0x00 0x032

If that works you can continue with your specific 0x0423 Register.

cob555 commented 1 year ago

I'm sorry, but your code does not generate the same request. For register 0422 the Modbus-software generates: 01 04 04 22 00 02 D0 F1 Your code generates (from byte-request 01 04 04 22 00 02): 01 04 04 22 2B 00

Obviously the "number of points high and low-bits" are missing. No wonder the inverter does not reply.

kommando828 commented 1 year ago

That is the same CAS software I was using but set to look for an IP and port. Strangely it successfully discovers the Janitza meter but then will not poll it, where as it would not discover the X1-Boost but could poll it once I set the IP and ID. Possibly due to RS485 being a very open standard so each implementation has its foibles so it seems you cannot reply on one piece of software to universally work.

tobiasfaust commented 1 year ago

I dont understand it :(

If you put the String 01 04 04 22 00 02 into sketch, CRC checksum will be added so 6+2 Bytes will send .

in your Post you forgot the last 2 Bytes i think.

cob555 commented 1 year ago

There are no missing bytes in the "byte request"-part of the code (I wish it would be that easy :-D ) Solax_ESP The last two bytes are overwritten by the check sum. If I add two "zero-dummy-bytes" to the request, the correct string is being generated. But even then the inverter does not reply. Solax_ESP1 Soooo....what...? Timing-issue? Or is the ESP32 not actually transmitting, what the serial monitor says is being transmitted? Seems so, why would the inverter not respond otherwise....

The communication via RS485-USB-Dongle is still working fine by the way.

I have to look for another Modbus-software, which can also only read whatever protocol is transmitted (decoding via oscilloscope would be the last resort).

tobiasfaust commented 1 year ago

Ahhh, You forgot the Last 2 template Bytes 0x00 as are in original example They will replaced with CRC (Not added)

Edit: i see you have already done that

Have you ever tested my original Firmware, Not the example? Use the MIC setting . I dont know what you have changed all there.

cob555 commented 1 year ago

No, I have not tested the original firmware, since I don't really know, where/how to install it. And no changes were made to the test-script.

But I got a result for total and today yeald with the Modbus-script for the SDM120 which I butchered a bit. Solax_ESP2

Unfortunately, it is not so easy, to get some data from the X1-Mini in the same way.

cob555 commented 1 year ago

I found the culprit. The Arduino-package with it's libraries (all new installed) on the laptop generates a different check-sum as my PC with a slightly older installation...unbelievable... Flashing the ESP32 via PC and hooking it up to the laptop for testing gives the expected result.

tobiasfaust commented 4 months ago

closed due inactivity