springfall2008 / batpred

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

Solis inverter via Solis Cloud - getting 'NoneType' object has no attribute 'split' #1375

Open chris-y opened 3 weeks ago

chris-y commented 3 weeks ago

Describe the bug I'm trying to set up predbat for my Solis inverter but using Solis Cloud rather than modbus. Monitoring is working great, but I'm not able to do any control. If I test any control service nothing happens, and I'm seeing 'NoneType' object has no attribute 'split' in the log and status.

I have set read-only to off and set a forced charge, then waited for the start of the forced charge to see if the charge_start_service triggers - it doesn't - and the only thing which looks relevant in the log is this NoneType error.

Expected behavior I expect my service to be called.

Predbat version

1.1.8

Environment details

Screenshots image image

Log file

    self.set_current_from_power(direction, 0)
  File "/config/inverter.py", line 1789, in set_current_from_power
    self.write_and_poll_value(f"timed_{direction}_current", self.base.get_arg(f"timed_{direction}_current", indirect=False, index=self.id), new_current, fuzzy=1)
  File "/config/inverter.py", line 1233, in write_and_poll_value
    domain, entity_name = entity_id.split(".")
AttributeError: 'NoneType' object has no attribute 'split'

Config

The charge_start_service stuff is what I was trying out. The first one runs a script which has 'power' as an input and just notifies me. This never triggers. The second runs the pyscript which controls the inverter, but I'll probably set this up as a script which takes the parameters to get the config out of here. For now though I was just trying to get it to trigger anything.

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

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

  # If you are using Predbat outside of HA then set the HA URL and Key (long lived access token here)
  #ha_url: 'http://homeassistant.local:8123'
  #ha_key: 'xxx'

  # Timezone to work in
  timezone: Europe/London

  #
  # Sensors, currently more than one can be specified and they will be summed up automatically
  # however if you have two inverters only set one of them as they will both read the same.
  #

  inverter_type: MINE
  inverter:
    name: "Solis Inverter"
    has_rest_api: False
    has_mqtt_api: False
    has_service_api: True
    output_charge_control: "current"
    current_dp: 0
    has_charge_enable_time: False
    has_discharge_enable_time: False
    has_target_soc: False
    has_reserve_soc: False
    charge_time_format: "HH:MM"
    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
    can_span_midnight: False
    charge_control_immediate: True

    charge_start_service:
      - service: script.test_script
        power: {power}

      - service: pyscript.solis_control
        data:
          days:
            - chargeCurrent: "{power}"
              dischargeCurrent: "0"
              chargeStartTime: "{charge_start_time}"
              chargeEndTime: "{charge_end_time}"
              dischargeStartTime: "00:00"
              dischargeEndTime: "00:00"
            - chargeCurrent: "{power}"
              dischargeCurrent: "0"
              chargeStartTime: "00:00"
              chargeEndTime: "00:00"
              dischargeStartTime: "00:00"
              dischargeEndTime: "00:00"
            - chargeCurrent: "{power}"
              dischargeCurrent: "0"
              chargeStartTime: "00:00"
              chargeEndTime: "00:00"
              dischargeStartTime: "00:00"
              dischargeEndTime: "00:00"
          config:
            secret: xxxx
            key_id: xxxx
            username: xxxx
            password: xxxx
            plantId: xxxx

  #solax_modbus_new: True   # Set to True if you have integration version 2024.03.2 or beyond

  num_inverters: 1
  #
  # Controls/status - must by 1 per inverter
  #

  # Max inverter power from battery
  battery_rate_max:
    - 3600
  # Battery capacity in kWh
  soc_max:
    - 9.6

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

  load_today:
    - sensor.solis_daily_grid_energy_used
  import_today:
    - sensor.solis_daily_grid_energy_purchased
  export_today:
    - sensor.solis_daily_on_grid_energy
  pv_today:
    - sensor.solis_energy_today

  battery_voltage:
    - sensor.solis_battery_voltage

  # This is disabled by default in the Solax integration so it must be manually enabled.
  #inverter_time:
  #  - sensor.solis_rtc

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

  # For Solis inverters we need to add the bypass (backup) load to the main house load. If not used the load_power_1 can be commented out
  load_power:
    - sensor.solis_plant_total_consumption_power
  #load_power_1:
  #  - sensor.solis_backup_load_power

  soc_percent:
    - sensor.solis_remaining_battery_capacity

  reserve:
    - sensor.solis_force_discharge_soc

  battery_min_soc:
    - sensor.solis_force_discharge_soc

  # Inverter max AC limit (one per inverter)
  # If you have a second inverter for PV only please add the two values together
  inverter_limit: 3600

  # 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
  #
  # The maximum rate the inverter can charge and discharge the battery can be overwritten, this will change
  # the register programming and thus cap the max rates. The default is to use the maximum supported rates (recommended)
  #
  inverter_limit_charge:
    - 3500
  inverter_limit_discharge:
    - 3500

  # Set these to match solcast sensor names if not using the cloud interface
  # 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: 're:(sensor.myenergi_zappi_[0-9a-z]+_charge_added_session|sensor.wallbox_portal_added_energy)'

  num_cars: 1
  car_charging_now: binary_sensor.xxnnxxx_charging

   # To make planned car charging more accurate, either using car_charging_planned or Octopus Intelligent
  # specify your battery size in kwh, charge limit % and current car battery soc % sensors/values
  # If you have intelligent the battery size and limit will be extracted from Intelligent 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:
    - 52
  # car_charging_limit:
  #   - 're:number.tsunami_charge_limit'
  car_charging_soc:
    - sensor.xxnnxxx_battery

  # 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
  # automatically matches your meter number assuming you have only one
  # Will be ignored if you don't have the sensor
  # Or manually set it to the correct sensor names e.g:
  # sensor.octopus_energy_electricity_xxxxxxxxxx_xxxxxxxxxxxxx_current_rate
  # sensor.octopus_energy_electricity_xxxxxxxxxx_xxxxxxxxxxxxx_export_current_rate
  metric_octopus_import: 're:(sensor.(octopus_energy_|)electricity_[0-9a-z]+_[0-9a-z]+_current_rate)'
  metric_octopus_export: 're:(sensor.(octopus_energy_|)electricity_[0-9a-z]+_[0-9a-z]+_export_current_rate)'

  # Standing charge can be set to a sensor (e.g. Octopus) or manually entered in pounds here (e.g. 0.50 is 50p)
  metric_standing_charge: 're:(sensor.(octopus_energy_|)electricity_[0-9a-z]+_[0-9a-z]+_current_standing_charge)'

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

  # Carbon Intensity data from National grid
  carbon_intensity: 're:(sensor.carbon_intensity_uk)'

  # 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

  # 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}'

  # 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

  # 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
  days_previous_weight:
    - 1

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

  # The number of hours ahead to count in charge planning (for cost estimates)
  # It's best to set this on your charge window repeat cycle (24) but you may want to set it higher for more variable
  # tariffs like Agile
  forecast_plan_hours: 24

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

  # Set the frequency in minutes that this plugin is run
  # recommend something that divides by 60 (5, 10 or 15) or you won't trigger at the start of energy price slots
  run_every: 5

  # 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
  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
springfall2008 commented 3 weeks ago

You appear to be missing settings for charge/discharge current as below:

timed_charge_current:

chris-y commented 3 weeks ago

Is that literally what I need? Or do I need a helper or value or something to plug into it?

(Edited, see below)

chris-y commented 3 weeks ago

OK, I worked that out - I needed a helper created, and this then pokes the value into that. Discharge always seems to be 0, even when I set a forced discharge, is this correct?

I also worked out why my service wasn't called - I'd set it at the wrong level.

Question: Is the {power} always in watts? Is there a way of getting this in amps? Do I just use the current helper I specified in timed_charge_current?

springfall2008 commented 3 weeks ago

These are in AMPS (current) rather than watts. The timed_discharge_current should not be zero during discharge.

chris-y commented 3 weeks ago

OK, cool. My discharge current isn't changing from 0, even when I did a test forced discharge.

Screenshot_20240822-192654~2.png

Other than that I think I've got everything working.

chris-y commented 3 weeks ago

I tried a live test last night, it was supposed to charge the battery a little but when I woke up it had charged to 100%. It then had planned a discharge but the discharge start/end time hadn't been set. I fixed that by setting charge_discharge_with_rate: False.

So I think the only outstanding issue is that neither the charge/discharge rate in Watts or Amps is changing. image image

The charge rate is a bit weird as it looks like it did change overnight yesterday, but not last night: image

Current plan: (we're currently discharging but the rate on the amps sensor is still 0) image

chris-y commented 3 weeks ago

Further update. The charging current is now updating - not sure what I changed to kick it into action! Discharge current is still stuck on 0.

However, it looks like the charge_start_service etc aren't called after the rate changes, so the rate sent to the inverter is prior to the change. I observed this earlier when it was in charge mode, and now it's gone to hold but hasn't updated with 0A:

Plan is on HOLD: image

Charge rate has dropped to 0A: image

The last call of the service has happened before the drop: (this screenshot taken after the two above) image

Also I notice there's a 1 minute overlap on the discharge stop and charge start times.

It updated about five minutes later but seems a bit of a lag?

After this hold session ended, it updated for the overnight charge: image

The charge rate is still 0A even though it expects to charge a bit: image

Later... OK, it set the correct charge rate a few seconds after the charge period started. It would be better if it set this ahead of time. It seems to call the service very often even if there are no changes - tweaking the current at this point would make sense (in case we lose connection, it's all planned to the most recent prediction before the connection was lost)

chris-y commented 2 weeks ago

OK, as far as I'm concerned this is working bar a niggle with the charge and discharge currents - which I'll raise as a separate issue.

My config is as follows:

script.set_solis_inverter_config_predbat is:

alias: Set Solis Inverter Config (Predbat)
sequence:
  - metadata: {}
    data:
      days:
        - chargeCurrent: "  0{{ states('input_number.solis_battery_charge_rate_predbat') | int | string }} "
          dischargeCurrent: "80"
          chargeStartTime: >-
            {{ states('sensor.predbat_mine_0_charge_start_time')[0:5] | string
            }}
          chargeEndTime: "{{ states('sensor.predbat_mine_0_charge_end_time')[0:5] | string }}"
          dischargeStartTime: >-
            {{ states('sensor.predbat_mine_0_discharge_start_time')[0:5] |
            string }}
          dischargeEndTime: >-
            {{ states('sensor.predbat_mine_0_discharge_end_time')[0:5] | string
            }}
        - chargeCurrent: " 0{{ states('input_number.solis_battery_charge_rate_predbat') | int | string }} "
          dischargeCurrent: "80"
          chargeStartTime: "00:00"
          chargeEndTime: "00:00"
          dischargeStartTime: "00:00"
          dischargeEndTime: "00:00"
        - chargeCurrent: " 0{{ states('input_number.solis_battery_charge_rate_predbat') | int | string }} "
          dischargeCurrent: "80"
          chargeStartTime: "00:00"
          chargeEndTime: "00:00"
          dischargeStartTime: "00:00"
          dischargeEndTime: "00:00"
      config:
        secret: xxxx
        key_id: xxxx
        username: xxxx
        password: xxxx
        plantId: xxxx
    action: pyscript.solis_control
fields: {}
mode: single
icon: mdi:home-battery
description: ""

apps.yaml.txt