Universal Solar Inverter over Modbus RS485 / TCP custom_component (Growatt, Sofar, SolaX, Solis)

I tried it and it works good!

Just a thought, is it possible to divide the “platform -sensors” into different “groups” so that you can have different scan intervals? Things like battery typ, serial nr, states etc would be enough to read much less than current production. Or wont the inverter like to answer two calls?

I’m trying to read multiple registers at once and then split them into separate sensors.
That way there is less load on the ModBus bus as you can read them in a single transaction
read register 0 - 10, spit out the individual numbers
instead of read register 0, then read register 1, then read register 2 etc

But I am failing at getting my head around it at the min:

2 Likes

Thanks @wills106 for your hard work on this, it’s really useful. For the past year or so I’ve been scraping data from the web server available over the pocket wifi, but really wanted something a little more robust that didn’t tie up a Pi sitting attached to the Solax access point. So your work here really helped move me forward. I’m especially excited to get stuck in to some automation around charging.

I’ve got a X1-RetroFit-3.7 battery inverter in addition to a X1-Boost-3.6 for the solar. Right now I’m focused on the battery system. The X1ac file you produced works well for it, modified to use the LAN rather than RS485 connection.

I have discovered a couple of additional registers I’ve confirmed on my system:

    - name: SolaX Import Today
      hub: SolaX
      unit_of_measurement: kWh
      register: 154
      register_type: input
      scale: 0.01
      precision: 2
    - name: SolaX Charged Today
      hub: SolaX
      unit_of_measurement: kWh
      register: 145
      register_type: input
      scale: 0.1
      precision: 1

These reflect how much energy has gone into the battery today, and how much energy has been imported from the grid (measured by the external meter attached to the inverted in my case). I suspect daily grid export should be available too, but there’s not been enough sun today to have a measurable value to check against!

I know from the web server data (and the on-device screen) there are a bunch of cumulative counters too, like lifetime import/export for the inverter and meter. I’ve not pinned these down yet. I suspect they overflow 16 bits, so may well be spread across registers. I intend to spend some more time on that soon.

One other thing I found with my inverter was I need to authenticate before I can write to the registers to change anything. The authentication seems to last some unspecified amount of time. I discovered this because I authenticated first in the SolaX app and magically the controls started working for a short while.

You can see the extra step here, though I should replace the PIN with a secret of course…

  - alias: Solax ForceTime
    trigger:
      platform: state
      entity_id: input_boolean.solax_forcetime
      to: 'on'
    action:
    - service: modbus.write_register # authenticate
      data_template:
        hub: SolaX
        unit: '1'
        address: '0'
        value: '2014'
    - delay: '00:00:01'
    - service: modbus.write_register # Force Time Mode
      data_template:
        hub: SolaX
        unit: '1'
        address: '31'
        value: '1'
    - delay: '00:00:01'
    - service: modbus.write_register # 2nd Force Time Mode incase Inverter missed first
      data_template:
        hub: SolaX
        unit: '1'
        address: '31'
        value: '1'

It’s worked every time since.

Glad you have found it useful.
I have access to the full register list, I haven’t added anymore yet as I am trying to get my head around reading multiple registers in one go.

You shouldn’t need to “authenticate” the inverter. (Password input was only needed on really old inverters)
There can be a delay in force-time working during the night when there is no solar activity, so it may look like it’s not doing anything at first.

If you read Holding register 139, it should confirm it’s in force-time mode before the battery starts to take charge.

I wouldn’t worry about making 2014 a secret, it’s the default along with the higher level 6868

Now that reading multiple registers has been fixed in an upcoming PR

I will restart on moving this over to reading multiple registers in a single transaction.

Instead of reading
register: 0
and then
register: 1
and then
register: 2
etc you can replace it with:

    - name: SolaX Group Test
      hub: SolaX
      register: 0
      register_type: input
      count: 10
      data_type: custom
      structure: ">10h"

Which would return:
2423,15,294,1246,1207,0,1,5007,34,2
This can then be split into separate sensors through templating.

The benefit of this is that it will reduce the load on the Inverter ModBus bus, which will allow for a quicker response on register updates and will hopefully prevent / reduce missed writes to the inverter.

Ie:

  - alias: Solax ForceTime
    trigger:
      platform: state
      entity_id: input_boolean.solax_forcetime
      to: 'on'
    action:
    - service: modbus.write_register # Force Time Mode
      data_template:
        hub: SolaX
        unit: '255'
        address: '31'
        value: '1'
    - delay: '00:00:01'
    - service: modbus.write_register # 2nd Force Time Mode incase Inverter missed first
      data_template:
        hub: SolaX
        unit: '255'
        address: '31'
        value: '1'

Which can be replaced with a single write_register:

  - alias: Solax ForceTime
    trigger:
      platform: state
      entity_id: input_boolean.solax_forcetime
      to: 'on'
    action:
    - service: modbus.write_register # Force Time Mode
      data_template:
        hub: SolaX
        unit: '255'
        address: '31'
        value: '1'
2 Likes

Hi guys,

I have problems to wake my inverter from idle mode, what is the register to write? and what value?
My inverter is x1_hybrid with a triple power battery

thanks

If you read Holding register 139, it should confirm if it’s in force-time mode before the battery starts to take charge.

A few posts above give the meaning’s to the different values.

If you want to charge the battery during the night after the sun has gone to bed, the inverter needs to go through a check stage. So the inverter can appear like it’s doing nothing! It can take a min or two to respond and appear like it’s doing anything.

Also try changing your scan_interval: to a higher number, as the current method can flood the ModBus bus. Hence me wanting to read multiple registers at once!

I have observed that the only way to wake up is swtching on the “cluster control” in the app. what is the registry to activate the remote control?

I have increase the scan interval to 20, is it enough?

Should be more than enough, mine runs fine at 2 I know some have had to increase theirs to 7 / 8 to work reliably.

Do you have more than one inverter?

I would try reading Holding register 139 when you do a force charge, see if the value changes correctly and then give it enough time to react / complete checks.

Edit:

I can display some of the check sequence / times as a sensor by the looks of it. Will have a proper look at some point.

Thanks wills106 for your fast response.

I only have one inverter, in the “super” menu in the app, appears “cluster control”. I have only one inverter. I supose that means “remote control”. When I active that option, the system wait that I set the power output.

I have a sensor with the 139 register and I can check when I change the use_mode. The problem come because in idle mode the inverter doesn’t react after a mode changed throuth the 31 register.

I assume that I have to activate the “cluster control” to wake up the system, but I don’t know what register is.

I have never had to “activate” any modes.
I would just give the Inverter time to see what happens.
Like I say I think I can provide a “check” or “countdown” sensor to see if the Inverter is waking up so to speak.

I have been busy working on moving over to reading multiple registers at once.
I am down to only 3 reads on the ModBus bus now, with added functionality.
I may add some more later depending on what else looks interesting.

Now you can see what mode your inverter is in, min / max battery charge values etc.

Sneak peak:

I am using temples to unpack the multiple registers.

2 Likes

It’s possible the X1-Retrofit (or mine at least, from 2018) uses older software then. I can confirm that holding register 139 continues to indicate self use when switching if there’s not been a recent authentication. Same issue when adjusting any of the charge/discharge/min charge parameters.

I’ve had similar issues, when the inverter has been in Idle mode for too long, it becomes unresponsive to nearly all commands. Looking on the inverter itself, many of the menu items are missing when in this state and it reports a “DSP-COMMS failure”. It only wakes up when the inverter senses enough excess power to charge, there’s a scheduled force-time use, or by activating “Battery awaken” from the Advanced menu.

I’ve not been able to determine a way to remotely wake it, so I’ve implemented a simple workaround using a couple of automations to disable discharge a little above the min battery threshold, and re-enable it when it’s sufficiently charged above that point. This prevents entering Idle mode, I’m assuming at the cost of some extra power drain that would normally be saved.

- id: '1604003579362'
  alias: Power down battery on low capacity
  description: ''
  trigger:
  - platform: numeric_state
    entity_id: sensor.solax_battery_capacity
    below: '14'
    for: 00:00:30
  condition:
  - condition: numeric_state
    entity_id: input_number.solax_battery_discharge
    above: '0'
  action:
  - service: input_number.set_value
    data:
      value: 0
    entity_id: input_number.solax_battery_discharge
  mode: single
- id: '1604004168651'
  alias: Power up battery on sufficient capacity
  description: ''
  trigger:
  - platform: numeric_state
    entity_id: sensor.solax_battery_capacity
    for: 00:03:00
    above: '14'
  condition:
  - condition: numeric_state
    entity_id: input_number.solax_battery_discharge
    below: '20'
  action:
  - service: input_number.set_value
    data:
      value: 20
    entity_id: input_number.solax_battery_discharge
  mode: single

@SteRN
@xavi104
I’ll have another look to see if I can spot anything in the documentation that might help.

I have been busy moving everything over to reading multiple registers in a single transaction.
I am down to 2 Holding Register reads and 2 Input Register reads! This may increase as I find other values of interest…
This obviously reduces the load on the ModBus bus by a significant amount!

That’s not every register showing, I only have a fraction of the EPS ones showing.
Still need to work on the extra write registers.

3 Likes

Hi!

I have the same problem. When the inverter goes to idle only the sunlight will wake it up :slight_smile: Doesn’t matter if I change charge, discharghe, battery min, force mode… etc.
When you put the discharge to 0 before battery min, wont the inverter go to idle? I don’t really understand the automation.

Not in my experience, it remains in Normal mode consistently over the past 10 days. Holding it above the limit keeps the system fully online, at the cost of some power drain by the inverter from the grid that hovers at 57-58W. I’m not sure how that compares to idle mode.

Another side effect is when you do start charging, it’s immediately at full power, whereas I find the power ramps up slowly when the system reaches the minimum power and comes out of idle mode. Whether or not that is a good thing, I’m not sure!

1 Like

Hi!

Hope your work is going well! Do you have some code that you can share? Really interested in speeding up my raspberry. It is pretty slow with all the readings for me.

/Fredrik

Have a look in my experimental folder https://github.com/wills106/homeassistant-config It wont work unless you make a custom_component of the above PR for ModBus though.
As the changes required to ModBus are not merged into Home Assistant yet though!

If you do use it bare in mind it’s WIP and I am planning on changing some names of the register groups.

I may also add and delete stuff as I finish it off, there is also Solcast forecasting code left over. So delete them sections if not using them.

I didn’t want to experiment with my main raspberry with all the automations so now I have bought one more :slight_smile:
I have made a custom component folder with your file from the experimental folder but how do I make a custom component to load of it? It should include the alternative modbus?
WIP?