springfall2008 / batpred

Home battery prediction and charging automation for Home Assistant, supporting many inverter types
https://springfall2008.github.io/batpred/
95 stars 33 forks source link

Sunsynk inverter: Hold charge allows discharge #966

Closed bensebborn closed 2 months ago

bensebborn commented 2 months ago

Describe the bug

I’ve integrated our Sunsynk inverter based on the advise for “other inverters”. Charge and discharge work fine

So I’ve probably missed something in how we get the battery to hold charge?

when the plan is marked as “Hold charge” the battery discharges as normal.

Expected behavior I would expect the battery to be set to charge mode to ensure any load uses the grid, which would maintain the battery SOC

instead it seems the load is covered by the battery

our plan shows 100% at 23:00 then holding until 04:30. When I checked the SOC was at 43% at 0430

Predbat version

7.16.15

Environment details

A few lines of log show inverter is in discharge mode

-04-18 03:35:11.965088 INFO pred_bat: Not setting charging window yet as not within the window (now 04-18 03:35:00 target set_window_minutes 30 charge start time 04-18 13:00:00 2024-04-18 03:35:11.973860 INFO pred_bat: Inverter 0 Call service template charge_stop_service = {'service': 'switch.turn_on', 'entity_id': 'switch.sunsynk_inverter_use_timer'} 2024-04-18 03:35:11.985135 INFO pred_bat: Inverter 0 Call service switch/turn_on with data {'entity_id': 'switch.sunsynk_inverter_use_timer'} 2024-04-18 03:35:11.992066 INFO pred_bat: Inverter 0 current discharge rate is 9740.0 and new target is 8000 2024-04-18 03:35:14.017883 INFO pred_bat: Inverter 0 Wrote 8000 to discharge_rate, successfully now 8000 2024-04-18 03:35:14.022443 INFO pred_bat: Current SOC 53% is greater than Target SOC 0. Grid Charge disabled. 2024-04-18 03:35:14.053152 INFO pred_bat: Will recompute the plan as it is now 10.0 minutes old and will exceed the max age of 10 minutes before the next run

IMG_6011 IMG_6012

Config:

config file
# ------------------------------------------------------------------
# This is an example configuration, please modify it
# ------------------------------------------------------------------
---
pred_bat:
  module: predbat
  class: PredBat

  # Sets the prefix for all created entities in HA - only change if you want to run more than once instance
  prefix: predbat

  soc_max:
   - 28.8

  battery_rate_max:
   - 8000

  # Timezone to work in
  timezone: Europe/London

  # Currency, symbol for main currency second symbol for 1/100s e.g. $ c or £ p or e c
  currency_symbols:
   - '£'
   - 'p'

  # Number of threads to use in plan calculation
  # Can be auto for automatic, 0 for off or values 1-N for a fixed number
  threads: auto

  # XXX: This is a configuration template, delete this line once you edit your configuration

  # To disable set it to 1440
  load_filter_threshold: 30

  #
  # Sensors, more than one can be specified and they will be summed up automatically
  #
  # For two inverters the load today would normally be the master load sensor only (to cover the entire house)
  # If you have three phase and one inverter per phase then you would need three load sensors
  #
  # For pv_today if you have multiple solar inverter inputs then you should include one entry for each inverter
  #
  load_today:
    - sensor.total_house_load_today
  import_today:
    - sensor.grid_import_daily
  export_today:
    - sensor.grid_export_daily
  pv_today:
    - sensor.total_solar_output_today

  # Load forecast can be used to add to the historical load data (heat-pump)
  # To link to Predheat
  # Data must be in the format of 'last_updated' timestamp and 'energy' for incrementing kWh
  #load_forecast:
  #  - predheat.heat_energy$external
  #
  # If you enable ge_cloud_data then the load/import and export data will be fetches from the GE cloud instead of from GivTCP sensors
  # this is usually less efficient and of course prone to internet downtime, but could be useful if you lost your GivTCP data
  # Set the serial to the inverter serial to pull the data from and the key to your API key
  # When this is set load_today, import_today and export_today are not used
  #
#  ge_cloud_data: False
#  ge_cloud_serial: '{geserial}'
#  ge_cloud_key: 'xxxx'
  #
  # Controls/status - must by 1 per inverter
  #
  num_inverters: 1

  inverter_type: Sunsynk
  inverter:
    name : "Sunsynk"
    has_rest_api: False
    has_mqtt_api: False
    has_service_api: True
    output_charge_control: "power"
    has_charge_enable_time: False
    has_discharge_enable_time: False
    has_target_soc: False
    has_reserve_soc: False
    charge_time_format: "S"
    charge_time_entity_is_option: False
    soc_units: "%"
    num_load_entities: 1
    has_ge_inverter_mode: False
    time_button_press: False
    clock_time_format: "%Y-%m-%d %H:%M:%S"
    write_and_poll_sleep: 2
    has_time_window: False
    support_charge_freeze: False
    support_discharge_freeze: False

  # Services to control charging/discharging
  charge_start_service:
    service: switch.turn_off
    entity_id: "switch.sunsynk_inverter_use_timer"
  charge_stop_service:
    service: switch.turn_on
    entity_id: "switch.sunsynk_inverter_use_timer"

  discharge_start_service:
    service: select.select_option
    entity_id: "select.sunsynk_inverter_work_mode."
    option: "Selling first"

  #
  # Run balance inverters every N seconds (0=disabled) - only for multi-inverter
  balance_inverters_seconds: 0
  #
  # When set use the REST API rather than HA entity for control, should be more reliable/faster to control
  # Set one per inverter
  # If using Docker then change homeassistant.local to the Docker IP address
#  givtcp_rest:
#    - 'http://homeassistant.local:6345'
#    - 'http://homeassistant.local:6346'

  # When enabled automatic restart will restart the add-on if communication fails
  # Example below is auto-restart for GivTCP add-on itself
  #auto_restart:
  #  - shell: 'rm -rf /homeassistant/GivTCP/*.pkl'
  #  - service: hassio/addon_restart
  #    addon: a6a2857d_givtcp

  #  Example on how to restart the inverter via GivTCP
  #  - service: switch.turn_on
  #    entity_id: switch.givtcp_{geserial}_reboot_invertor

  # If not using REST then instead set the Control here (one for each inverter)
  # You should keep this section even when using REST as a fallback if it fails and for charge curve calculations
  charge_rate: sensor.max_battery_charge_rate
  discharge_rate: sensor.max_battery_discharge_rate
#    - number.givtcp2_{geserial2}_battery_discharge_rate
  battery_power:
     - number.sunsynk_inverter_battery_power
#    - sensor.givtcp2_{geserial2}_battery_power
  pv_power:
    - sensor.sunsynk_pv
    - sensor.solis_ac_output_total_power
  load_power:
    - sensor.calculated_house_load_w
#    - number.givtcp2_{geserial2}_load_power
  soc_kw:
     - sensor.sunsynk_battery_soc_kw
 #   - sensor.givtcp2_{geserial2}_soc_kwh
#  soc_max:
 #   - sensor.givtcp_{geserial}_battery_capacity_kwh
 #   - sensor.givtcp2_{geserial2}_battery_capacity_kwh
#reserve:
#    - number.givtcp_{geserial}_battery_power_reserve
#    - number.givtcp2_{geserial2}_battery_power_reserve
 # inverter_mode:
#    - select.givtcp_{geserial}_mode
#    - select.givtcp2_{geserial2}_mode
 # inverter_time:
 #   - sensor.givtcp_{geserial}_invertor_time
 #   - sensor.givtcp2_{geserial2}_invertor_time
#  charge_start_time:
 #   - select.givtcp_{geserial}_charge_start_time_slot_1
 #   - select.givtcp2_{geserial2}_charge_start_time_slot_1
 # charge_end_time:
 #   - select.givtcp_{geserial}_charge_end_time_slot_1
 #   - select.givtcp2_{geserial2}_charge_end_time_slot_1
  charge_limit:
    - number.sunsynk_inverter_capacity_point_6
 #   - number.givtcp2_{geserial2}_target_soc
 # scheduled_charge_enable:
#    - switch.givtcp_{geserial}_enable_charge_schedule
#    - switch.givtcp2_{geserial2}_enable_charge_schedule
#  scheduled_discharge_enable:
#    - switch.givtcp_{geserial}_enable_discharge_schedule
 #   - switch.givtcp2_geserial2}_enable_discharge_schedule
#  discharge_start_time:
#    - select.givtcp_{geserial}_discharge_start_time_slot_1
#select.givtcp2_{geserial2}_discharge_start_time_slot_1
#  discharge_end_time:
#    - select.givtcp_{geserial}_discharge_end_time_slot_1
  #  - select.givtcp2_{geserial2}_discharge_end_time_slot_1

  # Inverter max AC limit (one per inverter). E.g for a 3.6kw inverter set to 3600
  # If you have a second inverter for PV only please add the two values together
  inverter_limit:
    - 18000

  # Export limit is a software limit set on your inverter that prevents exporting above a given level
  # When enabled Predbat will model this limit
  #export_limit:
  # - 3600
  # - 3600

  # 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:
  #  - 200

  # Workaround to limit the maximum reserve setting, some inverters won't allow 100% to be set
  # Comment out if your inverter allows 100%
 # inverter_reserve_max : 98

  # Some batteries tail off their charge rate at high soc%
  # enter the charging curve here as a % of the max charge rate for each soc percentage.
  # the default is 1.0 (full power)
  # The example below is from GE 9.5kwh battery with latest firmware and gen1 inverter
  #
  # Predbat can compute this curve automatically if you have enough data, restart the add-on and look in the logfile for the data
  # once set here Predbat will no longer re-compute the curve.
  # Can also be set to 'auto' to just use the calculation curve, not recommended if you are using low power charging mode.
  #battery_charge_power_curve:
  #  91 : 0.91
  #  92 : 0.81
  #  93 : 0.71
  #  94 : 0.62
  #  95 : 0.52
  #  96 : 0.43
  #  97 : 0.33
  #  98 : 0.24
  #  99 : 0.24
  #  100 : 0.24
  #battery_discharge_power_curve:
  #  4 : 1.0

  # Inverter clock skew in minutes, e.g. 1 means it's 1 minute fast and -1 is 1 minute slow
  # Separate start and end options are applied to the start and end time windows, mostly as you want to start late (not early) and finish early (not late)
  # Separate discharge skew for discharge windows only
  inverter_clock_skew_start: 0
  inverter_clock_skew_end: 0
  inverter_clock_skew_discharge_start: 0
  inverter_clock_skew_discharge_end: 0

  # Clock skew adjusts the Appdaemon time
  # This is the time that Predbat takes actions like starting discharge/charging
  # Only use this for workarounds if your inverter time is correct but Predbat is somehow wrong (AppDaemon issue)
  # 1 means add 1 minute to AppDaemon time, -1 takes it away
  clock_skew: 0

  # Set these to match solcast sensor names
  # The regular expression (re:) makes the solcast bit optional
  # If these don't match find your own names in Home Assistant
  pv_forecast_today: re:(sensor.(solcast_|)(pv_forecast_|)forecast_today)
  pv_forecast_tomorrow: re:(sensor.(solcast_|)(pv_forecast_|)forecast_tomorrow)
  pv_forecast_d3: re:(sensor.(solcast_|)(pv_forecast_|)forecast_(day_3|d3))
  pv_forecast_d4: re:(sensor.(solcast_|)(pv_forecast_|)forecast_(day_4|d4))

  # car_charging_energy defines an incrementing sensor which measures the charge added to your car
  # is used for car_charging_hold feature to filter out car charging from the previous load data
  # Automatically set to detect Wallbox and Zappi, if it doesn't match manually enter your sensor name
  # Also adjust car_charging_energy_scale if it's not in kwH to fix the units
  car_charging_energy: 'sensor.myenergi_zappi_19556152_charge_added_session_2'

  # Defines the number of cars modelled by the system, set to 0 for no car
  num_cars: 1

  # car_charging_planned is set to a sensor which when positive indicates the car will charged in the upcoming low rate slots
  # This should not be needed if you use Intelligent Octopus slots which will take priority if enabled
  # The list of possible values is in car_charging_planned_response
  # Auto matches Zappi and Wallbox, or change it for your own
  # One entry per car
  car_charging_planned:
    - 'sensor.myenergi_zappi_19556152_plug_status_2'

  car_charging_planned_response:
    - 'yes'
    - 'on'
    - 'true'
    - 'connected'
    - 'ev connected'
    - 'charging'
    - 'paused'
    - 'waiting for car demand'
    - 'waiting for ev'
    - 'scheduled'
    - 'enabled'
    - 'latched'
    - 'locked'
    - 'plugged in'

  # In some cases car planning is difficult (e.g. Ohme with Intelligent doesn't report slots)
  # The car charging now can be set to a sensor to indicate the car is charging and to plan
  # for it to charge during this 30 minute slot
  #car_charging_now:
  #  - off

  # Positive responses for car_charging_now
  car_charging_now_response:
    - 'yes'
    - 'on'
    - 'true'

  # To make planned car charging more accurate, either using car_charging_planned or the Octopus Energy plugin,
  # specify your battery size in kwh, charge limit % and current car battery soc % sensors/values.
  # If you have Intelligent Octopus the battery size and limit will be extracted from the Octopus Energy plugin directly.
  # Set the car SOC% if you have it to give an accurate forecast of the cars battery levels.
  # One entry per car if you have multiple cars.
  #car_charging_battery_size:
  #  - 75
  #car_charging_limit:
  #  - 're:number.tsunami_charge_limit'
  #car_charging_soc:
  #  - 're:sensor.tsunami_battery'

  # If you have Octopus intelligent, enable the intelligent slot information to add to pricing
  # Will automatically disable if not found, or comment out to disable fully
  # When enabled it overrides the 'car_charging_planned' feature and predict the car charging based on the intelligent plan (unless octopus intelligent charging is False)
  # This matches either the intelligent slot from the Octopus Plugin or from the Intelligent plugin
#  octopus_intelligent_slot: 're:(binary_sensor.octopus_energy_intelligent_dispatching)'
 # octopus_ready_time: 're:(time.octopus_energy([0-9a-z_]+|)_intelligent_ready_time)'
#  octopus_charge_limit: 're:(number.octopus_energy([0-9a-z_]+|)_intelligent_charge_limit)'
  # Example alternative configuration for Ohme integration release >=v0.6.1
  #octopus_intelligent_slot: 'binary_sensor.ohme_slot_active'
  #octopus_ready_time: 'time.ohme_target_time'
  #octopus_charge_limit: 'number.ohme_target_percent'

  # Octopus saving session points to the saving session Sensor in the Octopus plugin, when enabled saving sessions will be at the assumed
  # Rate is read automatically from the add-in and converted to pence using the conversion rate below (default is 8)
  octopus_saving_session: 're:(binary_sensor.octopus_energy([0-9a-z_]+|)_saving_session(s|))'
  octopus_saving_session_octopoints_per_penny: 8

  # Energy rates
  # Please set one of these three, if multiple are set then Octopus is used first, second rates_import/rates_export and latest basic metric

  # Set import and export entity to point to the Octopus Energy plugin import and export sensors
  # automatically matches your meter number assuming you have only one (no need to edit the below)
  # Will be ignored if you don't have the sensor but will error if you do have one and it's incorrect
  # NOTE: To get detailed energy rates you need to go in and manually enable the following events in HA
  #       event.octopus_energy_electricity_xxxxxxxx_previous_day_rates
  #       event.octopus_energy_electricity_xxxxxxxx_current_day_rates
  #       event.octopus_energy_electricity_xxxxxxxx_next_day_rates
  # and if you have export enable:
  #       event.octopus_energy_electricity_xxxxxxxx_export_previous_day_rates
  #       event.octopus_energy_electricity_xxxxxxxx_export_current_day_rates
  #       event.octopus_energy_electricity_xxxxxxxx_export_next_day_rates
  # Predbat will automatically find the event. entities from the link below to the sensors
  metric_octopus_import: 'sensor.octopus_energy_electricity_23e1048870_1610013470677_current_rate'
  metric_octopus_export: 'sensor.octopus_energy_electricity_23e1048870_1650000177535_export_current_rate'

  # Standing charge in pounds, can be set to a sensor or manually entered (e.g. 0.50 is 50p)
  # The default below will pick up the standing charge from the Octopus Plugin
  # The standing charge only impacts the cost graphs and doesn't change the way Predbat plans
  # If you don't want to show the standing charge then just delete this line or set to zero
  metric_standing_charge: 'sensor.octopus_energy_electricity_current_standing_charge'

  # Or set your actual rates across time for import and export
  # If start/end is missing it's assumed to be a fixed rate
  # Gaps are filled with zero rate
  #rates_import:
  #  -  start: "00:30:00"
  #     end: "04:30:00"
  #     rate: 7.5
  #  -  start: "04:30:00"
  #     end: "00:30:00"
  #     rate: 40.0
  #
  #rates_export:
  #  -  rate: 4.2

  # Can be used instead of the plugin to get import rates directly online
  # Overrides metric_octopus_import and rates_import
  # rates_import_octopus_url : "https://api.octopus.energy/v1/products/FLUX-IMPORT-23-02-14/electricity-tariffs/E-1R-FLUX-IMPORT-23-02-14-A/standard-unit-rates"
  # rates_import_octopus_url : "https://api.octopus.energy/v1/products/AGILE-FLEX-BB-23-02-08/electricity-tariffs/E-1R-AGILE-FLEX-BB-23-02-08-A/standard-unit-rates"

  # Overrides metric_octopus_export and rates_export
  # rates_export_octopus_url: "https://api.octopus.energy/v1/products/FLUX-EXPORT-BB-23-02-14/electricity-tariffs/E-1R-FLUX-EXPORT-BB-23-02-14-A/standard-unit-rates"
  # rates_export_octopus_url: "https://api.octopus.energy/v1/products/AGILE-OUTGOING-BB-23-02-28/electricity-tariffs/E-1R-AGILE-OUTGOING-BB-23-02-28-A/standard-unit-rates/"
  # rates_export_octopus_url: "https://api.octopus.energy/v1/products/OUTGOING-FIX-12M-BB-23-02-09/electricity-tariffs/E-1R-OUTGOING-FIX-12M-BB-23-02-09-A/standard-unit-rates/"

  # Import rates can be overridden with rate_import_override
  # Export rates can be overridden with rate_export_override
  # Use the same format as above, but a date can be included if it just applies for a set day (e.g. Octopus power ups)
  # This will override even the Octopus plugin rates if enabled
  #
  #rates_import_override:
  # -  date: '2023-09-10'
  #    start: '14:00:00'
  #    end: '14:30:00'
  #    rate: 112
  #    load_scaling: 0.8

  # For pv estimate, leave blank for central estimate, or add 10 for 10% curve (worst case) or 90 or 90% curve (best case)
  # If you use 10 then disable pv_metric10_weight below
  # pv_estimate: 10

  # Days previous is the number of days back to find historical load data
  # Recommended is 7 to capture day of the week but 1 can also be used
  # if you have more history you could use 7 and 14 (in a list) but the standard data in HA only lasts 10 days
  days_previous:
    - 7
    - 14
    - 21

  # Days previous weight can be used to control the weighting of the previous load points, the values are multiplied by their
  # weights and then divided through by the total weight. E.g. if you used 1 and 0.5 then the first value would have 2/3rd of the weight and the second 1/3rd
  # Include one value for each days_previous value, each weighting on a separate line.
  # If any days_previous's that are not given a weighting they will assume a default weighting of 1.
  days_previous_weight:
    - 1

  # Number of hours forward to forecast, best left as-is unless you have specific reason
  forecast_hours: 48

  # Specify the devices that notifies are sent to, the default is 'notify' which goes to all
  #notify_devices:
  #  - mobile_app_treforsiphone12_2

  # Battery scaling makes the battery smaller (e.g. 0.9) or bigger than its reported
  # If you have an 80% DoD battery that falsely reports it's kwh then set it to 0.8 to report the real figures
  # One per inverter
  battery_scaling:
    - 1.0

  # Can be used to scale import and export data, used for workarounds
  import_export_scaling: 1.0

  # Export triggers:
  # For each trigger give a name, the minutes of export needed and the energy required in that time
  # Multiple triggers can be set at once so in total you could use too much energy if all run
  # Creates an entity called 'binary_sensor.predbat_export_trigger_<name>' which will be turned On when the condition is valid
  # connect this to your automation to start whatever you want to trigger
  export_triggers:
     - name: 'large'
       minutes: 60
       energy: 1.0
     - name: 'small'
       minutes: 15
       energy: 0.25

  # If you have a sensor that gives the energy consumed by your solar diverter then add it here
  # this will make the predictions more accurate. It should be an incrementing sensor, it can reset at midnight or not
  # It's assumed to be in Kwh but scaling can be applied if need be
  #iboost_energy_today: 'sensor.xxxxx'
  #iboost_energy_scaling: 1.0
  # Gas rates for comparison
  #metric_octopus_gas: 're:(sensor.(octopus_energy_|)gas_[0-9a-z]+_[0-9a-z]+_current_rate)'

  # Nordpool market energy rates
  futurerate_url: 'https://www.nordpoolgroup.com/api/marketdata/page/325?currency=GBP'
  futurerate_adjust_import: True
  futurerate_adjust_export: False
  futurerate_peak_start: "16:00:00"
  futurerate_peak_end: "19:00:00"
  futurerate_peak_premium_import: 14
  futurerate_peak_premium_export: 6.5

  # Watch list, a list of sensors to watch for changes and then update the plan if they change
  # This is useful for things like the Octopus Intelligent Slot sensor so that the plan update as soon as you plugin in
  # Only uncomment the items you actually have set up above in apps.yaml, of course you can add your own as well
  # Note those using +[] are lists that are appended to this list, whereas {} items are single items only
  #watch_list:
  #  - '{octopus_intelligent_slot}'
  #  - '{octopus_ready_time}'
  #  - '{octopus_charge_limit}'
  #  - '{octopus_saving_session}'
  #  - '+[car_charging_planned]'
  #  - '+[car_charging_soc]'
  #  - '{car_charging_now}'
bensebborn commented 2 months ago

Here’s sensors showing charge mode and battery SOC

IMG_6017 IMG_6018

bensebborn commented 2 months ago

But more info…

This is currently integrated using the basic method suggested for other inverters

So just has commands for charge/discharge

to do that on Sunsynk I am turning the timer on/off. When off this forces the battery to stay at 100% so this is the charge command.

When timer is on, it allows discharge down to min SOC

alternatively we could leave the timer on and set the SOC and “grid charge” mode. When grid mode is on it will charge to the target SOC. when grid mode is off, it will discharge to the target SOC.

Maybe that would work better?

bensebborn commented 2 months ago

Update: I have tried incorporating the SOC setting.

Because this is only one field, it’s not working correctly. When I set force charge, I can see the SOC target is set to 100% but then as it’s the same field it then gets set to the reserve Soc and overwritten so doesn’t charge

I did try to disable the “has reserve soc@ which allowed it to charge, but then I discharge the SOC remained on 100% so didn’t discharge.

Is there a way of only setting the SOC to target on charge, and reserve on discharge?

springfall2008 commented 2 months ago

So you want the target SOC to be set to the discharge target during export?

bensebborn commented 2 months ago

So:

during charge, send only the 'soc_max' (as on Sunsynk, the 'soc' field acts as an upper limit during charge) during discharge, send only the 'reserve' (as on Sunsynk, the 'soc' field acts as an lower limit during discharge)

I think those are the correct fields.

Currently it seems to send to both 'soc_max' and then 'reserve', so one figure overwrites the other as they both hit the same target sensor.

springfall2008 commented 2 months ago

I'm not sure I understand, during discharge the discharge service should be called with the discharge target SOC (e.g. reserve).

Are you finding the charge service is called during discharge also?

bensebborn commented 2 months ago

What I observed, is the 'SOC' on the inverter was initially set to '100' for example (charge soc target) then set to 0 very quickly

Config was:

reserve:
     - number.sunsynk_inverter_capacity_point_6
charge_limit:
     - number.sunsynk_inverter_capacity_point_6
 So it seems it was setting 'charge_limit' to 100 then setting 'reserve' to 0.

 However, because these both point to the same sensor on Sunsynk, they were overwriting each other, leaving the inverter soc at 0%.

 If that's not expected behaviour i can set it back to that config and send over the logs
bensebborn commented 2 months ago

Here you go:

2024-04-18 21:46:55.088160 INFO pred_bat: Inverter 0 Current charge limit is 15 % and new target is 100 %
2024-04-18 21:46:59.095197 INFO pred_bat: Inverter 0 Wrote 100 to charge_limit, successfully now 100
2024-04-18 21:46:59.098203 INFO pred_bat: Inverter 0 Current Reserve is 100.0 % and new target is 12.0 %
2024-04-18 21:47:03.105737 INFO pred_bat: Inverter 0 Wrote 12.0 to reserve, successfully now 12
2024-04-18 21:49:24.410232 INFO pred_bat: Inverter 0 Wrote 49 to charge_limit, successfully now 49
2024-04-18 21:49:30.432829 INFO pred_bat: Inverter 0 Wrote 12.0 to reserve, successfully now 12

And observed the same on the 'number.sunsynk_inverter_capacity_point_6' sensor.

Initial: 15 Then: 100% Then: 12% Then: 49% Then: 12%

This is due to both the 'reserve' and the 'current_limit' pointing to the same sensor, and both being set during charging.

We only have one SOC sensor on the inverter, so need just the 'charge_limit' to be set during charge, and 'reserve' to just be set during discharge

eg:

Charge: Set number.sunsynk_inverter_capacity_point_6 = 49%
Discharge: Set number.sunsynk_inverter_capacity_point_6 = 12%

Hope that helps

springfall2008 commented 2 months ago

Reserve is the minimum battery level before it shuts off, but charge_limit is the AC charge limit before stopping charging.

I can probably have an option to make sure it does as you suggest, let me have a look

bensebborn commented 2 months ago

Thank you. It would make things much better on a Sunsynk/Deye inverter.

bensebborn commented 2 months ago

In the meantime, is there any way to stop the battery from discharging during 'HoldCharge. SOC: 100%'?

It seems to just discarge during this period. I'm presuming due to the 'reserve' not being set due the above. Any workaround?

springfall2008 commented 2 months ago

I've created a new branch now with some of this rolled back into the code:

  1. I added inverter type SK to predbat.py
    • Enabled target SOC
  2. I change the code so if you have a target SOC but no reserve then it changes the target soc % to the reserve during a discharge.
  3. I added a sunsynk.yaml template onto the branch, its like yours but more generic now and using the settings built into Predbat.

Please copy predbat.py from: https://github.com/springfall2008/batpred/blob/sunsynk/apps/predbat/predbat.py and also look at my template https://github.com/springfall2008/batpred/blob/sunsynk/templates/sunsynk.yaml

One issue I notice is that 'charge_rate' and 'discharge_rate' are sensors and can't be modified, they are supposed to be number's which can be changed so Predbat can cut the discharge rate to 0 during a charge for example.

bensebborn commented 2 months ago

Thanks for this. Will give that a go and report back

With regards the charge / discharge rate, the inverter only gives us access to Max Charge/Discharge Current (Amps) We can’t set this as Watts. .

So I created a sensor which returned power by (current x voltage)

So it’s accurate in terms of the figure returned but you’re right, it can’t them be modified?

edit: Have found a “max power” editable figure ( not current power) but it’s one figure that controls both charge and discharge depending upon what it’s doing. Would that work?

bensebborn commented 2 months ago

Scrap that “max power” comment. It’s on my inverter app but isn’t appearing in HA via MQTT for some reason. So I only have “max charge current” and “max discharge current” I think.

springfall2008 commented 2 months ago

Scrap that “max power” comment. It’s on my inverter app but isn’t appearing in HA via MQTT for some reason. So I only have “max charge current” and “max discharge current” I think.

I think we can change the controls to current, if you change in the inverter settings as follows:

    "output_charge_control": "current",

Then in apps.yaml remove the charge/discharge power settings and instead add voltage and charge/discharge current e.g. from the Solis template:

timed_charge_current:

This should do the trick

bensebborn commented 2 months ago

Ok will Gcsss this a proper go over right to check charge rates etc

I’ve done a quick test:

force charge: Set SOC to 88% which was same as “Limit %” shown on plan so looks good

force discharge: Set SOC to 80% which matched the likit % so this allowed discharge correctly

force idle: SOC remained and wasn’t set. So here it was 80% which prevented the battery draining. Presume this needs to be reset down to 0% or reserve %

So just the idle to sort I believe.

Ben

Meatballs1 commented 2 months ago

I was just having a go at setting this up and then saw this.... The way I control the inverter (AC Coupled with separate SolarEdge PV) is:

Where battery is set to 0, it needs reverting back to the previous limit afterwards (or setting to the right level with each mode)

All timeslots set to 20% (or min DoD)

I don't think I have enough history for some of my template load settings yet to really check the data yet.

I'm not sure if the battery Low batterysetting could be used to set a reserve (I dont think its currently exposed in the esphome version I have but I'm sure could digout the modbus register)

jacekowski commented 2 months ago

It would be really good if we could get some sort of "simple" entitiy with current command (start/end times are not really necessary) and any additional parameters (minimum/maximum soc). that way it would be a lot simpler to write some sort of interface using HA automations or node-red to convert that to inverter commands rather than predbat trying to be clever

bensebborn commented 2 months ago

I was just having a go at setting this up and then saw this.... The way I control the inverter (AC Coupled with separate SolarEdge PV) is:

  • Idle - Timer On, Work Mode: Limited to Home
  • Charging - Timer Off
  • Freeze Charging - Battery max discharge current: 0
  • Hold Charging - As above I guess?
  • No Charge - Battery max charge current: 0 Battery max grid charge current: 0 (If I hit my min level, my battery BMS requests a force charge and the inverter will ignore battery max charge current and start grid charging if this isn't set).
  • Discharging - Timer On, Work Mode: Selling First
  • Freeze Discharging - Battery max charge current: 0

Where battery is set to 0, it needs reverting back to the previous limit afterwards (or setting to the right level with each mode)

All timeslots set to 20% (or min DoD)

I don't think I have enough history for some of my template load settings yet to really check the data yet.

I'm not sure if the battery Low batterysetting could be used to set a reserve (I dont think its currently exposed in the esphome version I have but I'm sure could digout the modbus register)

I’m moving away from that setup for Charging as it doesn’t take into account SOC

now that’s fixed my plan is to set all the timers the same except slot 6 so I that will cover all day

Then when I want to charge, tick Grid Charge Slot 6 SOC is then set to target SOC

this seems to be working well the only minor issue is that SunSynk only lets you change the time slots in 30 mins so my slot 6 starts at 00:30

IMG_6033

So now:

Charge: Set Grid Charge on, set SOC Discharge: Set grid charge off, Set SOC. Set selling first mode

Idle: Set grid charge off, Set SOC. Set load first mode

I’ll be testing that today to see if the charge adjustments work too.

I haven’t yet tried freeze charge etc.

bensebborn commented 2 months ago

This is working well. HoldCharge is working as the SOC is correctly set to 100%

Only thing I’ve had to do is reset SOC to 12% when cancelling charge/discharge (ie going to idle). Have done this via the automation for now but probably should be in the code.

springfall2008 commented 2 months ago

This is working well. HoldCharge is working as the SOC is correctly set to 100%

Only thing I’ve had to do is reset SOC to 12% when cancelling charge/discharge (ie going to idle). Have done this via the automation for now but probably should be in the code.

Why the reset, what goes wrong if you leave it as-is?

bensebborn commented 2 months ago

Because that SOC field works as a target during charge and a limit during discharge.

So when we’re not charging (so idle or discharging) the inverter will only discharge if the battery current SOC is above the SOC field.

So currently if it was charging it might be set high. Then it goes idle and because the battery is then above that figure, it won’t allow any discharge.

So golden rule in this inverter:

set the SOC field to target or 100% when charging (✅)

Set the SOC field to dischsrge limit or reserve when discharging (✅ when limit it set. ❓ Haven’t tested if force discharge without limit)

Set the SOC field to reserve when idle (❌)

Meatballs1 commented 2 months ago

I'm normally a fan of setting device schedules in automations as they are resilient to outages, but the SunSynk schedule is clunky. Having a 23.5 hour time slot seems a bit of a pain too as one half hour is going to be broken?

Predbat/HA knows the SoC, so can we not just signal a change of mode when the target/reserve SoC is reached? Would this be a problem if Predbat is only checking every 5 minutes?

I confess I need to get my head around a bit more of how predbat controls things.

Meatballs1 commented 2 months ago

With the output_charge_control set to current, there is no charge_rate to supply so it uses the default of 2600W:

2024-04-20 11:00:48.838506 INFO pred_bat: Found 1 inverters totals: min reserve 3.28 current reserve 0.66 soc_max 16.4 soc 14.6 charge rate 2.6 kW discharge rate 2.6 kW battery_rate_min 0.0 w ac limit 11.0 export limit 11.0 kW loss charge 3 % loss discharge 3 % inverter loss 4 %

https://github.com/springfall2008/batpred/blob/6885144b156bfd0291a7f4420e57a79e9fcdbd79/apps/predbat/predbat.py#L2192

Do we need to set Invertor_Max_Bat_Rate or Invertor_Max_Rate?

bensebborn commented 2 months ago

I'm normally a fan of setting device schedules in automations as they are resilient to outages, but the SunSynk schedule is clunky. Having a 23.5 hour time slot seems a bit of a pain too as one half hour is going to be broken?

Predbat/HA knows the SoC, so can we not just signal a change of mode when the target/reserve SoC is reached? Would this be a problem if Predbat is only checking every 5 minutes?

I confess I need to get my head around a bit more of how predbat controls things.

I guess that would work. However as I have a 10k inverter a lot can change in 5/10 mins! Potentially could go 1.6kW over/under

my plan was to use an automation to apply the SOC to the other slots. A bit clunky but would keep them all the same then the other 30 min slot would be correct. Would never change the times btw, just using it as a way of controlling SOC.

jacekowski commented 2 months ago

I'm using node red as interface between predbat and sunsynk. I'm not adusting times at all, just adjusting work mode and settings for current slot as needed (while also doing some other house keeping on the inverter - such as forcing discharge early (i have 10kW of panels on 5kW inverter, so if i avoid hitting 100% i can export 5kW and anything above that charges the battery)) i found it easier than messing with schedule settings.

springfall2008 commented 2 months ago

With the output_charge_control set to current, there is no charge_rate to supply so it uses the default of 2600W:

2024-04-20 11:00:48.838506 INFO pred_bat: Found 1 inverters totals: min reserve 3.28 current reserve 0.66 soc_max 16.4 soc 14.6 charge rate 2.6 kW discharge rate 2.6 kW battery_rate_min 0.0 w ac limit 11.0 export limit 11.0 kW loss charge 3 % loss discharge 3 % inverter loss 4 %

https://github.com/springfall2008/batpred/blob/6885144b156bfd0291a7f4420e57a79e9fcdbd79/apps/predbat/predbat.py#L2192

Do we need to set Invertor_Max_Bat_Rate or Invertor_Max_Rate?

You need to set 'battery_rate_max' in the apps.yaml

springfall2008 commented 2 months ago

Assuming has change enable time is still false this may fix your target soc % issue when not charging:

https://github.com/springfall2008/batpred/blob/sunsynk/apps/predbat/predbat.py

bensebborn commented 2 months ago

So this is working, but it's setting my soc back down to 4% on idle, which is too low.

I'm not sure where this 4% is coming from?

I can see in logs:

2024-04-21 12:56:00.752788 INFO pred_bat: Inverter 0 with soc_max 28.8 kWh nominal_capacity 28.8 kWh battery rate raw 9300.0 w charge rate 9.3 kW discharge rate 9.3 kW battery_rate_min 0.0 w ac limit 18.0 kW export limit 18.0 kW reserve 4.0 % current_reserve 4.0 %

Could you let me know what I need to change the 4% to 15% please?

(This is also probably the reason for #985 )

Meatballs1 commented 2 months ago

input_number.predbat_set_reserve_min

bensebborn commented 2 months ago

That was already set to 13% but didn't change anything

However, I've found the following which wasn't documented (from what I could see) but was in the templates:

  battery_min_soc: 
   - 14

This has done the trick 👍

bensebborn commented 2 months ago

Hmmm... so now my plan has updated and looks strange.

The min SOC is indeed 14% which is better.

However it just seems to have drained the battery with no plan to charge before the peak time..?

As you can see here, there's quite a few slots this afternoon around 13-15p

Then at peak time it goes up to 18-25p

Should it not be scheduling a charge at these lower rates to keep enough battery to cover teh peak slots?

IMG_6063

Full plan here:

Predbat – Home Assistant - Plan.pdf

I have Best SOC Keep 3.4 KWh (about 12% of total battery capacity) Reserve Min: 14% Best SOC Min/Max: 0

Sorry probably my configuration being wrong, any help appreciated! Plan attached as PDF

Meatballs1 commented 2 months ago

Still getting to grips with it too, but have you set the Rate Low Threshold?

Mine is just at 0 on agile.

bensebborn commented 2 months ago

Rate Low Threshold is 0p

springfall2008 commented 2 months ago

Do you have control charge enabed in the mode?

bensebborn commented 2 months ago

Do you have control charge enabed in the mode?

It’s set to Control Charge and Discharge

it’s currently doing a force discharge so it definitely has control

bensebborn commented 2 months ago

Not sure if related but checked the status column and seeing

“ Warn - Inverter 0 write to charge_limit failed”

I think this is since changing to current control instead of power

might not be related though.

bensebborn commented 2 months ago

Hey @springfall2008

The above issue hasn't happened again, so hard to recreate now. Will let you know if it happens again.

Could we get the changes on this Sunsynk branch merged into main so we can take advantage of any new releases?

Thanks for your work on this

Meatballs1 commented 2 months ago

@bensebborn could you show example of your final config? I think issues with charge_limit due to 1dp as mine fails to write if its not an integer? Ah My reserve was set to 4.1% which I think was mainly triggering it.

springfall2008 commented 2 months ago

Hey @springfall2008

The above issue hasn't happened again, so hard to recreate now. Will let you know if it happens again.

Could we get the changes on this Sunsynk branch merged into main so we can take advantage of any new releases?

Thanks for your work on this

This was merged onto MAIN and released

Can you help me with the documentation on Sunsynk by sharing the steps to create a working install?