Solis Inverter Modbus integration

So far I’ve only implemented the control in a hacky way, I got stuck with using a numberentity to create a controllable input in home assistant. So it is possible, but I don’t have a good UI for it at the moment, could really do with some help on that as this is the first time I’ve tried to do anything in Home assistant custom components or Python.

I believe we will be able to set the charge rates, times, direction etc.

What is the numberentity actually linked to within home assistant? I’ve written a couple of custom HACS integrations myself so I’ll probably put my hand to this once I’ve got time in a few weeks

Great work. I added the Solis Hybrid support to that integration. Adding r/w support has been on my todo list, but I haven’t gotten around to it yet. I had intended integrating pysolarmanv5 into the integration to handle all of the Solarman protocol handling.

1 Like

Ah, nice, good work! I’ve found it very useful to be able to control the inverter and have created a basic template and automation to use the forecasted solar and consumption amount for the next day to determine how much (if at all) to charge the batteries by each night and that’s been working very well.

2 Likes

I’ve recently had a Solis Hybrid inverter RHI-6K-48ES-5G 6 kW installed and have applied this integration to my HA setup today, however the entities aren’t returning values. In my excitement, I’d missed the fact this is for the Solarman logger, whereas I have the Solis DLS-W wifi data logger.

Any advice?

Waiting for my installation of Solis Hybrid RHI 3P10K HVES 5G together with Soluna 15kWh battery pack. The thing is that Im having a fixed price of 1,28SEK/ kWh (App 0,11€/kWh) and that is valid until autumn of 2024. Here in Sweden the spotmarket price most days now are about 3 and sometimes up to 5SEK/kWh. So basically my idea is to maximise my use of the inverter with battery and as long as the spotmarket price is higher than say 2 SEK I’ll buy and sell energy constant. For sure it will wear the battery but its bought to be used. So will the functions you have here be able to simply tell the inverter charge with 10kW and discharge with 10kW independent of what the house and solarpanels consumption and production is? Of course Ill have to keep an eye not to overload the mainfuse of the house but I can get that up to 35Amps if needed. (now 25A is installed).

Same boat here.
Our data loggers have alphanumeric serial numbers which the integration doesn’t accept.

Does anyone know how to reset the web login password admin/admin doesn’t seem to be working for me when I try to access the logger’s IP address… Not sure why, maybe I changed it but no idea what it is now

Im maybe being dense - but where do I find the solarman integration? I cant see it in homeassistant or HACS
I have the ginlong one already (hultenvp)

For my Solis 5G inverter, I went down this route with a spare Pi Zero W and a cheap adapter from amazon

Working perfectly, 60sec refresh rate, I just need to smooth out the registers file as the included one is for older models.

1 Like

Search Solarman in HACS, or find it here:

I have also branched it and added control support for Solis inverter here (warning potential damage could be caused by writing wrong values!):

1 Like

@Gadgit83 Any plans to raise a PR and get this merged back into Stephan’s tree?

This is brilliant!
Any thoughts on how this could be achieved with a pi Zero plugged in to the SOLIS communicating with HA over MQTT?

Hi all,

Following on from a breaking change to the Solis Cloud Platform (and integration) I took the jump to go with MODBUS for my Solis 5G Inverter.

Here’s my code which includes querying a batch of registers then applying to a template - it’s quicker this way and gives me 2 second updates (though you might not need it this high).

First, the MODBUS registers for my specific device:
Solis Energy Storage 6kW Hybrid 5G Inverter with DC switch for On Grid Hybrid for 48V batteries SOL-6K-RHI-48ES-5G-DC

The MODBUS code in my configuration.yam:


modbus:
  - name: "solis"
    type: tcp
    host: 172.22.32.102
    port: 8899
    sensors:
      # - name: solismodbus_33073_33084
      #   slave: 1
      #   address: 33073
      #   count: 12
      #   input_type: input
      #   data_type: custom
      #   lazy_error_count: 5
      #   scan_interval: 2
      #   structure: ">HHHHHHlll"

      - name: solismodbus_33126_33150
        slave: 1
        address: 33126
        count: 25
        input_type: input
        data_type: custom
        lazy_error_count: 5
        scan_interval: 2
        structure: ">LHHlHHhHHHHHHHhHHHHHHl"

      - name: solismodbus_33161_33180
        slave: 1
        address: 33161
        count: 20
        input_type: input
        data_type: custom
        lazy_error_count: 5
        scan_interval: 60
        structure: ">LHHLHHLHHLHHLHH"

      - name: solismodbus_33251_33286
        slave: 1
        address: 33251
        count: 36
        input_type: input
        data_type: custom
        lazy_error_count: 5
        scan_interval: 2
        structure: ">HHHHHHllllllllllllhHLL"

      - name: solismodbus_33029_33058
        slave: 1
        address: 33029
        count: 30
        input_type: input
        data_type: custom
        lazy_error_count: 5
        scan_interval: 2
        structure: ">LLLHHLLHHHHHHHHHHHHHHHHL"

      - name: solismodbus_33093_temperature
        slave: 1
        address: 33093
        count: 1
        input_type: input
        data_type: uint16
        lazy_error_count: 5
        scan_interval: 60

template: !include solis.yaml

And a seperate file with all my sensors that I currently use:

unique_id: solismodbussensors
sensor:
  # - name: solismodbus.inverter_line_voltage # 33073
  #   unique_id: solismodbus.inverter_line_voltage
  #   state_class: measurement
  #   device_class: voltage
  #   unit_of_measurement: V
  #   state: "{{ (states('sensor.solismodbus_33073_33084').split(',')[0]|float * 0.1) }}"

  # - name: solismodbus.inverter_line_current # 33076
  #   unique_id: solismodbus.inverter_line_current
  #   state_class: measurement
  #   device_class: current
  #   unit_of_measurement: A
  #   state: "{{ (states('sensor.solismodbus_33073_33084').split(',')[3]|float * 0.1) }}"

  # - name: solismodbus.inverter_power # 33079-33080
  #   unique_id: solismodbus.inverter_power
  #   state_class: measurement
  #   device_class: power
  #   unit_of_measurement: W
  #   state: "{{ (states('sensor.solismodbus_33073_33084').split(',')[6]) }}"

  - name: solismodbus.meter_total_active_power # 33126-33127
    unique_id: solismodbus.meter_total_active_power
    state_class: total_increasing
    device_class: energy
    unit_of_measurement: kWh
    state: "{{ (states('sensor.solismodbus_33126_33150').split(',')[0]|float * 0.001) }}"

  - name: solismodbus.meter_voltage # 33128
    unique_id: solismodbus.meter_voltage
    state_class: measurement
    device_class: voltage
    unit_of_measurement: V
    state: "{{ (states('sensor.solismodbus_33126_33150').split(',')[1]|float * 0.1) }}"

  - name: solismodbus.meter_current # 33129
    unique_id: solismodbus.meter_current
    state_class: measurement
    device_class: current
    unit_of_measurement: A
    state: "{{ (states('sensor.solismodbus_33126_33150').split(',')[2]|float * 0.01) }}"

  - name: solismodbus.meter_power # 33130-33131
    unique_id: solismodbus.meter_power
    state_class: measurement
    device_class: power
    unit_of_measurement: W
    state: "{{ (states('sensor.solismodbus_33126_33150').split(',')[3]| int *-1) }}"

  - name: solismodbus.battery_voltage # 33133
    unique_id: solismodbus.battery_voltage
    state_class: measurement
    device_class: voltage
    unit_of_measurement: V
    state: "{{ (states('sensor.solismodbus_33126_33150').split(',')[5]|float * 0.1) }}"

  - name: solismodbus.battery_current # 33134
    unique_id: solismodbus.battery_current
    state_class: measurement
    device_class: current
    unit_of_measurement: A
    state: "{{ (states('sensor.solismodbus_33126_33150').split(',')[6]|float * 0.1) }}"

  - name: solismodbus.bypass_ac_voltage # 33137
    unique_id: solismodbus.bypass_ac_voltage
    state_class: measurement
    device_class: voltage
    unit_of_measurement: V
    state: "{{ (states('sensor.solismodbus_33126_33150').split(',')[9]|float * 0.1) }}"

  - name: solismodbus.bypass_ac_current # 33138
    unique_id: solismodbus.bypass_ac_current
    state_class: measurement
    device_class: current
    unit_of_measurement: A
    state: "{{ (states('sensor.solismodbus_33126_33150').split(',')[10]|float * 0.1) }}"

  - name: solismodbus.battery_soc # 33139
    unique_id: solismodbus.battery_soc
    state_class: measurement
    device_class: battery
    unit_of_measurement: "%"
    state: "{{ (states('sensor.solismodbus_33126_33150').split(',')[11]) }}"

  - name: solismodbus.battery_soh # 33140
    unique_id: solismodbus.battery_soh
    state_class: measurement
    device_class: battery
    unit_of_measurement: "%"
    state: "{{ (states('sensor.solismodbus_33126_33150').split(',')[12]) }}"

  - name: solismodbus.house_load_power # 33147
    unique_id: solismodbus.house_load_power
    state_class: measurement
    device_class: power
    unit_of_measurement: W
    state: "{{ (states('sensor.solismodbus_33126_33150').split(',')[19]) }}"

  - name: solismodbus.bypass_load_power # 33148
    unique_id: solismodbus.bypass_load_power
    state_class: measurement
    device_class: power
    unit_of_measurement: W
    state: "{{ (states('sensor.solismodbus_33126_33150').split(',')[20]) }}"

  - name: solismodbus.battery_power # 33149-33150
    unique_id: solismodbus.battery_power
    state_class: measurement
    device_class: power
    unit_of_measurement: W
    state: "{{ (states('sensor.solismodbus_33126_33150').split(',')[21]) }}"

  - name: solismodbus.battery_total_charge # 33161-33162
    unique_id: solismodbus.battery_total_charge
    state_class: total_increasing
    device_class: energy
    unit_of_measurement: kWh
    state: "{{ (states('sensor.solismodbus_33161_33180').split(',')[0]) }}"

  - name: solismodbus.battery_today_charge # 33163
    unique_id: solismodbus.battery_today_charge
    state_class: total_increasing
    device_class: energy
    unit_of_measurement: kWh
    state: "{{ (states('sensor.solismodbus_33161_33180').split(',')[1]|float * 0.1) }}"

  - name: solismodbus.battery_total_discharge # 33165-33166
    unique_id: solismodbus.battery_total_discharge
    state_class: total_increasing
    device_class: energy
    unit_of_measurement: kWh
    state: "{{ (states('sensor.solismodbus_33161_33180').split(',')[3]) }}"

  - name: solismodbus.battery_today_discharge # 33167
    unique_id: solismodbus.battery_today_discharge
    state_class: total_increasing
    device_class: energy
    unit_of_measurement: kWh
    state: "{{ (states('sensor.solismodbus_33161_33180').split(',')[4]|float * 0.1) }}"

  - name: solismodbus.grid_total_imported # 33169-33170
    unique_id: solismodbus.grid_total_imported
    state_class: total_increasing
    device_class: energy
    unit_of_measurement: kWh
    state: "{{ (states('sensor.solismodbus_33161_33180').split(',')[6]) }}"

  - name: solismodbus.grid_today_imported # 33171
    unique_id: solismodbus.grid_today_imported
    state_class: total_increasing
    device_class: energy
    unit_of_measurement: kWh
    state: "{{ (states('sensor.solismodbus_33161_33180').split(',')[7]|float * 0.1) }}"

  - name: solismodbus.grid_yesterdayday_imported # 33172
    unique_id: solismodbus.grid_yesterdayday_imported
    state_class: total_increasing
    device_class: energy
    unit_of_measurement: kWh
    state: "{{ (states('sensor.solismodbus_33161_33180').split(',')[8]|float * 0.1) }}"

  - name: solismodbus.grid_total_exported # 33169-33170
    unique_id: solismodbus.grid_total_exported
    state_class: total_increasing
    device_class: energy
    unit_of_measurement: kWh
    state: "{{ (states('sensor.solismodbus_33161_33180').split(',')[9]) }}"

  - name: solismodbus.grid_today_exported # 33171
    unique_id: solismodbus.grid_today_exported
    state_class: total_increasing
    device_class: energy
    unit_of_measurement: kWh
    state: "{{ (states('sensor.solismodbus_33161_33180').split(',')[10]|float * 0.1) }}"

  - name: solismodbus.grid_yesterdayday_exported # 33172
    unique_id: solismodbus.grid_yesterdayday_exported
    state_class: total_increasing
    device_class: energy
    unit_of_measurement: kWh
    state: "{{ (states('sensor.solismodbus_33161_33180').split(',')[11]|float * 0.1) }}"

  - name: solismodbus.house_load_total # 33169-33170
    unique_id: solismodbus.house_load_total
    state_class: total_increasing
    device_class: energy
    unit_of_measurement: kWh
    state: "{{ (states('sensor.solismodbus_33161_33180').split(',')[12]) }}"

  - name: solismodbus.house_load_today # 33171
    unique_id: solismodbus.house_load_today
    state_class: total_increasing
    device_class: energy
    unit_of_measurement: kWh
    state: "{{ (states('sensor.solismodbus_33161_33180').split(',')[13]|float * 0.1) }}"

  - name: solismodbus.house_load_yesterday # 33172
    unique_id: solismodbus.house_load_yesterday
    state_class: total_increasing
    device_class: energy
    unit_of_measurement: kWh
    state: "{{ (states('sensor.solismodbus_33161_33180').split(',')[14]|float * 0.1) }}"

  - name: solismodbus.meter_ac_voltage # 33251
    unique_id: solismodbus.meter_ac_voltage
    state_class: measurement
    device_class: voltage
    unit_of_measurement: V
    state: "{{ (states('sensor.solismodbus_33251_33286').split(',')[0]|float * 0.1) }}"

  - name: solismodbus.meter_ac_current # 33252
    unique_id: solismodbus.meter_ac_current
    state_class: measurement
    device_class: current
    unit_of_measurement: A
    state: "{{ (states('sensor.solismodbus_33251_33286').split(',')[1]|float * 0.01) }}"

  - name: solismodbus.meter_active_power # 33257-33258
    unique_id: solismodbus.meter_active_power
    state_class: measurement
    device_class: power
    unit_of_measurement: kW
    state: "{{ (states('sensor.solismodbus_33251_33286').split(',')[6]) }}"

  - name: solismodbus.meter_power_factor # 33281
    unique_id: solismodbus.meter_power_factor
    state_class: measurement
    device_class: power_factor
    unit_of_measurement: "%"
    state: "{{ (states('sensor.solismodbus_33251_33286').split(',')[18]|float * 0.01) }}"

  - name: solismodbus.meter_frequency # 33282
    unique_id: solismodbus.meter_frequency
    state_class: measurement
    device_class: frequency
    unit_of_measurement: "Hz"
    state: "{{ (states('sensor.solismodbus_33251_33286').split(',')[19]|float * 0.01) }}"

  - name: solismodbus.meter_total_imported # 33283-33284
    unique_id: solismodbus.meter_total_imported
    state_class: total_increasing
    device_class: energy
    unit_of_measurement: kWh
    state: "{{ (states('sensor.solismodbus_33251_33286').split(',')[20]|float * 0.01) }}"

  - name: solismodbus.meter_total_exported # 33285-33286
    unique_id: solismodbus.meter_total_exported
    state_class: total_increasing
    device_class: energy
    unit_of_measurement: kWh
    state: "{{ (states('sensor.solismodbus_33251_33286').split(',')[21]|float * 0.01) }}"

  - name: solismodbus.inverter_total_generated # 33029-33030
    unique_id: solismodbus.inverter_total_generated
    state_class: total_increasing
    device_class: energy
    unit_of_measurement: kWh
    state: "{{ (states('sensor.solismodbus_33029_33058').split(',')[0]) }}"

  - name: solismodbus.inverter_month_generated # 33031-33032
    unique_id: solismodbus.inverter_month_generated
    state_class: total_increasing
    device_class: energy
    unit_of_measurement: kWh
    state: "{{ (states('sensor.solismodbus_33029_33058').split(',')[1]) }}"

  - name: solismodbus.inverter_today_generated # 33035
    unique_id: solismodbus.inverter_today_generated
    state_class: total_increasing
    device_class: energy
    unit_of_measurement: kWh
    state: "{{ (states('sensor.solismodbus_33029_33058').split(',')[3]|float * 0.1) }}"

  - name: solismodbus.inverter_today_generated # 33036
    unique_id: solismodbus.inverter_today_generated
    state_class: total_increasing
    device_class: energy
    unit_of_measurement: kWh
    state: "{{ (states('sensor.solismodbus_33029_33058').split(',')[4]|float * 0.1) }}"

  - name: solismodbus.dc1_voltage # 33049
    unique_id: solismodbus.dc1_voltage
    state_class: measurement
    device_class: voltage
    unit_of_measurement: V
    state: "{{ (states('sensor.solismodbus_33029_33058').split(',')[15]|float * 0.1) }}"

  - name: solismodbus.dc1_current # 33050
    unique_id: solismodbus.dc1_current
    state_class: measurement
    device_class: current
    unit_of_measurement: A
    state: "{{ (states('sensor.solismodbus_33029_33058').split(',')[16]|float * 0.1) }}"

  - name: solismodbus.dc2_voltage # 33051
    unique_id: solismodbus.dc2_voltage
    state_class: measurement
    device_class: voltage
    unit_of_measurement: V
    state: "{{ (states('sensor.solismodbus_33029_33058').split(',')[17]|float * 0.1) }}"

  - name: solismodbus.dc2_current # 33052
    unique_id: solismodbus.dc2_current
    state_class: measurement
    device_class: current
    unit_of_measurement: A
    state: "{{ (states('sensor.solismodbus_33029_33058').split(',')[18]|float * 0.1) }}"

  - name: solismodbus.dc_total_power # 33057-33058
    unique_id: solismodbus.dc_total_power
    state_class: measurement
    device_class: power
    unit_of_measurement: W
    state: "{{ (states('sensor.solismodbus_33029_33058').split(',')[23]|int ) }}"

  - name: solismodbus.inverter_temperature # 33093
    unique_id: solismodbus.inverter_temperature
    state_class: measurement
    device_class: temperature
    unit_of_measurement: "°C"
    state: "{{ (states('sensor.solismodbus_33093_temperature').split(',')[0]|float * 0.1) }}"

  - name: solismodbus.battery_direction # 33135
    unique_id: solismodbus.battery_direction
    state: "{{ (states('sensor.solismodbus_33126_33150').split(',')[7]|int) }}"

  - name: solismodbus.battery_charging # 33135
    unique_id: solismodbus.battery_charging
    state: >
      {% if states('sensor.solismodbus_battery_direction') == '1' %}
      discharging
      {% else %}
      charging
      {% endif %}

This is a work in progress and I thank everyone else with their contributions as you have masivly helped me to get to this stage.

4 Likes

yes, you can get real time stats :slight_smile:

Thank you for sharing this.

Can you please help me because I cannot get Home Assistant to retrieve these sensors.

I have A USR TCP232-304 Modbus to Ethernet bridge

Can you please tell me:

Local port number?

Remote port number is it necessary and if so what?

Work mode - presume TCP server?

Remote server address. IP of USR device or Home Assistant host IP?

Does it matter that mine is a 3.6K inverter?

Many thanks in advance

Tony

EDIT

The modus document you use is dated 2018, the one I believe I need is dated 2021. Now I have to see if I’m clever enough to amend your code accordingly.

EDIT 2

I have asked Solis Service to point me to the correct RS485_MODBUS Communication Protocol for my UK inverter

Tony

1 Like

I have a working USR TCP232-410S adaptor connected between my Solis Hybrid Inverter and Home Assistant. This collects inverter data from the registers using Modbus over RS485, converted into Modbus over TCP.

Your adaptor is a different model, so I cannot provide you will all the details guaranteed to make it work, however the following information may help you move forward.

To make your arrangement work, you need to ensure the following:

  • Connect the adaptor to your local network, and using the web interface page, set the IP address to static, and enter an address (something that is not used by anything else on the network, and make a note). This is the IP address you will put into HA so HA can talk to your adaptor over the local network.

  • Go to the serial port setting page, and make sure your settings are correct for connection to the Solis Modbus (RS485) port

  • Baud rate 9600, data 8 bits, no parity, 1 stop bit

  • The local port number is the port that is exposed to the network, and USR devices default this to 23 which will be OK. If you want to keep to a standard, 502 is the usual port for Modbus, although you can usually safely use anything over 1000.

Once you have set the IP address and local port, you can use these in HA for host / port under modbus setup.

Now we need to ensure that the unit is in TPC server mode. A server (or slave) responds to requests from a client (or master). The Solis inverter is a slave/server, and your HA computer is a master/client. This means your HA will make a request (via the adaptor) and the inverter responds. The adaptor has two faces - the Ethernet side must in this situation pretend to be a server (faces the HA client), so it is set up as a TCP server. The serial side then acts like a client to the inverter, and no ‘ports’ are involved. The adaptor is just converting the physical carrier for the Modbus message, and looks like a plug-socket would in an extension lead.

[Only if the adaptor is set up as a TCP client do we need the remote server and port. In TCP server mode, the device listens to anything that connects to it (on the IP/port address). In TCP client mode however the device is doing the requesting and needs to know where the server is, hence the remote server IP /port address]

You should find that setting the operating mode to TCP server removes the need for remote port / remote server settings.

Now you need to ensure that the adaptor is connected correctly to the inverter Modbus port.

This should just be a pair of wires, connecting the Modbus A and B from the inverter RS485 port to the adaptor serial connection block (use the inverter comms port, not the meter port).

  • A must be connected to A, and B to B
  • Use twisted pair (network) cable. The earth is optional and for long cable runs. The standard uses blue and blue/white for A and B, another twisted pair (green) for the earth, earth connected only at one end (there is no earth on the inverter socket anyway).
  • Use a terminating resistor 120 ohms at the adaptor end. This must go between A and B. The interface will work without but you will get Modbus errors. RS485 requires a terminating resistor at each physical end of the bus, the inverter has this built in, the adaptor does not.

Note that you should not have anything else connected to the inverter. Running a Solis data logging stick as well as the adaptor will lead to issues as Modbus cannot support more than one master on the bus.

Register map.
Modbus is not forgiving, and requires exactly the right information otherwise no response will be issued.

  • the (register) address has to be valid
  • the read type (holding, input) must be correct for that register address

Different generations of Solis inverters have different register maps. The 5G (Hybrid) models have register maps as detailed elsewhere in this discussion. Earlier models have maps that can be found using Google. It is the ‘G’ that matters and not the kW power rating, and Hybrid models (with a DC battery) have additional quirks in the map to accommodate the battery and operating mode settings.

Good luck!

2 Likes

Thanks, comprehensive as usual!

I’m 99% right. I used a hacked up USB cable not CAT5, and I don’t have a resistor.

But apart from that I’m set up as you recommend.

From my reading rico365’s script should work for me.

So should madbobmcjims. Neither do.

Best go buy a resistor and have my friendly solderer warm his iron up.

Thanks so much

Tony

The resistor is not essential for short cable runs with only two devices, it just make things work better and stops erratic readings. I modified my wiring a couple of days ago and missed out the resistor at the adaptor end - result was Modbus errors at least once per hour. Resistor back and problems almost gone. With all the wiring and the inverter, there must be a lot of electrical noise.

I bouught this at eBay, Protoss PE11-H.
image
But I can’t get into the web page to set ut the device.
Can someone help me to get the IP adress to the device?
The device is not showing as in router as DHCP device, so I cant find it.

Please help.

There is a manual available via a google search.

Have you tried to find it? Have you factory reset the device?

Was it new or second hand? If second hand the IP address may have been set to work on a different address range to the one you are using.

If you have tried all of the above and its second hand it may be defective.

Best of luck with getting modbus to work if you aren’t able to get the ethernet to RS485 device to appear on your network.

I have taken a break from modbus and will be back on it soon.

Tony

Tony