jblance / mpp-solar

Python package to communicate to MPP Solar PIP-4048MS inverters (and similar)
MIT License
355 stars 149 forks source link

Full BMS support for PI17 #219

Open riogrande75 opened 2 years ago

riogrande75 commented 2 years ago

With later firmware versions (>2017) of the infini-/mpp-solar 10+15kw inverters, full bms support was implemented. Only supported BMS I'm aware of is pylontech via RS485 bus. You need a extra modbus-card (with modified fw on it) so the inverter can communicate with the bms. See http://www.mppsolar.com/manual/ACCESSORIES%20(FOR%20MONITORING)/BMS%20RS485%20Card/RS485-Card-Box-for%20BMS-manual-20181106.pdf While pylontech's rs485 bms commandos are well know, the internal communication between the (bms-)modbus card and the inverter is secret. To disclose the secret I disassamled the slave firmware of the 10k and noticed 2 PI17 commands that might be involved: BMS BMSV

The BMSV command just reads out the fw-version (date) from the plugged bms-card - so quite uninterresting.

BMSV: (BMSCARD:0000-00-00
BMSVersionTimeYear
BMSVersionTimeYear
BMSVersionTimeDay

The BMS commando seems to be more usefult to let any BMS communicate with the inverter. This is what I explored so far:

^D0520000,000,0,0000,00,0,0000,0000,0000,0,0,0000,0000
^D0520aaa,bbb,c,dddd,ee,f,gggg,hhhh,iiii,j,k,llll,mmmm

; aaa
; bbb
; c
; dddd
; ee

; j
; k 
; llll: BMS max charge curr (amps)
; mmmm: BMS max discharge curr (amps)

; ; P B M S a bbb c d e fff ggg hhh iiii jjjj<CRC><cr>
; 0 1 2 3 4 567 9 B D F01 345 789 BCDE 0123 45 6
; 0 1 2
; a : disconnect
; bbb : BMS SOC%
; c : BMS force AC charge
; d : Bat stop discharge flag
; e : Bat stop charge flag
; fff : BMS bat CV volt
; ggg : BMS Bat float volt
; hhh : BMS bat cutoff volt
; iiii: BMS max charge curr (amps)
; jjjj: BMS max discharge curr (amps)

Anyone here interrested in getting together this 2 scripts (mpp-solar + jkbms)?

jblance commented 2 years ago

Seems like you could achieve something with a specific output module, i.e

this type of output hasnt been implemented yet, but shouldnt be a problem (with a lot of testing) I'm (slowly) working on a more flexible process (powermon command in latest versions) that will allow for better configuration of inputs and outputs - seems like the above would work better with that, but the current mppsolar/jkbms commands should be able to made to work with a bunch of extra options

riogrande75 commented 2 years ago

Ok, thx. I'll investigate commands further. Some help with logfiles from other users would be very helpful. Can any of the MPI10k users pls. send me the inverter's reply for the command ^P004BMS?

riogrande75 commented 2 years ago

After a long research I've finally found out, how PI17/PI18 inverters (10k, 15k) get the BMS values.

Conclusion: You simply need to send a ^D054BMS... string periodically to the inverter. Format looks like this: BMSprot I created a script to read bms data from a mqtt server and create the ^D054BMS string that can be sent to the inverter: readmqttbms.php Sending this to the inverter let's the display show the "LI-bAt" and battery values read from BMS. 10kDisplayLiBat The inverter get's informed about BMS stoped charging/discharging and can react correctly:

LiBatWarn

@jblance Maybe you can implement this in your work - reading data from jk-bms (I do that currently with a extra ESP32 from https://forum.drbacke.de/viewtopic.php?t=982) and send it to mpp solar inverter.

gianfrdp commented 1 year ago

After a long research I've finally found out, how PI17/PI18 inverters (10k, 15k) get the BMS values.

Conclusion: You simply need to send a ^D054BMS... string periodically to the inverter.

Hello, how php script sends string to inverter? And which battery type needs to be selected on inverter to let this protocol work?

rene-dev commented 8 months ago

I have MPI 10k, and successfully used this command to set charge and discharge limits, and alarms. converting them from pylontech battery connected via can. Will share my code when its finished. ^P004BMS reply is: b'^D0520422,042,0,0000,01,0,0535,0525,0500,0,0,0500,0010\x15\xd3\r'

danieltroger commented 5 months ago

Hi, slightly off-topic because I don't need/have any BMS. But I have an MPPSolar MPI 15KW inverter and wondered how you guys were able to communicate with it using this project? I'd like to, for example, receive the current charging amperage, but the "default" mpp-solar commands don't seem to work.

Edit: I managed to communicate using protocol 17!

ubuntu@ubuntu:~$ sudo  mpp-solar -P PI17  -p /dev/hidraw0  -c INGS
Command: INGS - 
--------------------------------------------------------------------------------
Parameter                    Value              Unit
input_current_r              112                0.1A
input_current_s              116                0.1A
input_current_t              114                0.1A
output_current_r             4                  0.1A
output_current_s             92                 0.1A
output_current_t             7                  0.1A
pbusvolt                     4142               0.1V
nbusvolt                     4142               0.1V
pbusavgv                     4135               0.1V
nbusavgv                     4137               0.1V
nlintcur                     0                  0.1A
unknown_value_in_response_11 0007                   
unknown_value_in_response_12 0090                   
------------------------------------
ubuntu@ubuntu:~$ sudo  mpp-solar -P PI17  -p /dev/hidraw0  -c PS
Command: PS - Device Power Status
--------------------------------------------------------------------------------
Parameter                      Value            Unit
solar_input_power_1            2529             W   
solar_input_power_2            3669             W   
ac_input_active_power_r        1959             W   
ac_input_active_power_s        -1927            W   
ac_input_active_power_t        -1835            W   
ac_input_total_active_power    -5721            W   
ac_output_active_power_r       14               W   
ac_output_active_power_s       78               W   
ac_output_active_power_t       179              W   
ac_output_total_active_power   252              W   
ac_output_apparent_power_r     119              VA  
ac_output_apparent_power_s     94               VA  
ac_output_apparent_power_t     236              VA  
ac_output_total_apparent_power 450              VA  
ac_output_power_percentage     3                %   
ac_output_connect_status       Connected            
solar_input_1_work_status      Working              
solar_input_2_work_status      Working              
battery_power_direction        Charging             
dc/ac_power_direction          DC to AC             
line_power_direction           Output               
--------------------------------------------------------------------------------
PaulEPop commented 3 months ago

It would be wonderfull, that we could communicate like a BMS to MPP-inverters! Many BMS have a problem with inverters from MPP (12k / 15k)

riogrande75 commented 3 months ago

In fact BMS comms to MPP/FSP/Voltrinic hybrid inverters (10/15k) is quite easy. I run it with my php scripts since more than 2 years witout any issue. All you need is the information from my post above. Issue #485 would be solved with this too, as inverter changes internal charging voltage/current settings according to bms information.

As far as I understand this project, it's "simply" pulling data from inverters and bms' for using this data in 3rd pty visualization. For bms comms to work, data from bms need to be processed and sent to the inverter.

@jblance Is bms->inverter comms on the 2do list, or will it never be implemented anyway. Off course, pulled data from bms (e.g. jk) would have to be temporarily stored on the machine and then be sent to the inverter while quering production data. Off course I'd assist in implementing, even my python abilities are quite low.

PaulEPop commented 3 months ago

Hi riogrande75, I have noticed, you are the one from Dr. Backe. :) You have wrote 'Die Daten vom BMS kommen via ESP32bei mir am Mosquitto an' The link doesn't work, So I can't see the basics for the ESP32 / ESP8266. It's possible to share this information to us? Do you read the information from the BMS internal rs485 port or CAN/rs485?

riogrande75 commented 3 months ago

The link doesn't work anymore. I used a ESP32 that reads data from JK via BLE and pushes these values on a mqtt server via WiFi. Everything is described here jkbms-auslesen-ueber-ble-bluetooth-oder-rs485-adapter-mittels-eps-iobroker. But there are similar other projects that will do the job.

jblance commented 3 months ago

As far as I understand this project, it's "simply" pulling data from inverters and bms' for using this data in 3rd pty visualization. For bms comms to work, data from bms need to be processed and sent to the inverter.

This is pretty close - it simply runs a command (any inverter or other device command) and outputs it (to a variety of outputs including mqtt)

@jblance Is bms->inverter comms on the 2do list, or will it never be implemented anyway. Off course, pulled data from bms (e.g. jk) would have to be temporarily stored on the machine and then be sent to the inverter while quering production data. Off course I'd assist in implementing, even my python abilities are quite low.

It is, probably in the powermon codebase though (as mppsolar is creaking at the seams a bit) I havent figured out what the inverter logic is for BMS integration is it: 1- just needs a 'command' that contains BMS data 2- needs to send a command (to the BMS) and then get a correctly formated response 3- something else ???

How does you php logic work?

riogrande75 commented 3 months ago

There is no start command, etc. for BMS comms to start working. You simply send the ^D054BMS... command in cycles to the inverter. I do it every 5 seconds inbetween my queries for production data (^P003GS,...). After a few seconds the inverter starts displaying "Li-Bat" in it's display and updates battery charging&discharging settings with the values presented by the BMS.

I created this php script that pulls data from jk bms and prepares the BMS string in a shared mem obj as well as pushing values to mqtt for my hassio battery monitoring. My script that reads all needed values from the inverter opens this shmop and sends the contents to the inverter (line 370ff).

There is in fact no communication in direction downwards from the inverter to bms. Obviously not needed.

PaulEPop commented 3 months ago

Hi, i will use my words: Einfach Endgeil hier.... I have to modify your php script (I will try), because I'm using the direct connection via rs232 and I need just the BMS funktionality.

riogrande75 commented 3 months ago

Hi, i will use my words: Einfach Endgeil hier.... I have to modify your php script (I will try), because I'm using the direct connection via rs232 and I need just the BMS funktionality.

Well, I guess that shouldn't be a big deal with the code I posted. Big difference to the query command 's is to prepare the BMS string's CRC (crc16-xmodem).

PaulEPop commented 3 months ago

Do you get a response to the following command?

$serial->sendMessage($bmscmd.chr(hexdec($bmscrc1)).chr(hexdec($bmscrc2)).chr(0x0d));

In my case the log looks like this: (BMS1 without CRC, BMS2 with CRC) 2024-06-06 23:13:12: BMS_1: ^D054BMS0554,098,0,0000,00,0,0552,0552,1500,1,1,0504,150 2024-06-06 23:13:12: BMS_2: ^D054BMS0554,098,0,0000,00,0,0552,0552,1500,1,1,0504,1506# string(0) ""

I'm sending just 'BMS_2' Serial connection is running well,I will receive correct responses to ID requests. I have a MPP-SOLAR MPI12K (PI17 Protokoll)

riogrande75 commented 3 months ago

Your string is too long, it's more than 54 (^D054) characters long. Fault see pic. grafik Off course I don't see the CRC you send in your post.

PaulEPop commented 3 months ago

I have changed your code in readmqttbms.php from: shmop_write($sh_bms1, ",00", 23); to shmop_write($sh_bms1, ",0", 23);

Result ^D054BMS0539,077,1,0039,0#,0,0552,0552,1500,1,1,0504,150

PaulEPop commented 3 months ago

I have now the following datapackage $bmscmd = ^D054BMS0531,094,0,0019,0,0,0560,0560,1500,1,1,0504,2000 (from shmop_read...)

this package is going thrue your script

       if($bms){
                $bmscmd = shmop_read($sh_bms, 0, 56);
                $bmscrc = paddings(genCRC($bmscmd),4);
                $bmscrc1 = substr($bmscrc,-4,2);
                $bmscrc2 = substr($bmscrc,-2);
                if($debug) logging("BMS_1: ".$bmscmd); 
                if($debug) logging("BMS_2: ".$bmscmd.chr(hexdec($bmscrc1)).chr(hexdec($bmscrc2)).chr(0x0d));
                $serial->sendMessage($bmscmd.chr(hexdec($bmscrc1)).chr(hexdec($bmscrc2)).chr(0x0d));

output in console: 2024-06-07 21:42:00: BMS_1: ^D054BMS0531,093,0,0020,0,0,0560,0560,1500,1,1,0504,2000 2024-06-07 21:42:00: BMS_2: ^D054BMS0531,093,0,0020,0,0,0560,0560,1500,1,1,0504,2000Rt

But inverter don't switch to LI-Mode

riogrande75 commented 3 months ago

What FW version is on your inverter? Can you post the string in 'hex to see if crc is ok?

PaulEPop commented 3 months ago

2024-06-08 22:58:51: BMS_1: ^D054BMS0531,090,0,0015,0,0,0560,0560,1500,1,1,0504,2000 2024-06-08 22:58:51: BMS_2: ^D054BMS0531,090,0,0015,0,0,0560,0560,1500,1,1,0504,2000▒▒ 2024-06-08 22:58:51: CRC+0x0d: eed9d

for the BMS_1 string I have used Python to 'verhexen' . BMS_1: 5e44303534424d53303533312c3039302c302c303031352c302c302c303536302c303536302c313530302c312c312c303530342c32303030

DSP-Version: 211222123000 MCU-Version: 211222123000

riogrande75 commented 3 months ago

FW version is ok. Looking at your output, it seems that "verhexen" of BMS_1 did not include CRC.

When I do it with your BMS string and my code the hex string looks like this. 5E44303534424D53303533312C3039302C302C303031352C302C302C303536302C303536302C313530302C312C312C303530342C32303030EED90D Make sure that the character at the end is 0x0d and not simply "d"

PaulEPop commented 3 months ago

The hex value is converted into a chr and transferred. I use exactly your code for this. $serial->sendMessage($bmscmd.chr(hexdec($bmscrc1)).chr(hexdec($bmscrc2)).chr(0x0d)); Further up I use the following code, to which I get the corresponding answer.

$serial->sendMessage("^P003PI".chr(0x0d)); //QPI Protocol ID abfragen 6byte
$antw = $serial->readPort();

My guess is that the MPI12k does not recognize the ^D054... command, I don't get a response to the ^P004BMS request either.

riogrande75 commented 3 months ago

Ahhh, a MPI 12k WP.... Ok, that could be the case, as the inverter has a built in BMS card/port and does not need to be able to receive BMS commands via serial port.

If you have a firmware update for your inverter, I can disassamble it and check if the command is really missing or it has been modified.

rene-dev commented 3 months ago

you can also look at my script which sends the bms command: https://github.com/rene-dev/solar/blob/master/mqtt.py#L102

PaulEPop commented 3 months ago

I have testet a snipset of your pythoncode with serial. I have got b'^0\x1b\xe3\r' as answer for the ^D054 command For the test I used fixed values:

cmd = f"^D054BMS{'0556'},{98},{1},{'0050'},{0},{0},{'0562'},{'0562'},{'0200'},{1},{1},{'0500'},{'0250'}".encode()
crc = crc16(cmd)
cmd = cmd + (crc >> 8).to_bytes(1, "big") + (crc&0xff).to_bytes(1, "big") + b'\r'

I have to add "big", without I have got an error message from Python

cmd = cmd + (crc >> 8).to_bytes(1) + (crc&0xff).to_bytes(1) + b'\r'
TypeError: to_bytes() missing required argument 'byteorder' (pos 2)

With ^P003ID --> b'^D0251496162206100759000000@\x90\r' Serial com is running well. D054 is unknown for MPI12k. @riogrande75 : I have asked MPP-Solar for an Firmwareupdate.

Thank you very much for your kind help.

riogrande75 commented 3 months ago

Did you activate BMS and set battery mode to LiFe in solarpower? Did you try sending the bms command cyclic for some minutes? Even my inverters need some time to recognize bms command and show it in display.

If you have a RS485 BMS port on your MPI 12k WP, why do you frickle arround with bms command instead of using a esp32 for directly connecting jk with the inv? You could also use a simple serial2eth converter and send reply's via bms port as a last resort.

PaulEPop commented 3 months ago

I have tried everything, the commands was sendind more than 12h. You mean mppsolar-lib-protocol-to-jk-bms-rs485? The BMS isn't a JK, it' a Seplos. So I cant use this project direct and I'm not a softwareengineer just a verry little hobby coder with limited skills. :)

riogrande75 commented 3 months ago

We're OT for a long time 🫣

Pls. leave this git issue and read how to connect a seplos directly to your inverter. SEPLOS "speaks" pylontech protocol, it can be connected with a simple cable, and the correct setup, off course.