home_assistant_solarman icon indicating copy to clipboard operation
home_assistant_solarman copied to clipboard

Passive mode and forced charge/discharge on sofar_g3hyd.yaml

Open vermut opened this issue 1 year ago • 2 comments

As you know, there are secret codes to enable passive mode and manually force charge/discharge. image

This is useful when you want fine control of your charging combined with EMHASS for example.

I was wondering why it's not implemented yet as a read registers? Should I do it or there is a community policy or opinion?

And what about writing registers to set this mode? Can this integration do that somehow or it's purely read mode and I should just implement those modbus calls separately?

Sample force-discharge 1000W code

from pysolarmanv5.pysolarmanv5 import PySolarmanV5

sofar = PySolarmanV5('172.16.x.x', 2222222222, verbose=True)
sofar.write_multiple_holding_registers(register_addr=4368, values=[3])
print(sofar.read_holding_registers(register_addr=4368, quantity=1))
sofar.write_multiple_holding_registers(register_addr=4487, values=[0xFFFF, 0xFC18, 0xFFFF, 0xFC18, 0xFFFF, 0xFC18])

vermut avatar Apr 26 '24 06:04 vermut

Have you tried your code? just to know

execcr avatar May 09 '24 06:05 execcr

Yes, it works for me. Here is a nicer version:

from pysolarmanv5.pysolarmanv5 import PySolarmanV5

sofar = PySolarmanV5('172.16.10.211', 2700663862, verbose=True)

MODE_SELF_USE = 0
MODE_TIME_OF_USE = 1
MODE_PASSIVE = 3


def set_passive_mode(charge_rate: int):
    set_mode(MODE_PASSIVE)

    # Convert charge_rate to two 16-bit words
    high_word = (charge_rate >> 16) & 0xFFFF
    low_word = charge_rate & 0xFFFF

    # Repeat the words three times
    values = [high_word, low_word] * 3

    ret = sofar.write_multiple_holding_registers(register_addr=4487, values=values)
    assert ret == len(values), "Wrong number of values returned"


def set_mode(mode):
    ret = sofar.read_holding_registers(register_addr=4368, quantity=1)
    if ret != [mode]:
        print("Updating mode")
        ret = sofar.write_multiple_holding_registers(register_addr=4368, values=[mode])
        assert ret == 1, "Wrong number of values returned"


# set_passive_mode(-10000)
set_mode(MODE_SELF_USE)

I'm just asking if I need another integration to WRITE data or @StephanJoubert 's solution has place for it.

vermut avatar May 09 '24 06:05 vermut

Actually I just realized that there is write register service call and it works. So I'd just create a helper to properly parse negative values for passivemode discharge.

service: solarman.write_multiple_holding_registers
data:
  register: 4368
  values: 0

vermut avatar May 11 '24 05:05 vermut

@vermut Could you precise a bit more on how to do this?

I'm trying to set mine up so that I can trigger a force-charge when needed. Also, do I need to switch to passive-mode to do that and then switch back to self-use? Lastly, is this possible with the LSW3 logger?

SamirHafez avatar Aug 12 '24 10:08 SamirHafez

Yes, you need to either switch back or adjust the charging parameters. No idea about LSW3, I'm using this integration's HA service.

Two things to keep in mind: registers are VERY inverter specific, and setting them sometimes fails. So it's better to have some retry/failsafe logic, because you might set to passive and then, when setting self-use, if will silently fail.

I'm providing 2 automation scripts that you can use as inspiration - first to discharge to desired SOC, second - to charge until end-of-hour (like when there is cheap period).

alias: Discharge to 60% SOC
sequence:
  - service: solarman.write_multiple_holding_registers
    data:
      register: 4487
      values:
        - 65535
        - 55536
        - 65535
        - 55536
        - 65535
        - 55536
  - service: solarman.write_multiple_holding_registers
    data:
      register: 4368
      values:
        - 3
  - wait_template: "{{ states('sensor.solarman_battery_1_soc')|int < 60 }}"
    continue_on_timeout: true
    timeout: "3600"
  - service: solarman.write_multiple_holding_registers
    data:
      register: 4368
      values:
        - 0
mode: single
icon: mdi:battery-60
alias: Charge to until next hour
sequence:
  - service: solarman.write_multiple_holding_registers
    data:
      register: 4487
      values:
        - 0
        - 10000
        - 0
        - 10000
        - 0
        - 10000
  - service: solarman.write_multiple_holding_registers
    data:
      register: 4368
      values:
        - 3
  - delay:
      hours: 0
      minutes: |
        {{ (60 - now().minute) % 60 }}
      seconds: 0
      milliseconds: 0
  - service: solarman.write_multiple_holding_registers
    data:
      register: 4368
      values:
        - 0
mode: restart
icon: mdi:battery

I say again - those service calls can fail silently.

vermut avatar Aug 12 '24 10:08 vermut

Thank you @vermut I'm seeing repeatedly:

Service Call: write_multiple_holding_registers: [4368], values : [[0]] failed with exception [IllegalDataAddressError: The data address received in the request is not an allowable address for the server. ]

So I'm guessing this might not be the right register for my inverter as I don't think it's the G3. I'll have to keep digging.

SamirHafez avatar Aug 12 '24 11:08 SamirHafez

@vermut Could you provide me with the document you screenshotted in the description 🙏🏽 ?

No idea about LSW3, I'm using this integration's HA service.

Same, but how is HA connecting to the inverter? Via the WiFi dongle?

SamirHafez avatar Aug 12 '24 15:08 SamirHafez

Yes, wifi dongle, LSW3_15_270A_1.68. Again, registers are model-specific.

vermut avatar Aug 12 '24 15:08 vermut

Yes, wifi dongle, LSW3_15_270A_1.68. Again, registers are model-specific.

@vermut my version says LSW3_15_FFFF_1.0.96... so this might be far too old

SamirHafez avatar Aug 12 '24 17:08 SamirHafez