• Have you tried out dark mode?! Scroll to the bottom of any page to find a sun or moon icon to turn dark mode on or off!

diy solar

diy solar

EG4 6000XP - reading SoH via modbus

Ambrotos

New Member
Joined
Feb 7, 2024
Messages
39
Location
Canada
I've been referring to the EG4 Modbus protocol spec (provided by EG4 here) and successfully polling my inverter for the usual suspects (inverter state, battery voltage, PV power in, load power out, bus current, etc.) directly via a DIY modbus controller I'm working on. The one thing I haven't been able to pull is the battery state of health.

As per the spec, both State of Charge (I believe that's a typo in the document, "capacity" is register 97!), and State of Health are input register address 5. I'm not sure how to interpret that. This isn't a register with multiple states mapped to individual bits where you can apply a bitmask to extract the information you want, since elsewhere they clearly spell out which bits map to which values. A good example of this is register 71 where bits 0-3 indicate AutoTestStart, and so on. Address 5 is the only register in the doc that's overloaded like this. I've tried querying both U_INT16 and U_INT32 values from it, and I've tried applying high- and low- WORD and DWORD masks to the return value. The only result I can extract is 42, which is the correct value for my battery's current State of Charge.

Has anyone had any success pulling the battery State of Health from the inverter?

Cheers,

-A

N.B. - since the inverter aggregates all of the batteries' status information into one representation, I'm making the assumption here that battery SoH would represent the worst value reported by any of the attached batteries' BMSs.
 
Very interesting! Looking at your register map (here) made me realize that while I did try bitmasking on the WORD and D_WORD boundaries, one thing I didn't try was handling the high/low BYTES of the register as individual value. In retrospect, I'm not sure why that didn't occur to me ;) I'm going to give this a try once I'm home and have access to my inverter again.

Thanks for sharing. This might be the clue I needed.

-A
 
Very interesting! Looking at your register map (here) made me realize that while I did try bitmasking on the WORD and D_WORD boundaries, one thing I didn't try was handling the high/low BYTES of the register as individual value. In retrospect, I'm not sure why that didn't occur to me ;) I'm going to give this a try once I'm home and have access to my inverter again.

Thanks for sharing. This might be the clue I needed.

-A
Let us know if that works!
 
Let us know if that works!
Sorry, I suppose I should have updated this thread. No, unfortunately I'm still not able to poll SoH. I did check the high byte of the 16-bit return response from register 5, and it's always 0.

There aren't any other references to SoH or Health in the modbus protocol doc, and all of the references I've found online seem to be based on the project hotnoob linked above. In other words, based on the manufacturer's doc but untested.

I haven't had a lot of time to play this month, but I hope to get back to it shortly. I'll update this thread if I have any luck.

-A
 
Last edited:
Anyway to pull this data from inverter thru the 6000xp wifi dongle with out the EG4 app. Lets say directly to smart hub like Hubitat? Obviously a driver would need to be made for the hub.
 
Here is the 485 traffic captured using a 485 transceiver and a logic analyzer of a request to an EG4 18kPV (I think the 6000xp uses the same register mapping? I haven't looked at it)

modbus request:
modbus_request.png

modbus reply:

modbus_reply.png

The SOH of the battery bank is the 0x64 (100 decimal)
and the SOC is 0x63 (99 decimal)

Using the meter port there seems to be a delay of around 280 ms before the inverter will send a reply -- I've been looking at the other 485 port (the one that's shared with the wifi dongle) and might use that instead if the delay is less (although it looks like the protocol is a little different and the endianness is also different?)
 
Maybe Solar Assistant?
SA uses a raspberry pi. Place is off grid, trying to keep unnecessary device from drawing power. But will mull over there website and see if the SA data can be integrated into a smart hub so I can make rules to run or not run things bases on battery SOC. For example: if SOC is <25% do not run well pump, etc..
If EG4 has an open API then cloud data could theoretically be accessed by a smart hub. But even better if it can be access locally thru the wifi dongles IP address / port.
 
I have Solar Assistant, EG4 6000XP and ProPower Battery.

This is what I see in the settings page through SA.
1717874677194.png

This what I see in the Automation page:
1717874545228.png

Rule table options.

1717874349356.png
1717874359274.png

But there are limited triggers from there.
1717874601602.png

I hope this helps.
 
Hi guys,

Just got my 6000xp fired up and been playing around with pulling data from this unit. I tested Solar-Assistant and it works but looks pretty limited on what you can actually control. So I kept looking for alternatives and found this Home Assistant Add-on/Docker package:


It works with the Wifi Dongle over port 8000 (same as what Solar Assistant uses). You have full control over the modbus interface through MQTT.

I created some entities and switches to control Gird Charing and AC First control:

1729738915219.png

Still early days from me playing around with it.... but so far so good.
 
I too have lxp-bridge set up to monitor inverter, and it works great. But, I would much rather use serial though, as the dongles are problematic. @Ambrotos , do you mind describing how your DIY modbus controller works? What software/hardware are you using?
 
I read twice, registers 0-99 and 100-199, and then:
Code:
    # Battery SOC/SOH
    SOH = int(Inputs[5]/256)
    if PrintData: print("SOH ",SOH,"%")
    RedisDB.set(Redis_Prefix+"SOH",SOH,ex=Redis_Expire)
    MQTTpublish(MQTTclient,InverterName,"SOH",SOH)
    SOC = int(Inputs[5] & 255)
    if PrintData: print("SOC ",SOC,"%")
    RedisDB.set(Redis_Prefix+"SOC",SOC,ex=Redis_Expire)
    MQTTpublish(MQTTclient,InverterName,"SOC",SOC)
 
@diso12 Hardware-wise I'm just using an ESP32 with a RS485 to UART adapter. I also don't really like the wifi dongle implementation (security-wise, if nothing else), and besides my inverter is in an outbuilding with no wifi connectivity, so I leave the wifi dongle disconnected. I'm not sure whether it's common knowledge or not, but the HDMI connectors used for the wifi dongle are only actually using 4 of the 19 available pins -- 2 for power, and 2 for RS485 modbus comms. So by taking over that connection I can query any register I like while still leaving the standard RJ45 BMS port for battery comms.

Software-wise, I've written a pretty basic Arduino sketch that queries a bunch of registers at a fixed interval, and then publishes it to my MQTT broker for ingest.
 
@diso12 Hardware-wise I'm just using an ESP32 with a RS485 to UART adapter. I also don't really like the wifi dongle implementation (security-wise, if nothing else), and besides my inverter is in an outbuilding with no wifi connectivity, so I leave the wifi dongle disconnected. I'm not sure whether it's common knowledge or not, but the HDMI connectors used for the wifi dongle are only actually using 4 of the 19 available pins -- 2 for power, and 2 for RS485 modbus comms. So by taking over that connection I can query any register I like while still leaving the standard RJ45 BMS port for battery comms.

Software-wise, I've written a pretty basic Arduino sketch that queries a bunch of registers at a fixed interval, and then publishes it to my MQTT broker for ingest.
If you don't mind... What are the HDMI connections, can you perhaps post a screenshot of pinout here?
 
@diso12 Actually, I didn't bother with trying to figure out the HDMI connector's pinout. If you remove the 4 screws holding the wifi dongle's mounting bracket to the inverter's chassis, you'll see that inside there's just a simple PCB to adapt the HDMI connector to a standard 4-pin JST header. If memory serves, the color coding of the wires connected to the JST header makes it pretty obvious which pins are DC and which are data. I just made a corresponding male JST plug to connect to the RS485 Data A/B pins and left the DC unconnected.
 
@diso12 Actually, I didn't bother with trying to figure out the HDMI connector's pinout. If you remove the 4 screws holding the wifi dongle's mounting bracket to the inverter's chassis, you'll see that inside there's just a simple PCB to adapt the HDMI connector to a standard 4-pin JST header. If memory serves, the color coding of the wires connected to the JST header makes it pretty obvious which pins are DC and which are data. I just made a corresponding male JST plug to connect to the RS485 Data A/B pins and left the DC unconnected.
Yeah, I mean you could find an HDMI breakout like https://www.amazon.com/SinLoon-Solderless-Extension-Connector-Screwdriver/dp/B07M98XCL6 and that would force you to never plug in your RS485 while the dongle was in place, but hardwired connections are easy enough to do with the standard set of connectors inside the inverter.

My problem is remembering to shut everything else down when trying to do firmware updates and such, the inverter comms can't keep up with multiple queries _and_ other data transfer...
 
@diso12 Actually, I didn't bother with trying to figure out the HDMI connector's pinout. If you remove the 4 screws holding the wifi dongle's mounting bracket to the inverter's chassis, you'll see that inside there's just a simple PCB to adapt the HDMI connector to a standard 4-pin JST header. If memory serves, the color coding of the wires connected to the JST header makes it pretty obvious which pins are DC and which are data. I just made a corresponding male JST plug to connect to the RS485 Data A/B pins and left the DC unconnected.

could you publish an excerpt of your sketch, where the communication is made? I'm trying to understand why I am not receiving any data from the RS485, whether it's something wrong with hardware I use or I just don't use correct software. Any command I could emit via regular minicom perhaps?
 
What RS485 to UART converter are you using? I had nothing but trouble with some cheap adapter boards I bought off AliExpress initially. Things magically started working once I bought these. Also, does your model RS485 converter have a flowcontrol pin that you need to trigger to toggle between Tx and Rx?

If I could make a suggestion, since you mentioned above that you're currently running lxp-bridge it seems safe to assume you're trying to pull this data into homeassistant. If I were to redo this project again today, I'd probably save myself some hassle and write the code in esphome. Have you played with esphome at all before? Getting a modbus controller up and running is incredibly easy. I did it recently with my home hydronics' boiler to pull things like supply/return and flue temps. It also makes it really easy to do over-the-air debug logging while you're troubleshooting.
 
I have two of the four port boxes that wpns recommends above and I have also used the single port clear blue dongles that you can see the flashing lights in from Amazon. Both work terrifically well.
 
What RS485 to UART converter are you using? I had nothing but trouble with some cheap adapter boards I bought off AliExpress initially. Things magically started working once I bought these. Also, does your model RS485 converter have a flowcontrol pin that you need to trigger to toggle between Tx and Rx?

If I could make a suggestion, since you mentioned above that you're currently running lxp-bridge it seems safe to assume you're trying to pull this data into homeassistant. If I were to redo this project again today, I'd probably save myself some hassle and write the code in esphome. Have you played with esphome at all before? Getting a modbus controller up and running is incredibly easy. I did it recently with my home hydronics' boiler to pull things like supply/return and flue temps. It also makes it really easy to do over-the-air debug logging while you're troubleshooting.
Played with esphome, and agree it would be best to implement the product into it. I'm currently just trying to understand how things work. Plugged the same 485 adapter into tigo, and it sends some binary data. Plugged it into 18kpv and dead silence. Tried inverter port, and then tried the ports named RS485A/B, same thing. 18kpv literally has 485A/B ports right there, and still no go

1739151493429.png

That's my port, and whatever thing EG4 shipped to me works in it. I'll go ahead and try other RS485 adapters, see how it works
 
Any command I could emit via regular minicom perhaps?
Unfortunately, it's binary data and needs to incorporate a checksum and such. IIRC you have a Linux box, try setting up the most basic minimalmodbus script. Here's snippets from mine.

Code:
    # port name, slave address (in decimal)
    inverter = minimalmodbus.Instrument(PortName, \
                                        ModbusAddress, \
                                        debug=False, \
                                        close_port_after_each_call=True)
    inverter.serial.baudrate = 19200
    inverter.serial.timeout = 10      # 50ms default, but sometimes exceeds 3s
    inverter.serial.write_timeout = 10      # 2s default, but sometimes exceeds 3s
    #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    print("First batch, 0-99 inclusive")
  
    while attempts < retries:
        if PrintData: print("Try {}/{}".format(attempts,retries))
        try:
            Inputs = inverter.read_registers(0,100,4)     # Start, Count, FunctionCode
            for index, value in enumerate(Inputs):
                print('{:03d} {:04x} {:d}'.format(index,value,value))
            break
        except Exception as e:
            if PrintData: print("Exception: ",e)
            attempts += 1
            time.sleep(0.01)

Note that this uses the METER485 connection, it _MIGHT_ be that the INV485 connection needs the serial number encoded in the command, but METER485 doesn't.

but essentially you need to make the minimal code that'll make anything work and either debug or expand from there. I can't seem to find any of my initial stabs at reading a single register, but look through the minimalmodbus examples and I'm sure you'll figure it out.
 
Unfortunately, it's binary data and needs to incorporate a checksum and such. IIRC you have a Linux box, try setting up the most basic minimalmodbus script. Here's snippets from mine.

Code:
    # port name, slave address (in decimal)
    inverter = minimalmodbus.Instrument(PortName, \
                                        ModbusAddress, \
                                        debug=False, \
                                        close_port_after_each_call=True)
    inverter.serial.baudrate = 19200
    inverter.serial.timeout = 10      # 50ms default, but sometimes exceeds 3s
    inverter.serial.write_timeout = 10      # 2s default, but sometimes exceeds 3s
    #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    print("First batch, 0-99 inclusive")
 
    while attempts < retries:
        if PrintData: print("Try {}/{}".format(attempts,retries))
        try:
            Inputs = inverter.read_registers(0,100,4)     # Start, Count, FunctionCode
            for index, value in enumerate(Inputs):
                print('{:03d} {:04x} {:d}'.format(index,value,value))
            break
        except Exception as e:
            if PrintData: print("Exception: ",e)
            attempts += 1
            time.sleep(0.01)

Note that this uses the METER485 connection, it _MIGHT_ be that the INV485 connection needs the serial number encoded in the command, but METER485 doesn't.

but essentially you need to make the minimal code that'll make anything work and either debug or expand from there. I can't seem to find any of my initial stabs at reading a single register, but look through the minimalmodbus examples and I'm sure you'll figure it out.
This worked beautifully!!!
 
I am trying to connect to the lux Power 12k inverter through rs485 but with the commands in esphome I cannot create a valid command that returns a result, can you help me with that?
 
I am trying to connect to the lux Power 12k inverter through rs485 but with the commands in esphome I cannot create a valid command that returns a result, can you help me with that?
Not sure how similar the 12k is to the 6000xp, but assuming they share a similar protocol (and you've got your wiring sorted out), you should just need to add a few components to your .yaml in order to get basic comms working:

YAML:
uart:
  - id: rs485_uart
    tx_pin: GPIO1
    rx_pin: GPIO3
    baud_rate: 19200

modbus:
  id: modbus1
  flow_control_pin: GPIO23
  uart_id: rs485_uart

modbus_controller:
  - id: lxp6000
    address: 0x1
    modbus_id: modbus1
    command_throttle: 2s

sensor:
  - platform: modbus_controller
    modbus_controller_id: lxp6000
    name: "Battery Voltage"
    id: battery_voltage
    register_type: read
    address: 0x004
    device_class: voltage
    state_class: measurement
    unit_of_measurement: "V"
    value_type: U_WORD
    accuracy_decimals: 1
    filters:
      - multiply: 0.1   # register holds the value in deci-volts

(obviously, the tx/rx/control pins would vary depending on your ESP device)

Hope that helps.

-A
 
Hello, I have it similar, minus the flow control, is it necessary? and how do you know which GPIO to use?


esphome:
name: luxpower
friendly_name: luxpower
esp32:
board: esp32dev
framework:
type: arduino

uart:
id: mod_bus
tx_pin: GPIO1
rx_pin: GPIO3
baud_rate: 19200

# Enable logging
logger:
baud_rate: 0
# Enable Home Assistant API

ethernet:
type: LAN8720
mdc_pin: GPIO23
mdio_pin: GPIO18
clk_mode: GPIO0_IN
phy_addr: 1
power_pin: GPIO16
modbus:
# flow_control_pin: 5
id: modbus1
uart_id: mod_bus
modbus_controller:
- id: lux12k
address: 0x01
modbus_id: modbus1
command_throttle: 50ms
update_interval: 15s
on_online:
then:
- logger.log: "modbus server back online !"
on_offline:
then:
- logger.log: " modbus server goes offline !"
sensor:
- platform: modbus_controller
modbus_controller_id: lux12k
name: "Battery Voltage"
id: battery_voltage
register_type: read
address: 0x004
unit_of_measurement: "V"
value_type: U_WORD
accuracy_decimals: 1
 

diy solar

diy solar
Back
Top