Integration Solar inverter huawei 2000L

I’m not sure if it’s the best or correct way, but this is how I do it…

I use the TOU (time of use) periods to have the periods where I want the battery to be charging or discharging.

I then switch between “maximise self consumption” modes and “time of use” to determine if I want the battery to be used or not.

For periods where I want to charge the battery, I’m in TOU mode with a period of “+” and “charge from grid” enabled, with a limit of what I want (usually 3000).

To stop charging, but without discharging, I disable charge from grid.

Period 1: 00:00-07:59/1234567/+
Period 2: 08:00-13:59/1234567/-
Period 3: 14:00-17:59/1234567/+
Period 4: 18:00-21:59/1234567/-
Period 5: 22:00-23:59/1234567/+

For any other time when I want to use the battery I move back to “Maximise Self Consumption”.

Anyone else got a problem with the battery working mode as of late?

Have a script for changing the battery working mode that’s been working for 6 month. Haven’t used it for a few weeks and now it cant change to anything other then Adaptive. All other modes render an error.
Have updated to the latest 1.3.1 version.
Is there any change to the naming for calling the different work modes?

See below for a snippet of the code from my testing in the Development tools…

service: select.select_option
target:
  entity_id: select.battery_working_mode
data:
  option: Time Of Use

edit:
If I try anything other than “Adaptive” as option, HA returns that its not valid option for select.battery_working_mode
Also tried to revert to V1.3.0 but same fault.

had to install HA Beta to solve this…

Okey so I have solved this after some fiddeling.
After going back and forth between different version of this integration and finally updating HA to 2024.1
I got a new error message that actually showed all valid options and not only a general error.

So for anyone who stumble across this, here is the correct options that you can use to
change the battery working mode:

adaptive
fixed_charge_discharge
maximise_self_consumption
fully_fed_to_grid
time_of_use_luna2000

This is a sample of my code that now works

service: select.select_option
target:
  entity_id: select.battery_working_mode
data:
  option: time_of_use_luna2000
1 Like

Hi,
I’m attempting to integrate my SUN2000-10KTL-M1 into my HA running on a RP4 and double checked that unrestricted Modbus TCP is enabled in the communication settings of the inverter via the installer account in FusionSolar. I tried all network connection variants mentioned in the documentation and adjusted the installer PW in const.py to match mine but keep running into below error and out of ideas. Any help and suggestions are highly appreciated.

Logger: huawei_solar.huawei_solar
Source: /usr/local/lib/python3.11/site-packages/huawei_solar/huawei_solar.py:184
First occurred: 00:21:40 (11 occurrences)
Last logged: 20:19:51

Aborting client creation due to error.
Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/backoff/_async.py", line 151, in retry
    ret = await target(*args, **kwargs)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/backoff/_async.py", line 151, in retry
    ret = await target(*args, **kwargs)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/huawei_solar/huawei_solar.py", line 349, in _do_read
    raise ConnectionInterruptedException(message)
huawei_solar.exceptions.ConnectionInterruptedException: Modbus client is not connected to the inverter.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/huawei_solar/huawei_solar.py", line 178, in create
    await huawei_solar._initialize()
  File "/usr/local/lib/python3.11/site-packages/huawei_solar/huawei_solar.py", line 107, in _initialize
    self.time_zone = (await self.get(rn.TIME_ZONE)).value
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/huawei_solar/huawei_solar.py", line 241, in get
    return (await self.get_multiple([name], slave))[0]
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/huawei_solar/huawei_solar.py", line 276, in get_multiple
    response = await self._read_registers(registers[0].register, total_length, slave)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/huawei_solar/huawei_solar.py", line 398, in _read_registers
    return await _do_read()
           ^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/backoff/_async.py", line 159, in retry
    await _call_handlers(on_giveup, **details, exception=e)
  File "/usr/local/lib/python3.11/site-packages/backoff/_async.py", line 37, in _call_handlers
    await handler(details)
  File "/usr/local/lib/python3.11/site-packages/backoff/_async.py", line 16, in f
    return coro_or_func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/huawei_solar/huawei_solar.py", line 327, in backoff_giveup
    raise ReadException(f"Failed to read register {register} after {details['tries']} tries")
huawei_solar.exceptions.ReadException: Failed to read register 43006 after 6 tries

Update: I was trying to debug what could be causing the issue and installed tcpdump as explained here. I started tcpdump inside the homeassistant docker listening on dst host 192.168.200.1 and with tcpdump running I was able to complete the integration with an installed PW dialogue coming up that wasn’t shown in previous attempts. - I have no clue which difference it makes to run tcpdump in the container during installation but hope this info is useful for others.

Thanks for this post @Ravenholm - I was trying to do the same thing, and was completely confused until I saw this post. Massive help! (@wlcrs) I think there would be value in adding this to the Wiki, as it is essential for enabling dynamic charging/discharging logic and I didn’t see it listed anywhere in the Git Wiki.

With that said, I am struggling a bit to find the best way to program the system, owing to the limitations of the Huawei modes. I use Intelligent Octopus tariff, which gives cheap rates at random periods of the day for EV charging. If my car charges when the battery is discharging, then it defeats the object of having a dynamic cheap tariff, because it pulls all the charge out of the house battery, into the car battery, rather than taking from the grid. I have tried the “forcible charge to SOC” option, when when it reaches the target SOC, it immediately starts to discharge, rather than holding at that percentage until I tell it to “maximise self consumption” when the cheap tariff ends.

I have ended up implementing the following “logic”, which I think might be the best (only?) solution:

  • TOU Config: Set the Time of use to “charge” between 00:00 and 23:59 (so that the TOU option is my method of switching to charging from the grid (and holding at that end state SOC until commanded to do something else)

  • Off Peak Charging: Whenever I want to charge, I set the “Grid Charge Cutoff SoC” to 100% and change the Working Mode to “time_of_use_luna2000”. This is triggered by the Octopus Energy charging signal “Octopus Energy [account number] Intelligent Dispatching” parameter.

  • Use The Battery: If I want to use the battery (i.e. when the tariff is expensive and the EV is not charging), I set the Working Mode to “maximise_self_consumption”

  • Pausing The Battery: If I want to pause the use of the battery (e.g. whilst I wait for an Octopus Energy Saving Session), I set the “Grid Charge Cutoff SoC” to the current Luna SOC, and change the Working Mode to “time_of_use_luna2000” (so it charges to target the SOC that the battery already has and does nothing until a mode change)

  • Pausing The Battery: My first attempt at this didn’t work. Pausing the Luna battery, depends on the battery SOC. Basically, you can’t set the “Grid Charge Cutoff SoC” to lower than 20%, and you can’t set the “Battery End of Discharge SOC” to higher than 20%. This means you need to create an If/else conditional as follows (in both of these cases, the battery will try to charge or discharge, to the current battery state, and therefore stop charging or discharging until you change the Working Mode again later):

    If battery SOC > 20%, then set the Working Mode to  "time_of_use_luna2000" 
    and the "Grid Charge Cutoff SoC" to the current Luna SOC
    
    If battery SOC <20%, then set the Working Mode to "maximise_self_consumption"
    and the "Battery End of Discharge SOC" to the current Luna SOC
    
  • Feed to grid: If I want to feed the battery to the grid, I select the Working Mode to “fully_fed_to_grid”

Does this seem like a sensible approach? Has anyone solved the problem by using the different operating modes in a different way to this?

Thanks

P.S. This is an epic integration, and works really well, so thanks for all the work that has gone into it.

EDIT 1: the above didn’t work - I will edit this post tomorrow to correct it, and explain what I have done.

EDIT 2: I have now corrected the above logic, since it didn’t work correctly for pausing the battery. I am pretty sure this all works as I need it to now, and hopefully it is helpful to someone else.

2 Likes

Few days ago my Huawei solar stopped working.
Here is the error:

This error originated from a custom integration.
Logger: pymodbus.logging
Source: custom_components/huawei_solar/init.py:92
Integration: Huawei Solar (documentation, issues)
First occurred: 12:34:58 AM (11 occurrences)
Last logged: 12:46:10 AM

Failed to connect [Errno 111] Connect call failed.

Restarded the invertors, restarted the HA, the wifi. deleted the Huawei Solar from HA.
Now I see only the invertor. I cant see the Power Meter.
The ModBus is enabled.
Sdongle dissapierded from my wifi list and now after the reboot has come back.
The Sdongle has the latest update.

Can you gus help me?

I have updated this post, with corrections I have found over the last 24 hours. Hopefully it is helpful to someone else.

again is losing connection, and it’s not wifi/network problem

i’ve just restarted the integration, and started to work

PS: HA is about 4 meters from Inverter, and connected with fixed IP Address to Inverter’s AP

found this in logs:

Logger: huawei_solar.huawei_solar
Source: /usr/local/lib/python3.11/site-packages/huawei_solar/huawei_solar.py:184
First occurred: 09:53:57 (5 occurrences)
Last logged: 09:56:13

Aborting client creation due to error.
Traceback (most recent call last):
  File "/usr/local/lib/python3.11/asyncio/tasks.py", line 500, in wait_for
    return fut.result()
           ^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/asyncio/locks.py", line 213, in wait
    await fut
asyncio.exceptions.CancelledError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/huawei_solar/huawei_solar.py", line 178, in create
    await huawei_solar._initialize()
  File "/usr/local/lib/python3.11/site-packages/huawei_solar/huawei_solar.py", line 107, in _initialize
    self.time_zone = (await self.get(rn.TIME_ZONE)).value
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/huawei_solar/huawei_solar.py", line 241, in get
    return (await self.get_multiple([name], slave))[0]
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/huawei_solar/huawei_solar.py", line 276, in get_multiple
    response = await self._read_registers(registers[0].register, total_length, slave)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/huawei_solar/huawei_solar.py", line 396, in _read_registers
    async with self._communication_lock():
  File "/usr/local/lib/python3.11/contextlib.py", line 204, in __aenter__
    return await anext(self.gen)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/huawei_solar/huawei_solar.py", line 145, in _communication_lock
    raise err
  File "/usr/local/lib/python3.11/site-packages/huawei_solar/huawei_solar.py", line 141, in _communication_lock
    await asyncio.wait_for(self._client.connected_event.wait(), WAIT_FOR_CONNECTION_TIMEOUT)
  File "/usr/local/lib/python3.11/asyncio/tasks.py", line 502, in wait_for
    raise exceptions.TimeoutError() from exc
TimeoutError
Logger: custom_components.huawei_solar
Source: helpers/update_coordinator.py:306
Integration: Huawei Solar (documentation, issues)
First occurred: 09:57:48 (1 occurrences)
Last logged: 09:57:48

Timeout fetching HV2240421156_data_update_coordinator data
Logger: huawei_solar.huawei_solar
Source: /usr/local/lib/python3.11/site-packages/huawei_solar/huawei_solar.py:143
First occurred: 09:53:57 (12 occurrences)
Last logged: 09:59:33

Timeout while waiting for connection. Reconnecting...
Traceback (most recent call last):
  File "/usr/local/lib/python3.11/asyncio/tasks.py", line 500, in wait_for
    return fut.result()
           ^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/asyncio/locks.py", line 213, in wait
    await fut
asyncio.exceptions.CancelledError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/huawei_solar/huawei_solar.py", line 141, in _communication_lock
    await asyncio.wait_for(self._client.connected_event.wait(), WAIT_FOR_CONNECTION_TIMEOUT)
  File "/usr/local/lib/python3.11/asyncio/tasks.py", line 502, in wait_for
    raise exceptions.TimeoutError() from exc
TimeoutError
Logger: custom_components.huawei_solar
Source: helpers/update_coordinator.py:300
Integration: Huawei Solar (documentation, issues)
First occurred: 10:00:32 (1 occurrences)
Last logged: 10:00:32

Unexpected error fetching HV2240421156_data_update_coordinator data: 'NoneType' object has no attribute 'write'
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 300, in _async_refresh
    self.data = await self._async_update_data()
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/huawei_solar/__init__.py", line 314, in _async_update_data
    return await self.bridge.update()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/huawei_solar/bridge.py", line 169, in update
    result = await self._get_multiple_to_dict(INVERTER_REGISTERS)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/huawei_solar/bridge.py", line 162, in _get_multiple_to_dict
    return dict(zip(names, await self.client.get_multiple(names, self.slave_id)))
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/huawei_solar/huawei_solar.py", line 276, in get_multiple
    response = await self._read_registers(registers[0].register, total_length, slave)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/huawei_solar/huawei_solar.py", line 398, in _read_registers
    return await _do_read()
           ^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/backoff/_async.py", line 151, in retry
    ret = await target(*args, **kwargs)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/backoff/_async.py", line 151, in retry
    ret = await target(*args, **kwargs)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/huawei_solar/huawei_solar.py", line 351, in _do_read
    response = await self._client.read_holding_registers(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/pymodbus/client/base.py", line 193, in async_execute
    self.transport_send(packet)
  File "/usr/local/lib/python3.11/site-packages/pymodbus/transport/transport.py", line 404, in transport_send
    self.transport.write(data)  # type: ignore[attr-defined]
    ^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'write'

@jodewee were you able to figure out this issue? I had something similar, where all was fine during morning hours battery charging, but when the battery reached 98%, solar output suddenly dropped to 0 and did not come up anymore that day. The next day it worked again without any intervention. Looking at the log in HA, the ‘sensor.inverter_locking_status’, which was ‘unlocked’, briefly changed to ‘locked’ at that exact moment when solar output dropped, but then got back to ‘unlocked’, but solar output remained 0.
Some background on my system: Huawei SUN2000-10KTL-M1 with firmware V100R001C00SPC153 and LUNA2000 battery (15kWh). I know the Huawei integration documentation in HA says the firmware should be V200R001C00, but it seems not straightforward to upgrade this. So I tried with the current firmware and connection to the dongle Modbus interface. I asked my installer if the system can be upgraded, but no answer.

@KmanOz Can you share the Yaml please ?

this is mine…

type: vertical-stack
cards:
  - type: picture-elements
    image: local/pics/Sun2000Front.png
    elements:
      - type: state-label
        entity: sensor.inverter_input_power
        prefix: 'Produzione Attuale:  '
        style:
          color: grey
          top: 82%
          left: 50%
          font-size: 20px
      - type: state-label
        entity: sensor.inverter_daily_yield
        prefix: 'Prodotti Oggi:  '
        style:
          color: grey
          top: 12%
          left: 50%
          font-size: 20px
      - type: custom:mini-graph-card
        card_mod:
          style: |
            ha-card {
            --ha-card-background: "rgba(0, 0, 0, 0.3)";
              #
              #
            box-shadow: none;
            color: var(--primary-color);
            }
            .header {
              display: none !important;
            }
        style:
          top: 50%
          left: 50%
          width: 90%
          height: 42%
        entities:
          - entity: sensor.inverter_input_power
        show:
          name: false
          state: false
          icon: false
          extrema: true
          line_width: 1
          font_size: 125
          height: 100
          points_per_hour: 12
          fill: fade
  - type: custom:mini-graph-card
    entities:
      - sensor.power_meter_active_power
    name: W da/per la Rete
    points_per_hour: 8
    show_state: true
    icon: mdi:transmission-tower-export
    hours_to_show: 24
    show:
      extrema: true
      fill: false
    animate: true
    height: 150
    line_width: 2
  - type: entities
    entities:
      - entity: sensor.inverter_active_power
        name: Potenza Attiva
      - entity: sensor.inverter_input_power
        name: Potenza Immessa
      - entity: sensor.inverter_daily_yield
        name: Resa Oggi
      - entity: sensor.inverter_internal_temperature
        name: Temperatura Interna
type: vertical-stack
cards:
  - type: picture-elements
    image: local/pics/Luna2000Front.png
    elements:
      - type: state-label
        entity: sensor.battery_charge_discharge_power
        prefix: 'Carica/Scarica:  '
        style:
          color: grey
          top: 82%
          left: 51%
          font-size: 15px
      - type: state-label
        entity: sensor.battery_day_charge
        prefix: 'Caricati Oggi:  '
        style:
          color: grey
          top: 15%
          left: 50%
          font-size: 15px
      - type: state-label
        entity: sensor.battery_day_discharge
        prefix: 'Scaricati Oggi:  '
        style:
          color: grey
          top: 20%
          left: 50%
          font-size: 15px
      - type: state-label
        entity: sensor.battery_state_of_capacity
        style:
          color: green
          top: 40%
          left: 52%
          font-size: 40px
      - type: custom:mini-graph-card
        card_mod:
          style: |
            ha-card {
              --ha-card-background: "rgba(0, 0, 0, 0.3)";


              box-shadow: none;
              color: var(--primary-color);
            }
            .header {
              display: none !important;
            }
        style:
          top: 54%
          left: 50.5%
          width: 47%
          height: 42%
        entities:
          - entity: sensor.battery_state_of_capacity
        show:
          name: false
          state: false
          icon: false
          extrema: false
          line_width: 1
          font_size: 75
          height: 120
          points_per_hour: 12
          fill: fade
  - type: custom:mini-graph-card
    entities:
      - sensor.richiesta_energia_casa
    name: W Richiesti dalla Casa
    points_per_hour: 8
    icon: mdi:power-plug
    hours_to_show: 24
    show:
      extrema: true
      fill: false
    animate: true
    height: 150
    line_width: 2
  - type: entities
    entities:
      - entity: sensor.battery_charge_discharge_power
        name: Potenza Carica(+)/Scarica(-)
      - entity: sensor.battery_day_charge
        name: Ricaricati Oggi
      - entity: sensor.battery_day_discharge
        name: Scaricati Oggi
      - entity: switch.battery_charge_from_grid
        name: Carica dalla Rete

4 Likes

Hi AleDre,

Would you have a link to where you got the icon/images from, as the ones I’ve tried end up with the sensors for the LUNA hidden by the black badge section.

Also could you confirm is sensor.richiesta_energia_casa a Huawei / WLCRS integration sensor, or a custom sensor? What data is it providing?

Thanks.

the images was found by google in png format, and the sensor.richiesta_energia_casa is calculated

template:
  - sensor:
      - name: "Richiesta Energia Casa"
        unique_id: home_total_power_request
        state: >-
          {{ (states('sensor.inverter_input_power')|float -
              states('sensor.battery_charge_discharge_power')|float -
              states('sensor.power_meter_active_power')|float) }}
        unit_of_measurement: W
        device_class: power
        state_class: measurement

Can you explain to me how you configured the 802N to make it work in this way?
Thank you

I’m actually having the same issue. Communication was working during months but 5 days ago wifi disconnected and It’s impossible to reconnect. It just works again reinstalling HA. Did you found the solution? I also think NetworkManager is part of the problem…

Have you updated your inverter amd battery with the latest firmware. I updated mine about a month ago, and all my connectivity drop-outs went away immediately.

same here !! finnaly

1 Like

Thank you so much. Problem solved. In my case: I was in firmware version [SUN2000L V200R001C00SPC130]. Now with [SUN2000L V200R001C00SPC138] works like a charm!

2 Likes