Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Solax Inverters #259

Open
Bart39 opened this issue Nov 4, 2023 · 51 comments
Open

Solax Inverters #259

Bart39 opened this issue Nov 4, 2023 · 51 comments

Comments

@Bart39
Copy link

Bart39 commented Nov 4, 2023

Splitting this out to separate request.
Please add support for Solax inverters.
I use https://github.com/wills106/homeassistant-solax-modbus for HA integration (also supports other brands of inverters)
As I have an X1 gen 4 inverter https://github.com/wills106/homeassistant-solax-modbus/wiki/Modbus-Power-Control-(remotecontrol-power) is the preferred method as it avoids excessive writes to eeprom

@fboundy
Copy link
Collaborator

fboundy commented Nov 4, 2023 via email

@Bart39
Copy link
Author

Bart39 commented Nov 5, 2023

Perfect, many thanks

@fboundy
Copy link
Collaborator

fboundy commented Nov 7, 2023

OK - I think I'm getting there. What I first need to add Solax is for you to try to edit the config.yaml file with the entities you would use for a Solax inverter and then to comment any that are different.

Then can you answer the following:

  • What format are the charge/discharge start/end entities? (i.e to they take a string as HH:MM(Givenerrgy) or are there separate entities for Hours and Minutes (Solis)
  • Once you have set the start/end time entities, do they automatically get written to the inverter or do you have to press a button?
  • Do you set Power or Current during a timed Charge/Discharge?
  • Can you set a Target SOC for a timed charge or discharge period?
  • Does the inverter report SOC in kWh or Percent?
  • Is there a specific boolean entity to toggle to enable Timed Charge and/or Discharge?
  • Can you set a Reserve or Backup SOC?
  • Does the inverter have a specific Mode that needs setting for Timed Charge, Discharge or Backup?

There's probably more but that would be a decent start!

@Bart39
Copy link
Author

Bart39 commented Nov 8, 2023

Thanks, will do (I have it already working in read only mode)
FYI for my inverter (X1-Hybrid Gen 4) it doesn’t really have a timed charge/discharge mode rather it allows you to change the mode between Self use, forced charge, forced discharge etc but they are instant, however the preferred method is by using “Modbus Power Control” which again is instant but gives you finer control on power limits / duration and doesn’t write to eeprom (saving limited writes)
Will write this all up later today when I am back at home

@fboundy
Copy link
Collaborator

fboundy commented Nov 8, 2023

OK - so I think I have BatPred working with the Solis. To get the Solax working, in addition to the above we need

Constants

  • Battery capacity in kWh
  • Max Battery Power
  • Max Inverter Power (if different from Battery)

Entity IDs for the following sensors:

Cumulative Daily Energy

  • Load today in kWh (resetting daily)
  • Import today in kWh (resetting daily)
  • Export today in kWh (resetting daily)
  • PV Generation today in kWh (resetting daily)

Current Power / Battery Readings

  • Battery power
  • PV power
  • Load power
  • Battery SOC (%)

Others

  • Inverter clock (if available) - if so let me know the format it reports in

Entity IDs for the Modbus Power Control Entities

I think I can get all of these from here but no harm to confirm them.

@Bart39
Copy link
Author

Bart39 commented Nov 12, 2023

Sorry it took a while as work has been crazy

Constants

  • Battery capacity in kWh
    • 9.3
  • Max Battery Power
    • 6100w
  • Max Inverter Power (if different from Battery)
    • 6100w

Cumulative Daily Energy

  • Load today in kWh (resetting daily)
    • sensor.solax_today_house_load (utility helper as there is no daily total load from the inverter)
  • Import today in kWh (resetting daily)
    • sensor.solax_today_s_import_energy
  • Export today in kWh (resetting daily)
    • sensor.solax_today_s_export_energy
  • PV Generation today in kWh (resetting daily)
    • sensor.solax_today_s_solar_energy

Current Power / Battery Readings

  • Battery power
    • sensor.solax_battery_power_charge
  • PV power
    • sensor.solax_pv_power_total
  • Load power
    • sensor.solax_house_load
  • Battery SOC (%)
    • sensor.solax_battery_capacity

Others

  • Inverter clock (if available) - if so let me know the format it reports in
    • sensor.solax_rtc (disabled by default due to the constant updates)
    • YYYY-MM-DD HH24:MI:SS

Entity IDs for the Modbus Power Control Entities

Set Mode
select.solax_remotecontrol_power_control

  • "Disabled",
    
  • "Enabled Power Control",
    
  • "Enabled Grid Control",
    
  • "Enabled Battery Control",
    
  • "Enabled Self Use",
    
  • "Enabled Feedin Priority"
    
  • "Enabled No Discharge"
    
    • When remotecontrol_power_control = Enabled Power Control is chosen, the target value refers to the battery interface where positive values will cause batteries to charge, negative values will make the batteries discharge. When the target is set to zero, in the presence of PV, the PV will go to the battery, the house load will come from the grid. If in addition to selecting this mode, remote_control_import_limit is set to Zero, the house load will come from PV and battery only. Enabled Power Control is the basic mode offered by solax, it allows us to specify activepower directly, but the notion activepower may be difficult to understand, so grid control and battery control may be easier to understand.
    • When remotecontrol_power_control = Enabled Grid Control is chosen, the target value refers to the grid interface where positive values mean import, negative values mean export. When using this mode, make sure that remotecontrol_import_limit is set to a high enough value so that the import target can be reached.
    • When remotecontrol_power_control = Enabled Battery Control is chosen, the target value refers to the battery interface where positive values mean charge, negative values mean discharge. If target is set to zero, excess PV power will be sent to the grid.
    • NEW: When remotecontrol_power_control = Enabled Self Use is chosen, the target value is ignored and the system will emulate the standard self-use mode for the specified (autorepeat) duration. This mode may not be as accurate/responsive as the builtin self_use mode.
    • NEW: When remotecontrol_power_control = Enabled Feedin Priority is chosen, the target value is ignored and the system will emulate the standard feedin-priority mode for the specified (autorepeat) duration. This mode may not be as accurate/responsive as the builtin feedin_priority mode.
    • NEW: When remotecontrol_power_control = Enabled No Discharge is chosen, the target value is ignored and the system will make sure that the battery does not discharge. Houseload will be provided by PV, and when PV is insufficient, from Grid.

I prefer using battery control to charge, No discharge for charge freeze, and grid control for export

Set Active Power (Watts - positive charge, negative discharge)

  • number.solax_remotecontrol_active_power

Set Autorepeat duration (seconds)

  • number.solax_remotecontrol_autorepeat_duration

Main button press to start the selected mode with the active power for the specified duration

  • button.solax_remotecontrol_trigger

@fboundy
Copy link
Collaborator

fboundy commented Nov 12, 2023 via email

@nikotime
Copy link

nikotime commented Dec 8, 2023

Hey, I have a Solax system and use the same integration to control it. Anything a layperson can do to support at this stage?

@springfall2008
Copy link
Owner

@nikotime the work so far has been pushed to main including the template configuration and the code. Maybe you can give it a try and feedback?

@nikolearnerbly
Copy link

@nikotime the work so far has been pushed to main including the template configuration and the code. Maybe you can give it a try and feedback?

Oh wow! Just found the guide,

## Inverter Control Integration install (GivTCP/SolaX-ModBus)

Will give it a go this weekend :)

@nikotime
Copy link

Sorry @Bart39 , could you please share how you set up the utility sensor for total daily load? I've been struggling and getting some wildly wrong numbers!

sensor.solax_today_house_load (utility helper as there is no daily total load from the inverter)

@gcoan
Copy link
Collaborator

gcoan commented Dec 15, 2023

Sorry @Bart39 , could you please share how you set up the utility sensor for total daily load? I've been struggling and getting some wildly wrong numbers!

sensor.solax_today_house_load (utility helper as there is no daily total load from the inverter)

There's a sample template sensor in the predbat docs for calculating house load https://springfall2008.github.io/batpred/config-yml-settings/#data-from-givtcp as I have two GivEnergy inverters and as they share the load between them, I found I couldn't use the inbuilt entities.

You should be able to follow this approach for your inverter

@Bart39
Copy link
Author

Bart39 commented Jan 7, 2024

Sorry @Bart39 , could you please share how you set up the utility sensor for total daily load? I've been struggling and getting some wildly wrong numbers!

sensor.solax_today_house_load (utility helper as there is no daily total load from the inverter)

Sorry have been busy and not spotted this
i create all my sensors directly in yaml so this is what i have:
First create a sensor to track the house load and then secondly add a utility helper to accumulate and reset daily:

sensor:
    - platform: integration
      source: sensor.solax_house_load
      name: house_load_total
      unit_prefix: k
      round: 2
      method: left
utility_meter:
    solax_today_house_load:
      source: sensor.house_load_total
      cycle: daily

@Bart39
Copy link
Author

Bart39 commented Jan 19, 2024

@fboundy any progress on solax modbus control ?
If this is proving tricky or doesn't really fit with the other supported inverters @springfall2008 would it be worth considering exposing some sensors for the charging/discharging mode, power / Soc limits, start/end times etc ?
That way it would universally support any inverter that can be controlled through HA via our own automations

@fboundy
Copy link
Collaborator

fboundy commented Jan 19, 2024 via email

@nikotime
Copy link

Just got PV OPT set up with my Solax inverter and is now in read only mode :) I used the SOLIS_SOLAX_MODBUS inverter type and only had to make the following changes:

  id_consumption_today: sensor.energy_house_load_today
  id_grid_import_today: sensor.{device_name}_today_s_import_energy
  id_grid_export_today: sensor.{device_name}_today_s_export_energy
  id_battery_soc: sensor.{device_name}_battery_capacity

Big thing I guess relates to Bart's point earlier that PV OPT also seems to just work with this concept of timed_charge and discharge which doesn't exist in Solax. Need to configure the graphs etc and get more history for house load and then will look into GUI Automations to trigger changes to forced charge and forced discharge.

You rock @fboundy

@springfall2008
Copy link
Owner

@fboundy any progress on solax modbus control ? If this is proving tricky or doesn't really fit with the other supported inverters @springfall2008 would it be worth considering exposing some sensors for the charging/discharging mode, power / Soc limits, start/end times etc ? That way it would universally support any inverter that can be controlled through HA via our own automations

I did release the solax code for Predbat also so I think it’s usable but I can’t test it myself.

@Bart39
Copy link
Author

Bart39 commented Jan 21, 2024

@fboundy any progress on solax modbus control ? If this is proving tricky or doesn't really fit with the other supported inverters @springfall2008 would it be worth considering exposing some sensors for the charging/discharging mode, power / Soc limits, start/end times etc ? That way it would universally support any inverter that can be controlled through HA via our own automations

I did release the solax code for Predbat also so I think it’s usable but I can’t test it myself.

In read only it looks to work really well, just can't use it to control the charge / discharge as solax doesn't support a timed charge /discharge

@springfall2008
Copy link
Owner

Timed charge should work as predbat has an immediate mode where it forces charging on and off at the correct times

@nikotime
Copy link

@springfall2008 I'm so sorry would you mind linking to the released Solax code in the github which supports the immediate mode? I've been trying to find how to change the Solis integration to use 'Modbus Power Control Mode' as per https://github.com/springfall2008/batpred/blob/c1d5d7087b927a4060ac36cfbf730bfc18ecfc1c/docs/other-inverters.md but can't see that option in the ginlong_solis.yaml or anything solax specific through searching through the repo.

@springfall2008
Copy link
Owner

Sorry I’ve been a bit distracted, the code lists it as “SX4” which when enabled will use power control
To start and stop charging. What we are missing is a template configuration which maybe you can help with?

@nikotime
Copy link

nikotime commented Feb 4, 2024

I can definitely try and help with that!

Firstly I needed to create house load which was kindly provided by other clever people - I just have this in configuration.yaml:

sensor:
  - platform: integration
    source: sensor.solaxmodbus_house_load
    name: "Energy House Load Total"
    unique_id: "energy_house_load_total"
    method: trapezoidal
    unit_prefix: k
    unit_time: h
    round: 2

apps.yaml settings I used (ps my intergration is called solaxmodbus rather than solax as default):

  # Max inverter power from battery
  battery_rate_max:
    - 5000
  # Battery capacity in kWh
  soc_max:
    - 11.6

  # Solax specific parameters (these are based on https://github.com/wills106/homeassistant-solax-modbus)

  load_today:
    - sensor.energy_house_load_today
  import_today:
    - sensor.solaxmodbus_today_s_import_energy
  export_today:
    - sensor.solaxmodbus_today_s_export_energy
  pv_today:
    - sensor.solaxmodbus_today_s_solar_energy

  battery_voltage:
    - sensor.solaxmodbus_battery_voltage_charge

  # I manually enabled solax time in the integration but it killed the whole integration after about 30 seconds. Not recommended! I just pulled in a separate sensor for date time to avoid expected errors
  # inverter_time:
  # - sensor.date_time

  # This is disabled by default in the Solax integration so it must be manually enabled.
  battery_power:
    - sensor.solaxmodbus_battery_power_charge
  pv_power:
    - sensor.solaxmodbus_pv_power_total

  load_power:
    - sensor.solaxmodbus_house_load
 
   soc_percent:
    - sensor.solaxmodbus_battery_capacity

  reserve:
    - number.solaxmodbus_backup_discharge_min_soc

  battery_min_soc:
    - sensor.solaxmodbus_feedin_discharge_min_soc

  inverter_limit: 5000

Then the problem I experienced was with the control. I tried:


energy_control_switch:
  - select.solaxmodbus_remotecontrol_power_control

But no luck, down to not enabling SX4 but I now can't find anything relating to SX4 in Github either 😅

@springfall2008
Copy link
Owner

Have you tried setting:

inverter_type: "SX4"

This should change the controls to be more suitable.

Can you clarify how Predbat should start/stop charges and forced export?

@springfall2008
Copy link
Owner

What would be good is if you can share an automation that charges the battery and one that exports it

@nikotime
Copy link

I will try changing inverter type hopefully tomorrow and see if it works (if my baby sleeps enough to buy me time!)

For now here are my automations to force charge.

`alias: Predbat Charger Automation True
description: ""
trigger:
  - platform: state
    entity_id:
      - sensor.predbat_current_charging_session
    for:
      hours: 0
      minutes: 0
      seconds: 0
condition:
  - condition: state
    entity_id: sensor.predbat_current_charging_session
    state: "True"
    for:
      hours: 0
      minutes: 0
      seconds: 0
action:
  - device_id: 2780f933c7dfa3b564a86f618a26dfdb
    domain: select
    entity_id: 5c3fe78f0b70a79ac641d8ed49176c94
    type: select_option
    option: Manual Mode
  - device_id: 2780f933c7dfa3b564a86f618a26dfdb
    domain: select
    entity_id: 357cfa49177419da9d42526a8ac8bdd6
    type: select_option
    option: Force Charge
mode: single

And discharge is exactly the Same as above but select option Force Discharge

This is my code to reset it to normal after

alias: Predbat Charger Automation False
description: ""
trigger:
  - platform: state
    entity_id:
      - sensor.predbat_current_charging_session
    for:
      hours: 0
      minutes: 0
      seconds: 0
condition:
  - condition: state
    entity_id: sensor.predbat_current_charging_session
    state: "False"
    for:
      hours: 0
      minutes: 0
      seconds: 0
action:
  - device_id: 2780f933c7dfa3b564a86f618a26dfdb
    domain: select
    entity_id: 5c3fe78f0b70a79ac641d8ed49176c94
    type: select_option
    option: Self Use Mode
mode: single

@nikotime
Copy link

nikotime commented Feb 12, 2024

I have just tried setting it as SX4 and get:
2024-02-12 17:22:28.977032 INFO pred_bat: ERROR: Exception raised argument of type 'NoneType' is not iterable

Here it is the full log: https://pastebin.com/QfzNFpPs

Can confirm read only mode still works and I get the full Predbat plan. Let me know if there are more detailed logs I can pull!

@springfall2008
Copy link
Owner

For the error you probably need to capture the stack trace from 'settings, system, logs, appdeamon' so I can see what causes it.

Taking a step back can you share your apps.yaml so far so I know what you have configured?

@nikotime
Copy link

nikotime commented Feb 13, 2024

Sure, thanks!

Apps.yaml: https://pastebin.com/Ser82dSC

And here is the stack trace:



  File "/usr/lib/python3.11/concurrent/futures/_base.py", line 401, in __get_result
    raise self._exception
  File "/usr/lib/python3.11/site-packages/appdaemon/adapi.py", line 588, in _check_entity
    if "." not in entity:
       ^^^^^^^^^^^^^^^^^
TypeError: argument of type 'NoneType' is not iterable

2024-02-13 08:45:04.002111 WARNING pred_bat: ------------------------------------------------------------
2024-02-13 08:50:04.024183 WARNING pred_bat: ------------------------------------------------------------
2024-02-13 08:50:04.025037 WARNING pred_bat: Unexpected error in worker for App pred_bat:
2024-02-13 08:50:04.025959 WARNING pred_bat: Worker Ags: {'id': 'cad7e4124fd948adb57863342941485e', 'name': 'pred_bat', 'objectid': '38a38edca8844d53a1634f83d5a1d78e', 'type': 'scheduler', 'function': <bound method PredBat.run_time_loop of <predbat.PredBat object at 0x7ff62f593050>>, 'pin_app': True, 'pin_thread': 0, 'kwargs': {'interval': 300, 'random_start': 0, 'random_end': 0, '__thread_id': 'thread-0'}}
2024-02-13 08:50:04.026247 WARNING pred_bat: ------------------------------------------------------------
2024-02-13 08:50:04.027896 WARNING pred_bat: Traceback (most recent call last):
  File "/usr/lib/python3.11/site-packages/appdaemon/threading.py", line 1022, in worker
    funcref(self.AD.sched.sanitize_timer_kwargs(app, args["kwargs"]))
  File "/usr/lib/python3.11/site-packages/appdaemon/adbase.py", line 35, in f_app_lock
    return f(*args, **kw)
           ^^^^^^^^^^^^^^
  File "/config/apps/predbat.py", line 12119, in run_time_loop
    raise e
  File "/config/apps/predbat.py", line 12115, in run_time_loop
    self.update_pred(scheduled=True)
  File "/usr/lib/python3.11/site-packages/appdaemon/adbase.py", line 35, in f_app_lock
    return f(*args, **kw)
           ^^^^^^^^^^^^^^
  File "/config/apps/predbat.py", line 11142, in update_pred
    status, status_extra = self.execute_plan()
                           ^^^^^^^^^^^^^^^^^^^
  File "/config/apps/predbat.py", line 9834, in execute_plan
    self.reset_inverter()
  File "/config/apps/predbat.py", line 9811, in reset_inverter
    inverter.adjust_charge_rate(inverter.battery_rate_max_charge * MINUTE_WATT)
  File "/config/apps/predbat.py", line 1940, in adjust_charge_rate
    entity = self.base.get_entity(self.base.get_arg("charge_rate", indirect=False, index=self.id))
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/appdaemon/adapi.py", line 3188, in get_entity
    self._check_entity(namespace, entity)
  File "/usr/lib/python3.11/site-packages/appdaemon/utils.py", line 231, in inner_sync_wrapper
    f = run_coroutine_threadsafe(self, coro(self, *args, **kwargs))
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/appdaemon/utils.py", line 313, in run_coroutine_threadsafe
    result = future.result(self.AD.internal_function_timeout)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/concurrent/futures/_base.py", line 456, in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/concurrent/futures/_base.py", line 401, in __get_result
    raise self._exception
  File "/usr/lib/python3.11/site-packages/appdaemon/adapi.py", line 588, in _check_entity
    if "." not in entity:

@punkymuzzle
Copy link

Hi
Absolutely loving the work that everyone has put in here, it's really appreciated.
I have a Solax X1 AC inverter with a Waveshare Modbus attached, and have access to all of the entities for the inverter.
I have installed Predbat and have successfully managed to get it fully monitoring and predicting etc, which is awesome.
The problem is that I can't get it to charge / discharge the battery as per the plan, even though I've enabled charge / discharge in predbat.
I'm assuming that the issue is predbat knowing the exact commends to send to my inverter, so was wondering if anyone could help in solving this with me?
Happy to provide whatever information I can to help get this sorted, as I know others are in the same situation as me.

Many thanks in advance

@springfall2008
Copy link
Owner

I'm not sure were @nikotime got with this, I kind of lost track.

@punkymuzzle what is currently in your apps.yaml for Solax? If you have an automation example to start/stop charge we can use the service feature in apps.yaml to trigger it.

@springfall2008
Copy link
Owner

See the end of this page on unsupported inverter types: https://springfall2008.github.io/batpred/other-inverters/

@nikotime
Copy link

I'm not sure were @nikotime got with this, I kind of lost track.

@punkymuzzle what is currently in your apps.yaml for Solax? If you have an automation example to start/stop charge we can use the service feature in apps.yaml to trigger it.

Hey! Where we got to I believe is that something was up with my apps.yaml as I was getting errors, so i shared my file and the error log. I have been able to build automations relying on a helper which spits out true or false (shared a few of my comments ago) if we are currently in the time set by predbat.best_charge_start but failed to get any further to let predbat control the inverter directly. The logic of reading all my solaxmodbus sensors to build out the plans works perfectly well though!

@springfall2008
Copy link
Owner

I'm not sure were @nikotime got with this, I kind of lost track.

@punkymuzzle what is currently in your apps.yaml for Solax? If you have an automation example to start/stop charge we can use the service feature in apps.yaml to trigger it.

Hey! Where we got to I believe is that something was up with my apps.yaml as I was getting errors, so i shared my file and the error log. I have been able to build automations relying on a helper which spits out true or false (shared a few of my comments ago) if we are currently in the time set by predbat.best_charge_start but failed to get any further to let predbat control the inverter directly. The logic of reading all my solaxmodbus sensors to build out the plans works perfectly well though!

Can you share your apps.yaml so far ?

@nikotime
Copy link

Sure, thanks!

Apps.yaml: https://pastebin.com/Ser82dSC

And here is the stack trace:



  File "/usr/lib/python3.11/concurrent/futures/_base.py", line 401, in __get_result
    raise self._exception
  File "/usr/lib/python3.11/site-packages/appdaemon/adapi.py", line 588, in _check_entity
    if "." not in entity:
       ^^^^^^^^^^^^^^^^^
TypeError: argument of type 'NoneType' is not iterable

2024-02-13 08:45:04.002111 WARNING pred_bat: ------------------------------------------------------------
2024-02-13 08:50:04.024183 WARNING pred_bat: ------------------------------------------------------------
2024-02-13 08:50:04.025037 WARNING pred_bat: Unexpected error in worker for App pred_bat:
2024-02-13 08:50:04.025959 WARNING pred_bat: Worker Ags: {'id': 'cad7e4124fd948adb57863342941485e', 'name': 'pred_bat', 'objectid': '38a38edca8844d53a1634f83d5a1d78e', 'type': 'scheduler', 'function': <bound method PredBat.run_time_loop of <predbat.PredBat object at 0x7ff62f593050>>, 'pin_app': True, 'pin_thread': 0, 'kwargs': {'interval': 300, 'random_start': 0, 'random_end': 0, '__thread_id': 'thread-0'}}
2024-02-13 08:50:04.026247 WARNING pred_bat: ------------------------------------------------------------
2024-02-13 08:50:04.027896 WARNING pred_bat: Traceback (most recent call last):
  File "/usr/lib/python3.11/site-packages/appdaemon/threading.py", line 1022, in worker
    funcref(self.AD.sched.sanitize_timer_kwargs(app, args["kwargs"]))
  File "/usr/lib/python3.11/site-packages/appdaemon/adbase.py", line 35, in f_app_lock
    return f(*args, **kw)
           ^^^^^^^^^^^^^^
  File "/config/apps/predbat.py", line 12119, in run_time_loop
    raise e
  File "/config/apps/predbat.py", line 12115, in run_time_loop
    self.update_pred(scheduled=True)
  File "/usr/lib/python3.11/site-packages/appdaemon/adbase.py", line 35, in f_app_lock
    return f(*args, **kw)
           ^^^^^^^^^^^^^^
  File "/config/apps/predbat.py", line 11142, in update_pred
    status, status_extra = self.execute_plan()
                           ^^^^^^^^^^^^^^^^^^^
  File "/config/apps/predbat.py", line 9834, in execute_plan
    self.reset_inverter()
  File "/config/apps/predbat.py", line 9811, in reset_inverter
    inverter.adjust_charge_rate(inverter.battery_rate_max_charge * MINUTE_WATT)
  File "/config/apps/predbat.py", line 1940, in adjust_charge_rate
    entity = self.base.get_entity(self.base.get_arg("charge_rate", indirect=False, index=self.id))
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/appdaemon/adapi.py", line 3188, in get_entity
    self._check_entity(namespace, entity)
  File "/usr/lib/python3.11/site-packages/appdaemon/utils.py", line 231, in inner_sync_wrapper
    f = run_coroutine_threadsafe(self, coro(self, *args, **kwargs))
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/appdaemon/utils.py", line 313, in run_coroutine_threadsafe
    result = future.result(self.AD.internal_function_timeout)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/concurrent/futures/_base.py", line 456, in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/concurrent/futures/_base.py", line 401, in __get_result
    raise self._exception
  File "/usr/lib/python3.11/site-packages/appdaemon/adapi.py", line 588, in _check_entity
    if "." not in entity:

@springfall2008 no worries it’s here https://pastebin.com/Ser82dSC and have the stack trace above too

@gcoan
Copy link
Collaborator

gcoan commented Mar 23, 2024

Sure, thanks!

Apps.yaml: https://pastebin.com/Ser82dSC

This bit isn't correctly indented YAML:

  # Some inverters don't turn off when the rate is set to 0, still charge or discharge at around 200w
  # The value can be set here in watts to model this (doesn't change operation)
  inverter_battery_rate_min:
   - 100

it should be:

  # Some inverters don't turn off when the rate is set to 0, still charge or discharge at around 200w
  # The value can be set here in watts to model this (doesn't change operation)
  inverter_battery_rate_min:
    - 100

Two indented spaces before the dash

This may be throwing the rest of the YAML file off. The export triggers also look to have too many spaces (3 or 4 rather than 2), but I don't think that's the issue

springfall2008 added a commit that referenced this issue Mar 28, 2024
@springfall2008
Copy link
Owner

springfall2008 commented Mar 28, 2024

@springfall2008 no worries it’s here https://pastebin.com/Ser82dSC and have the stack trace above too
Fix pushed to main

@springfall2008
Copy link
Owner

@nikotime
Copy link

@springfall2008 Amazing thanks. I just gave it a quick go and the error message went a way, the status is at Idle or turned to charging when I force charged but my batteries alas didn't charge. Going to have another look tomorrow to try and see why (if any entities change at all) and no errors sprung out the log that I saw, but will share logs properly when I give myself more time too.

@nikotime
Copy link

nikotime commented Mar 29, 2024

Have looked a little more.

When I first change from read only mode I get an strptime error from inverter.adjust_charge_window(charge_start_time, charge_end_time, self.minutes_now) so guessing one of those entities isn't working (not sure how to check!). Log below

2024-03-29 21:00:46.215376 WARNING pred_bat: ------------------------------------------------------------
2024-03-29 21:00:46.216024 WARNING pred_bat: Unexpected error in worker for App pred_bat:
2024-03-29 21:00:46.221629 WARNING pred_bat: Worker Ags: {'id': 'ee6329efd8494ebfb87a9253ef2d6e96', 'name': 'pred_bat', 'objectid': 'f2590d406c424156b304064ccce3af82', 'type': 'scheduler', 'function': <bound method PredBat.update_time_loop of <predbat.PredBat object at 0x7facfeeb2010>>, 'pin_app': True, 'pin_thread': 0, 'kwargs': {'interval': 15, 'random_start': 0, 'random_end': 0, '__thread_id': 'thread-0'}}
2024-03-29 21:00:46.222457 WARNING pred_bat: ------------------------------------------------------------
2024-03-29 21:00:46.226988 WARNING pred_bat: Traceback (most recent call last):
  File "/usr/lib/python3.11/site-packages/appdaemon/threading.py", line 1022, in worker
    funcref(self.AD.sched.sanitize_timer_kwargs(app, args["kwargs"]))
  File "/usr/lib/python3.11/site-packages/appdaemon/adbase.py", line 35, in f_app_lock
    return f(*args, **kw)
           ^^^^^^^^^^^^^^
  File "/config/apps/predbat.py", line 12687, in update_time_loop
    raise e
  File "/config/apps/predbat.py", line 12682, in update_time_loop
    self.update_pred(scheduled=False)
  File "/usr/lib/python3.11/site-packages/appdaemon/adbase.py", line 35, in f_app_lock
    return f(*args, **kw)
           ^^^^^^^^^^^^^^
  File "/config/apps/predbat.py", line 11702, in update_pred
    status, status_extra = self.execute_plan()
                           ^^^^^^^^^^^^^^^^^^^
  File "/config/apps/predbat.py", line 10503, in execute_plan
    inverter.adjust_charge_window(charge_start_time, charge_end_time, self.minutes_now)
  File "/config/apps/predbat.py", line 3633, in adjust_charge_window
    self.press_and_poll_button(entity_id)
  File "/config/apps/predbat.py", line 3668, in press_and_poll_button
    time_pressed = datetime.strptime(entity.get_state(), TIME_FORMAT_SECONDS)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: strptime() argument 1 must be str, not None

2024-03-29 21:00:46.227245 WARNING pred_bat: ------------------------------------------------------------

After leaving it for 5 minutes it then turns to Idle:

image

And then allows me to try and charge.

When I try and charge I get no errors other than the above strptime one appearing again and 'solaxmodbus_charger_use_mode' does not change from Self Use Mode to Manual Mode.

These are the general logs

2024-03-29 21:12:45.703636 INFO pred_bat: ERROR: Exception raised strptime() argument 1 must be str, not None
2024-03-29 21:12:43.698668 WARNING pred_bat: pred_bat: Entity button.solis_update_charge_discharge_times not found in namespace default
2024-03-29 21:12:43.695040 INFO pred_bat: Inverter 0 Wrote 08:30:00 to charge_end_time, successfully now 08:30:00
2024-03-29 21:12:41.680579 INFO pred_bat: Inverter 0 Wrote 21:00:00 to charge_start_time, successfully now 21:00:00
2024-03-29 21:12:39.669909 INFO pred_bat: Configuring charge window now (now 03-29 21:10:00 target set_window_minutes 30 charge start time 03-29 21:00:00
2024-03-29 21:12:39.668772 INFO pred_bat: Inverter 0 current discharge rate is 2600.0 and new target is 0
2024-03-29 21:12:39.667710 INFO pred_bat: Inverter 0 current charge rate is 2600.0 and new target is 5000
2024-03-29 21:12:39.666616 INFO pred_bat: Charge window will be: 2024-03-29 21:00:00+00:00 - 2024-03-30 08:30:00+00:00 - current soc 74 target 95
2024-03-29 21:12:39.665604 INFO pred_bat: Base discharge window [ 29-03 00:00:00 - 29-03 00:00:00 @ 0p 100.0%, 30-03 00:00:00 - 30-03 00:00:00 @ 0p 100.0% ]
2024-03-29 21:12:39.664396 INFO pred_bat: Base charge window [ ]

and again the stack trace logs:

2024-03-29 21:12:45.725131 WARNING pred_bat: ------------------------------------------------------------
2024-03-29 21:12:45.725768 WARNING pred_bat: Unexpected error in worker for App pred_bat:
2024-03-29 21:12:45.726315 WARNING pred_bat: Worker Ags: {'id': 'ee6329efd8494ebfb87a9253ef2d6e96', 'name': 'pred_bat', 'objectid': 'f2590d406c424156b304064ccce3af82', 'type': 'scheduler', 'function': <bound method PredBat.update_time_loop of <predbat.PredBat object at 0x7facfeeb2010>>, 'pin_app': True, 'pin_thread': 0, 'kwargs': {'interval': 15, 'random_start': 0, 'random_end': 0, '__thread_id': 'thread-0'}}
2024-03-29 21:12:45.726831 WARNING pred_bat: ------------------------------------------------------------
2024-03-29 21:12:45.732179 WARNING pred_bat: Traceback (most recent call last):
  File "/usr/lib/python3.11/site-packages/appdaemon/threading.py", line 1022, in worker
    funcref(self.AD.sched.sanitize_timer_kwargs(app, args["kwargs"]))
  File "/usr/lib/python3.11/site-packages/appdaemon/adbase.py", line 35, in f_app_lock
    return f(*args, **kw)
           ^^^^^^^^^^^^^^
  File "/config/apps/predbat.py", line 12687, in update_time_loop
    raise e
  File "/config/apps/predbat.py", line 12682, in update_time_loop
    self.update_pred(scheduled=False)
  File "/usr/lib/python3.11/site-packages/appdaemon/adbase.py", line 35, in f_app_lock
    return f(*args, **kw)
           ^^^^^^^^^^^^^^
  File "/config/apps/predbat.py", line 11702, in update_pred
    status, status_extra = self.execute_plan()
                           ^^^^^^^^^^^^^^^^^^^
  File "/config/apps/predbat.py", line 10503, in execute_plan
    inverter.adjust_charge_window(charge_start_time, charge_end_time, self.minutes_now)
  File "/config/apps/predbat.py", line 3633, in adjust_charge_window
    self.press_and_poll_button(entity_id)
  File "/config/apps/predbat.py", line 3668, in press_and_poll_button
    time_pressed = datetime.strptime(entity.get_state(), TIME_FORMAT_SECONDS)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: strptime() argument 1 must be str, not None

2024-03-29 21:12:45.732468 WARNING pred_bat: ------------------------------------------------------------

So seems like something to do with that inverter.adjust_charge_window function!

EDIT:

And is probably a limitation of Solax to give you the present time. Solax seems to break when the time sensor is enabled so I pulled in a separate sensor just doing

  inverter_time:
    - sensor.date_time

This seems like it was a mistake....

@springfall2008
Copy link
Owner

This appears to relate to:

charge_discharge_update_button:
- button.solis_update_charge_discharge_times

Where its expecting that this entity returns a time that it was last pressed.

Your error indicates the sensor returned None, is this linked to anything or maybe the name is wrong?

@nikotime
Copy link

nikotime commented Apr 1, 2024

This appears to relate to:

charge_discharge_update_button: - button.solis_update_charge_discharge_times

Where its expecting that this entity returns a time that it was last pressed.

Your error indicates the sensor returned None, is this linked to anything or maybe the name is wrong?

@springfall2008 Ah I must have forgotten to comment that one out/change it. I am not aware of anything in Solax that does directly that, but there is button.solaxmodbus_battery_awaken as a potential option. Commenting it out directly gives me the same error as before. Trying the button gives me a few errors unfortunately - I think the pickle one relates to the button. FYI I have never needed to press that button before when doing my automations to change mode. An example output of data after the button is pressed is: 1 April 2024 at 21:51

Errors:


2024-04-01 21:50:05.422159 WARNING pred_bat: ------------------------------------------------------------
2024-04-01 21:50:05.422406 WARNING pred_bat: Unexpected error in worker for App pred_bat:
2024-04-01 21:50:05.422573 WARNING pred_bat: Worker Ags: {'id': 'dfac6db67fa94aa69ecc4e4913ba2c19', 'name': 'pred_bat', 'objectid': '59687914843142d492e38f07f969e56e', 'type': 'scheduler', 'function': <bound method PredBat.run_time_loop of <predbat.PredBat object at 0x7facfd5daa50>>, 'pin_app': True, 'pin_thread': 0, 'kwargs': {'interval': 300, 'random_start': 0, 'random_end': 0, '__thread_id': 'thread-0'}}
2024-04-01 21:50:05.422914 WARNING pred_bat: ------------------------------------------------------------
2024-04-01 21:50:05.426596 WARNING pred_bat: Traceback (most recent call last):
  File "/usr/lib/python3.11/site-packages/appdaemon/threading.py", line 1022, in worker
    funcref(self.AD.sched.sanitize_timer_kwargs(app, args["kwargs"]))
  File "/usr/lib/python3.11/site-packages/appdaemon/adbase.py", line 35, in f_app_lock
    return f(*args, **kw)
           ^^^^^^^^^^^^^^
  File "/config/apps/predbat.py", line 12709, in run_time_loop
    raise e
  File "/config/apps/predbat.py", line 12705, in run_time_loop
    self.update_pred(scheduled=True)
  File "/usr/lib/python3.11/site-packages/appdaemon/adbase.py", line 35, in f_app_lock
    return f(*args, **kw)
           ^^^^^^^^^^^^^^
  File "/config/apps/predbat.py", line 11716, in update_pred
    self.calculate_plan(recompute=True)
  File "/config/apps/predbat.py", line 10185, in calculate_plan
    self.optimise_all_windows(metric, metric_keep)
  File "/config/apps/predbat.py", line 9438, in optimise_all_windows
    best_soc, best_metric, best_cost, soc_min, soc_min_minute, best_keep = self.optimise_charge_limit(
                                                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/apps/predbat.py", line 8566, in optimise_charge_limit
    resultmid[try_soc] = hanres.get()
                         ^^^^^^^^^^^^
  File "/usr/lib/python3.11/multiprocessing/pool.py", line 774, in get
    raise self._value
  File "/usr/lib/python3.11/multiprocessing/pool.py", line 540, in _handle_tasks
    put(task)
  File "/usr/lib/python3.11/multiprocessing/connection.py", line 206, in send
    self._send_bytes(_ForkingPickler.dumps(obj))
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/multiprocessing/reduction.py", line 51, in dumps
    cls(buf, protocol).dump(obj)
_pickle.PicklingError: Can't pickle <function wrapped_run_prediction_charge at 0x7facffd1e8e0>: it's not the same object as predbat.wrapped_run_prediction_charge

2024-04-01 21:50:05.427329 WARNING pred_bat: ------------------------------------------------------------
2024-04-01 21:50:21.395710 WARNING pred_bat: ------------------------------------------------------------
2024-04-01 21:50:21.396214 WARNING pred_bat: Unexpected error in worker for App pred_bat:
2024-04-01 21:50:21.396689 WARNING pred_bat: Worker Ags: {'id': 'd66b5c34fb58476ea5a2f7db35e77758', 'name': 'pred_bat', 'objectid': '83f72fc20ff6452b95873841b3df9fd0', 'type': 'scheduler', 'function': <bound method PredBat.update_time_loop of <predbat.PredBat object at 0x7facfe2e97d0>>, 'pin_app': True, 'pin_thread': 0, 'kwargs': {'interval': 15, 'random_start': 0, 'random_end': 0, '__thread_id': 'thread-0'}}
2024-04-01 21:50:21.397151 WARNING pred_bat: ------------------------------------------------------------
2024-04-01 21:50:21.400168 WARNING pred_bat: Traceback (most recent call last):
  File "/usr/lib/python3.11/site-packages/appdaemon/threading.py", line 1022, in worker
    funcref(self.AD.sched.sanitize_timer_kwargs(app, args["kwargs"]))
  File "/usr/lib/python3.11/site-packages/appdaemon/adbase.py", line 35, in f_app_lock
    return f(*args, **kw)
           ^^^^^^^^^^^^^^
  File "/config/apps/predbat.py", line 12687, in update_time_loop
    raise e
  File "/config/apps/predbat.py", line 12682, in update_time_loop
    self.update_pred(scheduled=False)
  File "/usr/lib/python3.11/site-packages/appdaemon/adbase.py", line 35, in f_app_lock
    return f(*args, **kw)
           ^^^^^^^^^^^^^^
  File "/config/apps/predbat.py", line 11681, in update_pred
    self.fetch_sensor_data()
  File "/config/apps/predbat.py", line 10850, in fetch_sensor_data
    self.load_minutes, self.load_minutes_age = self.minute_data_load(self.now_utc, "load_today", self.max_days_previous, required_unit="kWh")
                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/apps/predbat.py", line 4614, in minute_data_load
    raise ValueError
ValueError

2024-04-01 21:50:21.400578 WARNING pred_bat: ------------------------------------------------------------

@nikotime
Copy link

nikotime commented Apr 6, 2024

Hey @springfall2008 , sorry me again!

I saw you did a Predbat update which included Fixes for Solax so gave it another go. The errors in my last post are now completely gone, which is great, but unfortunately the batteries are still not charging or discharging.

I do receive a warning which relates to the charge_discharge_update_button. I have tested button.solaxmodbus_sync_rtc, button.solaxmodbus_remotecontrol_trigger (which relates to Bart's post much earlier) but non seem to have any effect.

image

@Bart39 Would you be able to give it a go on your system in its present state to make sure its not just me with the issues?

My apps.yaml relates to Bart's post to here using remotecontrol_power_control.

My manual automations work but do so a little differently to that post. I instead change select.solaxmodbus_charger_use_mode to 'Manual Mode' and select.solaxmodbus_manual_mode_select to 'Force Charge' or 'Force Discharge' depending on a Read Only use of Predbat tells me what to do. Not sure if that is helpful, another option, or just simply noise!

@DougManton
Copy link

DougManton commented Apr 11, 2024

I'm seeing the same error reported regarding the button.solis_update_charge_discharge_times:

image

When I manually schedule charge/discharge, I adjust the times and then 'press' this button to save them. Unless the button is pressed within about a minute, the times revert to previous values. I guess Predbat is trying to do the same, but whatever test is used to confirm the button press is failing.

It looks like the button 'press' worked fine:

image

@DougManton
Copy link

DougManton commented Apr 12, 2024

I did some digging and noticed that

if (pytz.timezone("UTC").localize(datetime.now()) - time_pressed).seconds < 10:
resulted in a comparison between the current time in BST and the time on the button in UTC. date time.now() returns BST without a timezone, but its interpreted as UTC.

I changed it to the following and the error is gone:

        if (datetime.now(pytz.utc) - time_pressed).seconds < 10:

@nikotime
Copy link

I did some digging and noticed that

if (pytz.timezone("UTC").localize(datetime.now()) - time_pressed).seconds < 10:

resulted in a comparison between the current time in BST and the time on the button in UTC. date time.now() returns BST without a timezone, but its interpreted as UTC.
I changed it to the following and the error is gone:

        if (datetime.now(pytz.utc) - time_pressed).seconds < 10:

Amazing! Does it control your charge and discharge now following that change ?

@DougManton
Copy link

Amazing! Does it control your charge and discharge now following that change ?

It set the end discharge time and successfully presses the button to commit it, but then it sets the inverter mode to one where it doesn't apply the timed charge/discharge--so nothing happens. When I change it back to "Self-use" the discharge started, but Batpred switched it back almost immediately and the discharge stopped.

I'm taking a look at the logic that changes the switch setting. For my personal set-up, I don't think the switch needs to change -- self-use will charge or discharge based on the timers, and if the timers are blank it defaults to charging from solar and supporting the house load. So I may as well leave it on self-use.

@DougManton
Copy link

if self.inverter_type == "GS":
# Solis just has a single switch for both directions

I changed the above to force the test to fail, bypassing the code that chances the switch, I manually set the inverter control switch to "Self-Use" and it has successfully begun discharging the battery to Batpred's plan.

image

My inverter is a Solis RHI-6K-48ES-5G hybrid inverter with a stack of Pylontech US3000C batteries.

I'll take a look at a proper fix when I get back from vacation: I would like Batpred to control the switch to ensure it can correct it if an invalid manual choice was made by the user.

@heyiamluke
Copy link

I think force discharge is the only way to send the power back to the grid though? Timed discharge just lets the house draw from the battery between the set times.

I've got this working with automations to switch manual mode accordingly and back to self use. Like above. It seems to be working well.

@DougManton
Copy link

I think force discharge is the only way to send the power back to the grid though? Timed discharge just lets the house draw from the battery between the set times.

Mine is set to "Self-Use" and happily discharging to the grid whenever it falls within a configured timed discharge. But it's possible that different models behave differently :-/

There is one gotcha: it does not discharge when a timed discharge overlaps with a timed charge.

@DougManton
Copy link

DougManton commented Apr 13, 2024

There is one gotcha: it does not discharge when a timed discharge overlaps with a timed charge.

Last night’s schedule failed to work because the end time was overlapping the start time of the following window.

Discharge was scheduled to end at 00:01 and charge to start at 00:00. As a result, the inverter did neither.

As a test, I changed the discharge end-time manually to 00:00 and the inverter sprang to life.

@nikotime
Copy link

Hey @DougManton , was wondering whether you had made any more progress here ? :) would be fab to get this up and running in an official capacity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants