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

Thanks! I think it is working now. Will check in the following days the behaviour.
Other question if I may:

In solaxcloud website one has 4 values: PV Power, AC Power, Load Power, Grid Power. Are all these values measured, hence, there is a register, or some of them are calculated from the measured ones?
Following your package sensors:
PV Power = sensor.solax_pv_total_power
AC Power = sensor.solax_inverter_load
Load Power = ?
Grid Power = sensor.solax_feedin_power

The load power is the consumption of the house. Is there any register that provides directly this value?

I’m not sure what the Difference between AC Power and Load Power is.
I think sensor.solax_inverter_load matches the Load / Generator Power more?
It’s hard to tell with so little solar at the min. But perhaps AC Power is how much PV and Battery converted power that the Inverter is outputting? Or the other way round?

Not paid too much attention to be honest.

Ac power = inverter power
Load power = house consumption (being transmitted by a meter at the “house electrical entrance” to the inverter).

I was wondering if there is a register providing directly this load power value. This may be obtained from the other, but the calculation depends on the situation, and hence, calculation is tricky.
E.g., if no PV power and batter empty, then inverter power = 0, and consuption = feedin power… but during the day it’s different (and depending if battery is full or not)

I’d be really keen to get those API Urls please

Hi, a new problem for me came this weekend. I have had troubles with my router so I reset it this weekend. I dont think there was a problem with Solax before that but now I can only read values. As soon as I try to change charge rate or something all values disappear for some seconds and then it shows again. I have tried two different routers and two rasperries… could it be the inverter?

In the log the following is showing when i try to change charge amps:
Logger: homeassistant.helpers.condition
Source: helpers/condition.py:234
First occurred: 15:24:25 (9 occurrences)
Last logged: 15:24:49

  • Value cannot be processed as a number: <state sensor.solax_battery_capacity_charge=; unit_of_measurement=%, friendly_name=SolaX Battery Capacity @ 2021-01-30T15:24:25.188148+01:00> (Offending entity: )
  • Value cannot be processed as a number: <state sensor.solax_battery_capacity_charge=; unit_of_measurement=%, friendly_name=SolaX Battery Capacity @ 2021-01-30T15:24:49.107519+01:00> (Offending entity: )

and I also get a lot of these but I guess that comes because the inverter seems unavailable for a while:
Logger: homeassistant.components.template.template_entity
Source: components/template/template_entity.py:71
Integration: template (documentation, issues)
First occurred: 15:24:25 (38 occurrences)
Last logged: 15:24:49

  • TemplateError(‘UndefinedError: list object has no element 6’) while processing template ‘Template("{{ states(‘sensor.solax_group_i2’).split(’,’)[6]| float / 10 }}")’ for attribute ‘_state’ in entity ‘sensor.solax_eps_volatge’
  • TemplateError(‘UndefinedError: list object has no element 7’) while processing template ‘Template("{{ states(‘sensor.solax_group_i2’).split(’,’)[7]| float / 10 }}")’ for attribute ‘_state’ in entity ‘sensor.solax_eps_current’
  • TemplateError(‘UndefinedError: list object has no element 9’) while processing template ‘Template("{{ states(‘sensor.solax_group_i2’).split(’,’)[9]| float / 10 }}")’ for attribute ‘_state’ in entity ‘sensor.solax_eps_frequency’
  • TemplateError(‘UndefinedError: list object has no element 10’) while processing template ‘Template("{{ states(‘sensor.solax_group_i2’).split(’,’)[10]| float / 10 }}")’ for attribute ‘_state’ in entity ‘sensor.solax_energy_today’
  • TemplateError(‘UndefinedError: list object has no element 12’) while processing template ‘Template("{{ states(‘sensor.solax_group_i2’).split(’,’)[12]| float / 1000 }}")’ for attribute ‘_state’ in entity ‘sensor.solax_total_energy_to_grid’

edit:
I have tried some more. When I use the old read file (without groups) I dont get any error messages. I can read all the values but not write any. Also saw that with the updated solax cloud homepage I can change settings remote on the site. I could not do that before. Could Solax have changed something so we cant write to the inverter anymore?

@wills106 amazing work on the SolaX integration, got it all working without read groups for now!

I have read through the thread but I did not see it, have you been able to force a discharge from the SolaX? Force it to discharge on command/automation?

I believe in normal operation the SolaX is connected to a modbus meter which is sending updates to the inverter to tell it if there is any power coming in from the grid which causes the inverter to discharge and it will keep increasing its discharge until the modbus meter is reading Zero import. Was wondering if it was possible to send these modbus signals direct to the inverter in place of the meter to force it to discharge.

I managed to get an updated Modbus specification from Solex but finding it hard to see how to force discharge.

Thanks,
Richard

I use mine direct to the Inverter so yes you can change the charge/discharge on/off as you need

On another note, how is everyone managing to get the Modus spec and registers from SolaX? They seem to ignore every request I send to them :frowning:

Hi @matthewjporter, happy to try and answer any questions as I have a copy, just cant share it.

Can you also send me/past in a code snippet of what you are using to force discharge?

Email on its way

Not sure if you are using the old config or the new grouping, I have not had the time to migrate yet so still the old config

So, My inverter is connected via ethernet, I have an older X1 Gen2 Hybrid but still works the same

The simple answer is that based on the input_boolean.solax_forcetime that is created in the main solax config file you can force the inverter to charge the battery or self use / discharge

However, I needed to be able to control when I charged and discharged so went a step further and did the following by making an “additional” file with the following in it as I wanted to integrate with Octopus Agile which i called “solax_x1_hybrid_g2_additions.yaml” and saved in Saved in the packages folder in HA

So, Its a lot to take in, But this is what I have done that gives me the following and as per my needs but may help you

  • A slider that sets the value based on Octopus Agile p/kw that I want to charge the battery at
  • A sensor that is on/off based on the above slider if it is at or below the set p/kw value
  • An automation that will turn on the “Force time charge” on/off on the inverter based on the above slider

Furthe to that, I set the battery discharge percentage based on the Octopus Agile rate so Peak, High, Medium, Low and Plunge

Based on the rate and my other sensors/automations the battery will automatically charge & discharge as needed by setting the forcetime_use and the battery DOD%

In the same folder, I have the same files as listed on @wills106 github page

input_number:
# Creates an input_number.solax_battery_charge_price that can be set to the
# required p/kWh to turn on/off forcetime charge of the SolaX Battery
  solax_battery_charge_price:
    icon: mdi:cash
    name: SolaX Battery Charge p/kWh
#    initial: 9  #Initial Charge Price to charge at
    min: 0
    max: 25  #Max Octopus Price to charge at
    step: 0.5

sensor:
# Monitors input_number.solax_battery_charge_price and sensor.octopus_agile_current_rate (OctoBlock integration)
# and reflects true or false allowing automation(s) to turn on SolaX battery charging at desired p/kWh
    solax_battery_charge_price:
      friendly_name: "Solax Battery Charge @ p/kWh"
      value_template: >
        {% if states('sensor.octopus_agile_current_rate') | round(2) <= states('input_number.solax_battery_charge_price') | round(2) %}
          On
        {% else %}
          Off
        {% endif %}

automation:
# Charge SolaX battery based on input_number.solax_charge_price
  - alias: OctopusAgile - SolaX Battery Charging On
    trigger:
      platform: state
      entity_id: sensor.solax_battery_charge_price
      to: 'On'
    action:
    - service: notify.mjp
      data:
        message: Battery Charging
    - delay: '00:00:01'
    - service: input_boolean.turn_on
      entity_id: input_boolean.solax_forcetime

# Discharge SolaX battery based on input_number.solax_charge_price
  - alias: OctopusAgile - SolaX Battery Charging Off
    trigger:
      platform: state
      entity_id: sensor.solax_battery_charge_price
      to: 'Off'
    action:
    - service: notify.mjp
      data:
        message: Battery Discharging
    - delay: '00:00:01'
    - service: input_boolean.turn_off
      entity_id: input_boolean.solax_forcetime

#  Set SolaX battery minimum capacity based on input_select.octopus_price
  - alias: "OctopusAgile - SolaX Battery % Plunge"
    trigger:
      platform: state
      entity_id: input_select.octopus_price
      to: 'Plunge'
    action:
    - service: input_number.set_value
      data:
        value: 90
      entity_id: input_number.solax_battery_min_energy
    - delay: '00:00:01'
    - service: input_number.set_value
      data:
        value: 90
      entity_id: input_number.solax_battery_min_energy

  - alias: "OctopusAgile - SolaX Battery % Low"
    trigger:
      platform: state
      entity_id: input_select.octopus_price
      to: 'Low'
    action:
    - service: input_number.set_value
      data:
        value: 50
      entity_id: input_number.solax_battery_min_energy
    - delay: '00:00:01'
    - service: input_number.set_value
      data:
        value: 50
      entity_id: input_number.solax_battery_min_energy

  - alias: "OctopusAgile - SolaX Battery % Medium"
    trigger:
      platform: state
      entity_id: input_select.octopus_price
      to: 'Medium'
    action:
    - service: input_number.set_value
      data:
        value: 40
      entity_id: input_number.solax_battery_min_energy
    - delay: '00:00:01'
    - service: input_number.set_value
      data:
        value: 40
      entity_id: input_number.solax_battery_min_energy

  - alias: "OctopusAgile - SolaX Battery % High"
    trigger:
      platform: state
      entity_id: input_select.octopus_price
      to: 'High'
    action:
    - service: input_number.set_value
      data:
        value: 20
      entity_id: input_number.solax_battery_min_energy
    - delay: '00:00:01'
    - service: input_number.set_value
      data:
        value: 20
      entity_id: input_number.solax_battery_min_energy

  - alias: "OctopusAgile - SolaX Battery % Peak"
    trigger:
      platform: state
      entity_id: input_select.octopus_price
      to: 'Peak'
    action:
    - service: input_boolean.turn_off
      entity_id: input_boolean.solax_forcetime
    - service: input_number.set_value
      data:
        value: 10
      entity_id: input_number.solax_battery_min_energy
    - delay: '00:00:01'
    - service: input_number.set_value
      data:
        value: 10
      entity_id: input_number.solax_battery_min_energy

2 Likes

If you just want to create an automation to trigger use these automations

They turn on/off the force charge state but as soon as you tirn off it will start to discharge which is why I also did the change the the DOD% of my battery and the automation around that

As you can see, they rely on the input_boolean being setup but is in the main config file so you should have it created already

All you really need to do is either manage the state of the input_boolean and/or the DOD% and you can have full control

 Enable/Disable ForceTime/Self Use Modes
  - alias: SolaX ForceTime - On
    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 # Force Time Mode
      data_template:
        hub: SolaX
        unit: '255'
        address: '31'
        value: '1'

  - alias: SolaX ForceTime - Off
    trigger:
      platform: state
      entity_id: input_boolean.solax_forcetime
      to: 'off'
    action:
    - service: modbus.write_register # Auto Mode
      data_template:
        hub: SolaX
        unit: '255'
        address: '31'
        value: '0'
    - delay: '00:00:01'
    - service: modbus.write_register # Auto Mode
      data_template:
        hub: SolaX
        unit: '255'
        address: '31'
        value: '0'

1 Like

They have changed their tone then!

Do you have much contact with SolaX? I may have a favour to ask!

I have been very busy with work and not really updated my Solax stuff in a while.

At the moment I am keeping my Inverter in Force Time mode and grid charging 03:30 - 06:30 on one of the Octopus.Energy Go Faster tarifs.

You can easily turn on and off grid charging when you want, when using Force Time.

  - alias: Solax Allow Grid Charge
    trigger:
      platform: state
      entity_id: input_boolean.solax_grid_charge
      to: 'on'
    action:
    - service: modbus.write_register # Backup mode
      data_template:
        hub: SolaX
        unit: '255'
        address: '64'
        value: '1'

  - alias: Solax Disallow Grid Charge
    trigger:
      platform: state
      entity_id: input_boolean.solax_grid_charge
      to: 'off'
    action:
    - service: modbus.write_register # Backup mode
      data_template:
        hub: SolaX
        unit: '255'
        address: '64'
        value: '0'

You can then either have a set charge time like I do and leave it on all the time, or you could just turn it on and off as you need.

At the min I am finding Force Time mode better than Self Use as I was getting the Inverter stuck in deep sleep if I fully discharge the batteries during the night.

You can program the two start and end time blocks over ModBus, but I am yet to template it.

    - service: modbus.write_register # Solax Charger Start Time 1
      data_template:
        hub: SolaX
        unit: '255'
        address: '38'
        value: 'xyz-number'

It’s a little bit tricky though as you have to send the time as a 16bit value, but the hours and mins are sent as a upper 8bit and lower 8bit number.

So in python to set the time at 09:10 am you do:

Hbyte = 10
Lbyte = 9
value = Hbyte << 8 | Lbyte;

Which equals - 2569

I just haven’t finished it off yet…

1 Like

Thanks @matthewjporter and @wills106 for the detailed reply.

@wills106 happy to help with any contact with SolaX and see if I can help. I did sent them loads of questions a few days ago and still not had a reply so we will see how useful I can be :slight_smile:

#both - I am not sure I fully understand you TBO. My understanding is that (please correct me if I am wrong) you are both using a combination of Force Time mode and the timed windows to ask the battery to charge and discharge.

However within the discharge window you are putting the inverter into a state to allow itself to decide (through detecting the load on the house via a CT or meter) when and by how much to discharge.

What I am really after is the ability to force a discharge at any time at any rate to allow for applications like grid services, VPP and community energy.

Hope I have not missed something and thanks again for your reply’s.

You have four options with SolarChargerUseMode

    - service: modbus.write_register # FeedInPriority
      data_template:
        hub: SolaX
        unit: '255'
        address: '31'
        value: '3'

Thanks @wills106 understand, apparently the SolaX is being used in this way to deliver these types of services. Have sent the question to SolaX, will see if we get anything back.

Another thing I have found is that when my X1-Fit-5.0E goes into idle mode I cant make any changes and have to use the mobile app to make a change to wake up the inverter in order to then to able to change it through Mod-bus. Anyone experienced that?

Hi,

Yes, if you reach the low value you have sett for the battery it will go to Idle. I cant wake it either so I have an automation that starts force charge as soon as I am 1% above min. Charges for like 5 min and put discharge to 0. Then it will keep awake as long as you want.

What mode are you in when this happens?

I was using Self Use, but now I leave it in Force Time as the Inverter doesn’t go to sleep.

Question to SolaX:

If you do speak to them could you ask how Master / Slave mode works?

According to the Docs you can have a Master Inverter and up to 10 slaves.

At the min my Hybrid has two strings on SSW facing. If I was to add say an Inverter only model such as the X-1 Air or Boost on my East facing side of the house, would the Hybrid Charge the battery in the morning from the Power Generated by the Slave Inverter. Or would it just export that power?

The Hybrid would know the Air / Boost is Generating as they would be both behind the SDM230-MODBUS meter.

All three would be interlinked via ModBus

Thanks @fandersson yeah good solution, will use that for now. The SolaX mobile app dose it so why cant we :slight_smile: have asked SolaX, see if we get anything back.

The app connects a different manner.

It uses encrypted MQTT

Like I say I just leave mine in Force Time mode and then you can just turn on / off grid charging when you need it.

Thanks @wills106 will pass on your question and see if we get anything. My gut feeling is that the battery will change regardless of which inverter is causing the generation and there is export being detected by your connected meter. https://youtu.be/mQgrKjfMRbQ?t=1302 video talking about it a bit but no example of your specific case as far as I can tell.

Yeah, encrypted MQTT maybe the answer to a cleaner setup, get your point about using Force Time mode rather than Self Use which I was using.
Cheers

ok think I have an interim solution.

Most of the time I will sit in force time mode to stop it going into ideal and the battery will change or discharge dependent on load and generation on the solar or house. I can also force it to change by increasing the min % DOD during a low carbon or price drop event.

Then if I want to export to grid I can, but only if there is excess power generation from solar, by shifting to back up mode and letting any excess solar pass out to the grid. Now I just have to work on a way to centralize/automate command and control :slight_smile: