From 487083315ec7393bc8d89553aaa352c0e0f76a9c Mon Sep 17 00:00:00 2001 From: Geoffrey Coan <142018870+gcoan@users.noreply.github.com> Date: Sat, 16 May 2026 10:58:51 +0000 Subject: [PATCH 1/9] Minor documentation tweaks --- README.md | 2 +- docs/apps-yaml.md | 19 +++++++++++++------ docs/compare.md | 10 +++++----- docs/components.md | 14 +++++++------- docs/configuration-guide.md | 2 +- docs/customisation.md | 2 +- docs/energy-rates.md | 25 +++++++++++++------------ docs/faq.md | 8 ++++---- docs/index.md | 2 +- docs/install.md | 12 ++++++------ docs/installation-summary.md | 4 ++-- docs/inverter-setup.md | 4 ++-- docs/output-data.md | 2 +- 13 files changed, 57 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index 53d5f40e9..64a0e1c03 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ If you want to buy me a beer then please use [Paypal](https://paypal.me/predbat? * Use my referral code for Axle Energy (UK): If you are finding Home Assistant and Predbat too difficult to set up yourself there is now [PredBat Cloud](https://predbat.com/) which is a paid for version of Predbat hosted in the cloud. -Please note that while I have given permission for PredBat Cloud to operate this is not my company, PredBat will remain open source for everyone personal use. +Please note that while I have given permission for PredBat Cloud to operate, this is not my company and PredBat will remain open source for everyone's personal use. ## Predbat documentation diff --git a/docs/apps-yaml.md b/docs/apps-yaml.md index 26b48fa79..259ffbc82 100644 --- a/docs/apps-yaml.md +++ b/docs/apps-yaml.md @@ -1332,9 +1332,16 @@ Called when a charge/discharge is cancelled and the inverter goes back to home d topic: **topic**/set/auto payload: true -## Solcast Solar Forecast +## Solar Forecast -As described in the [Predbat installation instructions](install.md#solcast-install), Predbat needs a solar forecast +As described in the [Predbat installation instructions](install.md#solar-forecast-install), Predbat needs a solar forecast +in order to predict solar generation and battery charging. + +The Solar forecast configuration in `apps.yaml` should be configured for either for the [Solcast integration](#solcast-solar-forecast), [Forecast.solar](#forecastsolar-solar-forecast) or [Open-Meteo](#open-meteo-solar-forecast). + +### Solcast Solar Forecast + +As described in the [Predbat installation instructions](install.md#solar-forecast-install, Predbat needs a solar forecast in order to predict solar generation and battery charging which can be provided by the Solcast integration. By default, the template `apps.yaml` is pre-configured to use the [Solcast forecast integration](install.md#solcast-home-assistant-integration-method) for Home Assistant. @@ -1408,7 +1415,7 @@ This can have an impact on planning, especially for things like freeze charging See also [PV configuration options in Home Assistant](customisation.md#solar-pv-adjustment-options). -## Forecast.solar Solar Forecast +### Forecast.solar Solar Forecast The Forecast.solar service can also be used in Predbat, the free version offer access without an API Key but is limited to hourly data and does not provide any 10% or 90% data. Predbat Solar calibration can use past data to improve this information and provide the 10% data. @@ -1450,11 +1457,11 @@ Optionally you can set an api_key for personal or professional accounts and you Note you can omit any of these settings for a default value. They do not have to be exact if you use Predbat auto calibration for PV to improve the data quality. -## Open-Meteo Solar Forecast +### Open-Meteo Solar Forecast [Open-Meteo](https://open-meteo.com/) is a free, open-source weather API that provides solar irradiance forecasts with no API key required. Predbat fetches the Global Tilted Irradiance (GTI) for each array and converts it to a power estimate using a PVWatts cell-temperature model. -Ensemble members are used to derive a P10 pessimistic estimate alongside the central P50. +Ensemble members are used to derive a PV10 pessimistic estimate alongside the central PV50. You can define one or more rooftop arrays by providing a list; they will be summed automatically. @@ -1524,7 +1531,7 @@ These are described in detail in [Energy Rates](energy-rates.md) and are listed - **rates_export_override** - Over-ride export rate for specific date and time range - **futurerate_url** - URL of future energy market prices for Agile users - **futurerate_adjust_import** and **futurerate_adjust_export** - Whether tomorrow's predicted import or export prices should be adjusted based on market prices or not -- **futurerate_adjust_auto** - Auto-detect which of import/export are Agile and calibrate only those rates; overrides `futurerate_adjust_import` / `futurerate_adjust_export`; requires the Octopus Energy integration or Predbat's Octopus Component +- **futurerate_adjust_auto** - Auto-detect which of the import/export rates are Agile and calibrate only those rates; overrides `futurerate_adjust_import` / `futurerate_adjust_export`; requires the Octopus Energy integration or Predbat's Octopus Component - **futurerate_peak_start** and **futurerate_peak_end** - start/end times for peak-rate adjustment - **carbon_postcode** - Postcode to retrieve Carbon intensity grid information for - **carbon_automatic** - Retrieve Carbon intensity information automatically based upon postcode diff --git a/docs/compare.md b/docs/compare.md index ad9c4015e..f9de18ea5 100644 --- a/docs/compare.md +++ b/docs/compare.md @@ -19,7 +19,7 @@ When changing tariffs, you should use your judgment, the Predbat Compare data is ## Configuring the tariff's to compare -First, you need to tell Predbat in apps.yaml which tariffs you want to compare, you should list all the tariffs you realistically might want to switch between, including your current tariff to act as a baseline. +First, you need to tell Predbat in `apps.yaml` which tariffs you want to compare, you should list all the tariffs you realistically might want to switch between, including your current tariff to act as a baseline. Below is a suggestion of various Octopus tariff combinations (valid October 2025) against region A. You will need to change **dno_region** to match your region code if you decide to use this template - see list of [Electricity region codes](https://energy-stats.uk/dno-region-codes-explained/). @@ -138,7 +138,7 @@ The predicted cost is also shown, but keep in mind ending the day with an empty ## Comparison sensors -For each tariff a new sensor is created in Home Assistant called **predbat.compare_tariff_id** where **id** is the ID name you entered above in apps.yaml. This sensor will track the cost as its main value and many details about the prediction in its attributes. +For each tariff a new sensor is created in Home Assistant called **predbat.compare_tariff_id** where **id** is the ID name you entered above in `apps.yaml`. This sensor will track the cost as its main value and many details about the prediction in its attributes. You can create charts from these sensors to show how the different tariffs compare on a daily basis. @@ -146,8 +146,8 @@ You can create charts from these sensors to show how the different tariffs compa ## Overriding Predbat configuration per tariff -You can override any standard Predbat configuration setting for a specific tariff comparison using the `config:` block. -This is applied before the scenario is run and is used to model that comparison scenario. +You can override any standard Predbat configuration setting for a specific tariff comparison using the `config:` block in `apps.yaml`. +This configuration override is applied before the comparison scenario is run and is used to model that scenario. For example, to model a tariff combined with a higher minimum SoC target: @@ -167,7 +167,7 @@ These are applied after live inverter data is fetched, so they fully replace the All four keys are optional and can be combined freely: | Key | Description | Unit | -|-----|-------------|------| +| ----- | ------------- | ------ | | `override_soc_max_kwh` | Battery usable capacity | kWh | | `override_battery_rate_max_charge_kw` | Maximum battery charge rate | kW | | `override_battery_rate_max_discharge_kw` | Maximum battery discharge rate | kW | diff --git a/docs/components.md b/docs/components.md index e00c2e595..011c339e7 100644 --- a/docs/components.md +++ b/docs/components.md @@ -180,7 +180,7 @@ Example usage in VSCode - Browse all entities - Retrieve battery plan data - Override plan for specific time periods -- Access apps.yaml configuration +- Access `apps.yaml` configuration --- @@ -210,7 +210,7 @@ Connects directly to the GivEnergy Cloud to control your GivEnergy inverter and | ------ | ---- | -------- | ------- | ---------- | ----------- | | `ge_cloud_direct` | Boolean | Yes | - | `ge_cloud_direct` | Set to `true` to enable GivEnergy Cloud control | | `api_key` | String | Yes | - | `ge_cloud_key` | Your GivEnergy Cloud API key | -| `automatic` | Boolean | No | false | `ge_cloud_automatic` | Set to `true` to automatically configured Predbat to use GivEnergy Cloud direct (no additional apps.yaml changes required) | +| `automatic` | Boolean | No | false | `ge_cloud_automatic` | Set to `true` to automatically configured Predbat to use GivEnergy Cloud direct (no additional `apps.yaml` changes required) | #### How to get your API key (gecloud) @@ -272,7 +272,7 @@ Connects to your Octopus Energy account to automatically download your tariff ra | ------ | ---- | -------- | ------- | ---------- | ----------- | | `key` | String | Yes | - | `octopus_api_key` | Your Octopus Energy API key | | `account_id` | String | Yes | - | `octopus_api_account` | Your Octopus Energy account number (starts with A-) | -| `automatic` | Boolean | No | true | `octopus_automatic` | Set to `true` to automatically configure Predbat to use this Component (no need to update apps.yaml) | +| `automatic` | Boolean | No | true | `octopus_automatic` | Set to `true` to automatically configure Predbat to use this Component (no need to update `apps.yaml`) | #### How to get your API credentials (octopus) @@ -331,7 +331,7 @@ Select control my battery for 'Events Only'. 1. Log in to your Axle Energy VPP portal at 2. Navigate to the Home Assistant integration section 3. Copy your API key -4. Paste it into `axle_api_key` in apps.yaml +4. Paste it into **axle_api_key** in `apps.yaml` #### Sensor Attributes (axle) @@ -515,7 +515,7 @@ Integrates with Fox ESS inverters for monitoring and controlling Fox ESS battery | Option | Type | Required | Default | Config Key | Description | | ------ | ---- | -------- | ------- | ---------- | ----------- | | `key` | String | Yes | - | `fox_key` | Your Fox ESS API key | -| `automatic` | Boolean | No | false | `fox_automatic` | Set to `true` to automatically configured Predbat to use the Fox inverter (no manual apps.yaml updates required) | +| `automatic` | Boolean | No | false | `fox_automatic` | Set to `true` to automatically configured Predbat to use the Fox inverter (no manual `apps.yaml` updates required) | | `automatic_ignore_pv` | Boolean | No | false | `fox_automatic_ignore_pv` | When `automatic` is enabled, set to `true` to prevent Fox Cloud from overwriting `pv_power` and `pv_today` config. Useful for AC-coupled setups where PV is measured independently and Fox Cloud reports zero/absent PV data | --- @@ -551,7 +551,7 @@ Integrates with Solis inverters for monitoring and controlling Solis battery sys | `api_key` | String | Yes | - | `solis_api_key` | Your Solis Cloud API Key (KeyId) | | `api_secret` | String | Yes | - | `solis_api_secret` | Your Solis Cloud API Secret (KeySecret) | | `inverter_sn` | String/List | No | - | `solis_inverter_sn` | Inverter serial number(s) - Leave unset to see all. Single string or list of strings for multiple inverters | -| `automatic` | Boolean | No | false | `solis_automatic` | Set to `true` to automatically configure Predbat to use the Solis inverter (no manual apps.yaml sensor updates required) | +| `automatic` | Boolean | No | false | `solis_automatic` | Set to `true` to automatically configure Predbat to use the Solis inverter (no manual `apps.yaml` sensor updates required) | | `base_url` | String | No | Auto-detected | `solis_base_url` | Solis Cloud API base URL (automatically selects correct region) | | `control_enable` | Boolean | No | true | `solis_control_enable` | Enable/disable control commands (set to false for monitoring only) | @@ -814,7 +814,7 @@ For a detailed explanation of how the neural network works and comprehensive con | `load_ml_max_days_history` | Integer | No | 28 | `load_ml_max_days_history` | Maximum days of load history to fetch from HA on each poll (bounded by HA recorder retention) | | `load_ml_database_days` | Integer | No | 90 | `load_ml_database_days` | Days of history to accumulate in the on-disk database (`predbat_ml_history.npz`); set to 0 to disable the database | -Note: `load_today`, `pv_today` and `car_charging_energy` apps.yaml configuration items are also used, but these should already be set in Predbat. +Note: **load_today**, **pv_today** and **car_charging_energy** `apps.yaml` configuration items are also used, but these should already be set in Predbat. #### Configuration example (load_ml) diff --git a/docs/configuration-guide.md b/docs/configuration-guide.md index 030c3a76e..cc00bc9d1 100644 --- a/docs/configuration-guide.md +++ b/docs/configuration-guide.md @@ -1,7 +1,7 @@ # Configuration guide First, get the basics set up, ensure you have the [inverter controls configured](install.md#inverter-control-install), -you have [configured apps.yaml](apps-yaml.md) to your setup, and the [solar forecast](install.md#solcast-install) is in place. +you have [configured apps.yaml](apps-yaml.md) to your setup, and the [solar forecast](install.md#solar-forecast-install) is in place. Make sure your [energy rates](energy-rates.md) are configured correctly for import and export. If you have an EV try to set up the [car charging sensor](car-charging.md#filtering-car-charging-energy-from-house-load) correctly so Predbat can tell what part of your historical load is EV charging. diff --git a/docs/customisation.md b/docs/customisation.md index 269e421b1..09d0ad640 100644 --- a/docs/customisation.md +++ b/docs/customisation.md @@ -4,7 +4,7 @@ This document describes the Predbat configuration items in Home Assistant that y All of these settings are entities that can be configured directly in Home Assistant (unlike the '[apps.yaml](apps-yaml.md)' configuration items that have to be edited with a file editor). -Note the default values of the settings inside Home Assistant are set inside Predbat, but the default can be overridden by setting its value in apps.yaml prior to starting Predbat for the first time. +Note the default values of the settings inside Home Assistant are set inside Predbat, but the default can be overridden by setting its value in `apps.yaml` prior to starting Predbat for the first time. See [Displaying output data](output-data.md) for information on how to view and edit these entities within diff --git a/docs/energy-rates.md b/docs/energy-rates.md index a74a01ecf..4d9c573ad 100644 --- a/docs/energy-rates.md +++ b/docs/energy-rates.md @@ -17,7 +17,8 @@ There are a number of different ways of configuring your Energy rates in `apps.y - [Octopus Rates URL's](#octopus-rates-url), configuring Predbat to directly use the correct URL's for your Octopus tariff (not recommended as can stop working when you change tariff) - [Kraken component](#kraken-integration-for-edf-or-eonnext), Predbat getting rates directly from Kraken for EDF or Eon.Next customers - [Energidataservice Integration](#energidataservice-integration), Predbat getting rates from the Energidataservice integration -- [Spot rates](#other-energy-spot-rate-sensor-integrations), Predbat retrieving spot rates from a correctly formatted import and export rate sensor +- [Strømligning Integration](#strømligning-integration), Predbat getting rates from the Strømligning integration +- [Spot rates](#other-energy-spot-rate-sensor-integrations), Predbat retrieves spot rates from correctly formatted import and export rate sensors - [Manually defining your rates and time periods](#rate-bands-to-manually-configure-energy-rates). At least one of these methods must be used to define your import and export rates. If you don't then Predbat will assume zero for your energy rates. @@ -113,7 +114,7 @@ Confirm that the Octopus entities are being populated correctly. ### Configuring Predbat to use the Octopus Energy integration -The following configuration items in apps.yaml are used to configure Predbat to use the Octopus Energy integration. +The following configuration items in `apps.yaml` are used to configure Predbat to use the Octopus Energy integration. They are set to a regular expression and should be auto-discovered so that Predbat automatically uses the Octopus Energy integration, but you can comment out the regular expression lines to disable, or you set them manually. @@ -124,7 +125,7 @@ but you can comment out the regular expression lines to disable, or you set them metric_octopus_gas is (as above) only required to be configured if you are using Predbat to determine whether to heat your hot water via your iBoost or gas. -If you do not have an export rate or are not on the Octopus Go tariff, then the appropriate lines can be commented out in apps.yaml. +If you do not have an export rate or are not on the Octopus Go tariff, then the appropriate lines can be commented out in `apps.yaml`. Note: Predbat using the Octopus integration rates relies upon the day rate events being enabled (see above) and the events and the sensor found by metric_octopus_xxx in `apps.yaml` being similarly named.
There have been occasions with some Octopus Integration installations where the event name is as above but the sensor name has a different prefix, e.g. sensor.electricity_METER_NUMBER_current_rate and not sensor.octopus_energy_electricity_METER_NUMBER_current_rate.
@@ -133,11 +134,11 @@ If this is the case then the sensor must be renamed to the correct format so tha ### Standing charge Predbat can also (optionally) include the daily standing charge in cost predictions. -The following configuration item in apps.yaml defaults to obtaining the standing charge from the Octopus Energy integration: +The following configuration item in `apps.yaml` defaults to obtaining the standing charge from the Octopus Energy integration: - **metric_standing_charge** - Standing charge in pounds. By default points to the Octopus Energy integration sensor sensor.octopus_energy_electricity_METER_NUMBER_current_standing_charge -You can manually change this to a standing charge in pounds, e.g. 0.50 is 50p, or delete this line from apps.yaml, or set it to zero +You can manually change this to a standing charge in pounds, e.g. 0.50 is 50p, or delete this line from `apps.yaml`, or set it to zero if you don't want the standing charge (and only have consumption usage) to be included in Predbat charts and output data. Note that this configuration option to suppress the standing charge only applies if you are using the Octopus Integration from Predbat. @@ -178,11 +179,11 @@ simply delete or comment out the **octopus_saving_session** entry in `apps.yaml` Predbat can automatically detect Octopus free events and adjust your battery plan according. Note that this is derived from external sources, which do not verify your eligibility for free sessions. -For Predbat to automatically manage Octopus free sessions the following additional configuration item in apps.yaml is used. +For Predbat to automatically manage Octopus free sessions the following additional configuration item in `apps.yaml` is used. Note: **You must have signed up to the Octopus Octoplus scheme and eligible to benefit from these events** -Like the electricity rates, this is set in the apps.yaml template to a regular expression that should auto-discover the Octopus Energy integration. +Like the electricity rates, this is set in the `apps.yaml` template to a regular expression that should auto-discover the Octopus Energy integration. **octopus_free_session** - Will point to the free event sensor that is exposed by the Octopus Energy Integration. This event sensor contains the dates/times of all the free events. @@ -209,7 +210,7 @@ not work in future if Octopus ever change the website format. If you enable this As an alternative to the Octopus Direct or Octopus Energy integration methods, for Octopus Energy customers, you can configure Predbat to get the electricity rates directly online from the Octopus website. -In apps.yaml configure the following lines: +In `apps.yaml` configure the following lines: - **rates_import_octopus_url** to point to the appropriate import tariff URL on the Octopus website - **rates_export_octopus_url** to point to the export tariff URL @@ -389,9 +390,9 @@ A template sensor can be used to manipulate the rates provided by the integratio ## Rate Bands to manually configure Energy Rates -If you are not an Octopus Energy customer, or you are but your energy rates repeat simply, you can configure your rate bands in apps.yaml using rates_import/rates_export/rates_gas. +If you are not an Octopus Energy customer, or you are but your energy rates repeat simply, you can configure your rate bands in `apps.yaml` using rates_import/rates_export/rates_gas. -Add the following entries to apps.yaml to define the pattern of rates over 24 hours: +Add the following entries to `apps.yaml` to define the pattern of rates over 24 hours: ```yaml rates_import: @@ -435,7 +436,7 @@ The gas rates are only required if you have a gas boiler, or an iBoost, and are ## Manually over-riding energy rates -You can also override the import or export energy rates (regardless of whether they are set manually or via the Octopus Energy integration) by using the override feature in apps.yaml. +You can also override the import or export energy rates (regardless of whether they are set manually or via the Octopus Energy integration) by using the override feature in `apps.yaml`. Rate override is used to set the specific date and time period where your rates are different, e.g. an Octopus Power Up session (zero rate for an hour or two), or the British Gas half-price electricity on Sundays. @@ -514,7 +515,7 @@ and **input_number.predbat_metric_future_rate_offset_export** (*expert mode*) in ## Future Agile energy rates In the energy market, it's possible to calculate the Octopus Agile rates from around 10am UK time using public data, you can -enable this in apps.yaml for Import, Export or both. This will approximate the next day's rates based on the spot prices. +enable this in `apps.yaml` for Import, Export or both. This will approximate the next day's rates based on the spot prices. The approximation is only used until the real Octopus Agile rates are released around 4pm. - **futurerate_url** - URL of future energy market prices; this should not normally need to be changed diff --git a/docs/faq.md b/docs/faq.md index 426b34278..c0ce7077b 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -5,8 +5,8 @@ - First look at **predbat.status** in Home Assistant and the Predbat App log (which can be found in the list of log files in the System/Log area of the GUI). See if any errors are warnings are found. If you see an error something is likely configured incorrectly, check your entity settings are correct. -- Make sure Solcast is installed and it's auto-updated at least a couple of times a day (see the [Solcast instructions](install.md#solcast-install)). -The default Solcast sensor names may be wrong, you might need to update the `apps.yaml` config to match your own names +- Make sure a Solar Forecast is installed and it's auto-updated at least a couple of times a day (see the [Solar Forecast instructions](install.md#solar-forecast-install)). +If you are using the Solcast Integration then the default Solcast sensor names may be wrong, you might need to update the `apps.yaml` config to match your own names (some people don't have the solcast_ bit in their entity names). ## Predbat is failing with Warn: Service call select/select_option data failed @@ -149,7 +149,7 @@ Predbat can only work on the information it's given, although it does run every The plan Predbat produces assumes that your average load and PV forecasts are accurate and Predbat will aim to give you the maximum return. -Make sure you have set up your [Solcast solar forecast correctly](install.md#solcast-install) with the number of panels, orientation, output, etc. +Make sure you have set up your [Solar forecast correctly](install.md#solar-forecast-install) with the number of panels, orientation, output, etc. Projected daily load is determined from historical load information so make sure you have set [days_previous and days_previous_weight in apps.yaml](apps-yaml.md#basics) to give appropriately representative load history to Predbat, and read the [longer explanation of how days_previous works](apps-yaml.md#understanding-how-days_previous-works). @@ -287,7 +287,7 @@ delete all the old Octopus sensors, and [re-install the Octopus Integration](ins If you get this warning message in the Predbat log file or you see that the 'PV kWh' column in the [Predbat plan card](predbat-plan-card.md) is completely blank: -- Ensure that you have [installed and configured Solcast correctly](install.md#solcast-install) +- Ensure that you have [installed and configured a Solar Forecast correctly](install.md#solar-forecast-install) - Check the Solcast integration in Home Assistant is configured and enabled (go to Settings / Integrations / Solcast) - Check that there are no errors relating to Solcast in the Home Assistant log (go to Settings / System / Logs and view the 'Home Assistant Core' log). If you see an error 429 message in the log then this is as a result of Solcast's rate limiting for Hobbyist accounts. diff --git a/docs/index.md b/docs/index.md index cc68447eb..78150d63c 100644 --- a/docs/index.md +++ b/docs/index.md @@ -44,7 +44,7 @@ If you want to buy me a beer then please use [Paypal](https://paypal.me/predbat? ![image](https://github.com/springfall2008/batpred/assets/48591903/b3a533ef-0862-4e0b-b272-30e254f58467) If you are finding Home Assistant and Predbat too difficult to set up yourself there is now [PredBat Cloud](https://predbat.com/) which is a paid for version of Predbat hosted in the cloud. -Please note that while I have given permission for PredBat Cloud to operate this is not my company, PredBat will remain open source for personal use. +Please note that while I have given permission for PredBat Cloud to operate, this is not my company and PredBat will remain open source for personal use. ## Taster diff --git a/docs/install.md b/docs/install.md index 65251a844..414d4e1e6 100644 --- a/docs/install.md +++ b/docs/install.md @@ -97,12 +97,12 @@ Installing HACS, Appdaemon and then Predbat within Appdaemon has been deprecated The process to [upgrade from Predbat within Appdaemon to Predbat addon](#upgrading-from-appdaemon-to-predbat-app) is described below. -## Solcast Install +## Solar Forecast Install Predbat needs a solar forecast to predict solar generation and battery charging. If you have solar panels it's recommended to use the Solcast integration to retrieve your forecast solar generation. -If you do not want to use Solcast you can also use [Forecast.solar](#predbat-direct-to-forecastsolar) (less accurate) - see below. +If you do not want to use Solcast you can also use [Forecast.solar](#predbat-direct-to-forecastsolar) (less accurate) or [Open-Meteo](#predbat-direct-to-open-meteo) - see below. If you don't have one already, register for a free [Solcast hobbyist account](https://solcast.com/) and enter the details of your system. You can create 2 sites maximum under one (free hobbyist) account, if you have more aspects then it suggests you average the angle based on the number of panels @@ -320,7 +320,7 @@ multiple import rates during the day, and variable tariffs such as Agile, etc. The detailed [Predbat Customisation Guide](customisation.md) details all the Predbat configuration items (switches, input numbers, etc) in Home Assistant, and what each of them does. -The Predbat [Web Interface](web-interface.md) provides an easy way to view all of the Predbat configuration items, check apps.yaml for errors, and view the logfile. +The Predbat [Web Interface](web-interface.md) provides an easy way to view all of the Predbat configuration items, check `apps.yaml` for errors, and view the logfile. ## Ready to light the touch-paper @@ -449,7 +449,7 @@ The Predbat code that runs is the same and the configuration is exactly the same 6. Briefly start the new Predbat app so that it creates the addon_config folder and the template `apps.yaml` file: - Go to Settings/Apps - Click on the Predbat app - - Click START, wait a minute for the app to initialise itself, then click STOP. A predbat status warning that you have a template apps.yaml file is normal and can be ignored + - Click START, wait a minute for the app to initialise itself, then click STOP. A predbat status warning that you have a template `apps.yaml` file is normal and can be ignored 7. Open your file editor and open your existing `apps.yaml` file: - If you are using the old 'combined AppDaemon/Predbat app installation method' it's in the directory `/addon_configs/46f69597_appdaemon-predbat/apps`, @@ -457,10 +457,10 @@ The Predbat code that runs is the same and the configuration is exactly the same - with the old HACS Appdaemon app then Predbat installation method it's in `/config/appdaemon/apps/batpred/config/` -8. Select all the contents of the apps.yaml file and 'copy' (control-C, command-C, etc as appropriate) +8. Select all the contents of the `apps.yaml` file and 'copy' (control-C, command-C, etc as appropriate) 9. Now open the template `apps.yaml` file that's supplied with the Predbat app and has been created in the directory `/addon_configs/6adb4f0d_predbat`, -select all the contents of the template apps.yaml file, and paste in the contents of your existing apps.yaml, overwriting the template with your specific configuration +select all the contents of the template `apps.yaml` file, and paste in the contents of your existing `apps.yaml`, overwriting the template with your specific configuration 10. Now you are ready to swap from running the AppDaemon or AppDaemon-predbat app to the Predbat app: - Go to Settings/Apps diff --git a/docs/installation-summary.md b/docs/installation-summary.md index bd74989df..10319e4b4 100644 --- a/docs/installation-summary.md +++ b/docs/installation-summary.md @@ -7,8 +7,8 @@ see the [video guides](video-guides.md) section for those and other videos 2. Make sure the right [inverter control module](install.md#inverter-control-install) is installed and running 3. Install a file editor (either the File editor or Studio Code Server app) to enable you to edit configuration files if you haven't already - [Editing configuration files](install.md#editing-configuration-files-in-home-assistant) 4. Install - [Predbat app install](install.md#predbat-app-install) for HAOS, or as a [Docker install](install.md#docker-install) -5. Decide on and setup a Solar Forecast. It's recommended that you use [Solcast](install.md#solcast-install), or you can use [Open-Meteo](install.md#predbat-direct-to-open-meteo) (free, no API key required) or [Forecast.solar](install.md#predbat-direct-to-forecastsolar).
For Solcast: - - Register for a Solcast hobbyist account if you haven't already [Solcast install](install.md#solcast-install) and either: +5. Decide on and setup a Solar Forecast. It's recommended that you use [Solcast](install.md#solcast-home-assistant-integration-method), or you can use [Open-Meteo](install.md#predbat-direct-to-open-meteo) (free, no API key required) or [Forecast.solar](install.md#predbat-direct-to-forecastsolar).
For Solcast: + - Register for a Solcast hobbyist account if you haven't already [Solcast install](install.md#solar-forecast-install) and either: - [Configure Predbat to call Solcast](install.md#predbat-direct-solcast-method) for the Solar forecast, or - [Install and configure the Solcast integration](install.md#solcast-home-assistant-integration-method), and check that you see the Solcast data in Home Assistant 6. Follow the [Energy Rates](energy-rates.md) instructions to tell Predbat what your import and export energy rates are. diff --git a/docs/inverter-setup.md b/docs/inverter-setup.md index 174e3e873..28ae8441a 100644 --- a/docs/inverter-setup.md +++ b/docs/inverter-setup.md @@ -99,7 +99,7 @@ Click on the 'GivTCP' app, then click 'INSTALL' For example, if you have a gateway and two AIOs you could use the prefixes 'GW', 'AIO-1' and 'AIO-2'. The prefixes should be set before you start using GivTCP in anger as changing the prefixes later on will result in both the old and new sensor names appearing in Home Assistant with the 'old' sensors being "unavailable".
- Note that if you do change the givtcp prefixes then you will also have to edit the apps.yaml configuration file to match, + Note that if you do change the givtcp prefixes then you will also have to edit the `apps.yaml` configuration file to match, and change the sensor names that Predbat is looking for (by default prefixed 'givtcp_xxx') to your new sensor naming structure - Click Next and Next to get to the Selfrun page, and turn on Self Run so that GivTCP automatically retrieves data from your inverter. The Self Run Loop Timer is how often GivTCP will retrieve data - it's @@ -1790,7 +1790,7 @@ sensor: If you have multiple batteries connected to your SolarEdge inverter and are using the SolarEdge Modbus Multi integration, this enumerates the multiple batteries as b1, b2, b3, etc with separate entities per battery. -You will need to make a number of changes to the solaredge apps.yaml, replacing the following entries: +You will need to make a number of changes to the solaredge `apps.yaml`, replacing the following entries: ```yaml battery_rate_max: diff --git a/docs/output-data.md b/docs/output-data.md index 47c38e22e..2856afc75 100644 --- a/docs/output-data.md +++ b/docs/output-data.md @@ -648,7 +648,7 @@ These binary sensors are useful in Home Assistant automations, e.g. to start an ## Solar forecast data The following sensors give the forecast Solar data from Solcast. -Predbat populates these sensors irrespective of whether you are using the [Predbat direct Solcast or Solcast integration method](install.md#solcast-install) to get your Solar forecast, +Predbat populates these sensors irrespective of whether you are using the [Predbat direct Solcast or Solcast integration method](install.md#solar-forecast-install) to get your Solar forecast, but if you are using the Solcast integration then the Predbat sensors mirror the similarly named Solcast integration sensors so could be disabled if you so wish. - sensor.predbat_pv_today - Tracks the PV forecast in kWh for today, attributes give the total today, remaining amount today and the half-hourly data From edf4226ca38e52f7cbb9c9f0c1b8eec62886c92f Mon Sep 17 00:00:00 2001 From: Geoffrey Coan <142018870+gcoan@users.noreply.github.com> Date: Sat, 16 May 2026 21:03:27 +0000 Subject: [PATCH 2/9] Document PVAccuracy chart and Metrics view --- docs/car-charging.md | 6 +++--- docs/output-data.md | 31 ++++++++++++++++++++----------- docs/web-interface.md | 21 +++++++++++++++++---- 3 files changed, 40 insertions(+), 18 deletions(-) diff --git a/docs/car-charging.md b/docs/car-charging.md index 7c11e43f1..a3c8059be 100644 --- a/docs/car-charging.md +++ b/docs/car-charging.md @@ -100,9 +100,9 @@ If you are on the Octopus Intelligent Tariff set the following entries in `apps. - **octopus_slot_low_rate** - Default is `true`, meaning any Octopus Intelligent Slot reported will be at the lowest rate if at home. If `false` the existing rates only will be used which is only suitable for tariffs other than IOG. -- **octopus_slot_max** - Default is 48 (disabled). Sets the maximum number of 30-minute cheap rate slots per 24-hour period. -Octopus Intelligent users maybe from March 2026 limited to 6 hours of cheap charging per day. Slots beyond this limit will use standard rates. -Its recommended you set this to 12 (for 6 hours) once Octopus enforce this Octopus Intelligent limit. +- **octopus_slot_max** - Default is 48 (disabled). Sets the maximum number of 30-minute cheap rate EV charging slots per 24-hour period. +Octopus Intelligent users maybe from May 2026 will be limited to 6 hours of cheap EV charging per day. Slots beyond this limit will use standard rates. +Its recommended you leave this set this to 12 (for 6 hours) once Octopus enforce this Octopus Intelligent limit. The cap can be disabled by setting it to 48. If you are using Octopus-led charging with the [Octopus Energy integration](energy-rates.md#octopus-energy-home-assistant-integration): diff --git a/docs/output-data.md b/docs/output-data.md index 2856afc75..7684bdc08 100644 --- a/docs/output-data.md +++ b/docs/output-data.md @@ -7,7 +7,7 @@ There can never be a single Predbat dashboard that suits every user, so instead ## Web interface -The [Predbat Web Interface](web-interface.md) provides an easy to use way to see and change different aspects of your Predbat system including view the current plan, adjust the configuration, view the charts, check your apps.yaml and view the logfiles. +The [Predbat Web Interface](web-interface.md) provides an easy to use way to see and change different aspects of your Predbat system including view the current plan, adjust the configuration, view the charts, check your `apps.yaml` and view the logfiles. ![image](images/web-interface-plan-view.png) @@ -293,7 +293,7 @@ Predbat outputs the values it read from your inverters as totals, this gives the Predbat outputs the following sensors to predict what your battery is expected to do *over the forecast_hours duration of the plan* with no changes made by Predbat. This is considered to be the 'baseline' plan: -NB: All of Predbat's forecasts are from midnight today to the forecast_hours duration (set in apps.yaml) into the future and shouldn't be confused with 'today' figures. +NB: All of Predbat's forecasts are from midnight today to the forecast_hours duration (set in `apps.yaml`) into the future and shouldn't be confused with 'today' figures. e.g. predbat.pv_energy is the actual PV energy from midnight today, and for the predicted forecast_hours (typically 48) ahead so will be much larger than sensor.solcast_pv_forecast_today which is today's Solcast PV forecast. @@ -406,14 +406,14 @@ After midnight when insufficient data is available, this blends yesterday's fina ## 'Today' energy data The following sensor's output by Predbat give the 'today' energy readings. -They mirror input sensors fed into Predbat in apps.yaml and are used in the data prediction chart - see [creating the Predbat charts](creating-charts.md): +They mirror input sensors fed into Predbat in `apps.yaml` and are used in the data prediction chart - see [creating the Predbat charts](creating-charts.md): -- predbat.export_energy_h0 - Mirrors the export_today sensor configured in apps.yaml and gives today's total kWh of export energy -- predbat.import_energy_h0 - Mirrors the import_today sensor configured in apps.yaml and gives today's total kWh of import energy -- predbat.load_energy_h0 - Mirrors the load_today sensor configured in apps.yaml and gives today's total kWh of house load energy. +- predbat.export_energy_h0 - Mirrors the export_today sensor configured in `apps.yaml` and gives today's total kWh of export energy +- predbat.import_energy_h0 - Mirrors the import_today sensor configured in `apps.yaml` and gives today's total kWh of import energy +- predbat.load_energy_h0 - Mirrors the load_today sensor configured in `apps.yaml` and gives today's total kWh of house load energy. Note that if you have configured [load scaling](customisation.md#scaling-and-weight-options) then load_energy_h0 will have been scaled by the scaling factor. -- predbat.pv_energy_h0 - Mirrors the pv_today sensor configured in apps.yaml and gives today's total kWh of generated PV energy -- predbat.soc_kw_h0 - Mirrors the soc_kwh sensor configured in apps.yaml and gives today's total kWh of battery state of charge (SoC). +- predbat.pv_energy_h0 - Mirrors the pv_today sensor configured in `apps.yaml` and gives today's total kWh of generated PV energy +- predbat.soc_kw_h0 - Mirrors the soc_kwh sensor configured in `apps.yaml` and gives today's total kWh of battery state of charge (SoC). Note that if you have configured [battery scaling](apps-yaml.md#battery-size-scaling) then soc_kw_h0 will have been scaled by the configured scaling factor ## Battery status @@ -596,7 +596,7 @@ and only charging at the lowest import rate in the 24 hour period vs not having a PV and battery system at all and all house load being met from grid import Note: The savings using Predbat are calculated by default compared to having one fixed nightly charge slot set to charge at the lowest import rate with a target of 100% -You can change the number of simulated charge slots in apps.yaml by setting **calculate_savings_max_charge_slots** to the number of slots to allow. +You can change the number of simulated charge slots in `apps.yaml` by setting **calculate_savings_max_charge_slots** to the number of slots to allow. If set to 0 then Demand (ECO) mode will be used as the baseline or if non-zero then the maximum number of slots can be set (e.g. 2). Note: The 'without Predbat' simulation is a self-consistent parallel universe — each day's starting SoC is the ending SoC of the previous day's simulation, not the actual midnight SoC. @@ -620,9 +620,9 @@ levels and at different times in the upcoming forecast window. The results are p - `grid_export_now` - Current grid export rate (p/kWh) - `baseline_metric` - Internal baseline cost used to compute deltas (standing charge excluded) - `rate_now_low_consumption` - Marginal cost now for the 'low' (1 kWh) load level - - `rate_now_med_consumption` - Marginal cost now for the 'med' (2 kWh) load level + - `rate_now_med_consumption` - Marginal cost now for the 'medium' (2 kWh) load level - `rate_now_high_consumption` - Marginal cost now for the 'high' (4 kWh) load level - - `rate_now_ev_consumption` - Marginal cost now for the 'ev' (8 kWh) load level + - `rate_now_ev_consumption` - Marginal cost now for the 'EV' (8 kWh) load level ### Cheap/moderate binary sensors @@ -873,6 +873,15 @@ triggers: alert_text: >- Predbat status is {{ states('predbat.status') }}, error={{ state_attr('predbat.status', 'error') }} + - trigger: template + alias: Predbat status contains 'unable to read REST data' for 10 minutes + value_template: "{{ 'unable to read REST data' in states('predbat.status') }}" + for: + minutes: 10 + variables: + alert_text: >- + Predbat status is {{ states('predbat.status') }}, error={{ + state_attr('predbat.status', 'error') }} - trigger: state alias: Predbat is in error status for 10 minutes entity_id: predbat.status diff --git a/docs/web-interface.md b/docs/web-interface.md index fc74e85db..c48d254c5 100644 --- a/docs/web-interface.md +++ b/docs/web-interface.md @@ -100,8 +100,9 @@ The chart also shows where charging is planned under the Base and Best scenarios - **Cost** - Shows the historic import, export and net total cost incurred for today and the predicted cost for the plan duration under the Base/Base10/Best and Best10 scenarios - **Rates** - Shows historic and future import and export rates along with historic hourly and today pence per kWh so you can see where you have earned or spent the most on electricity during today - **InDay** - Shows Predbat's predicted house load for today, the actual house load that has occurred so far today, and then Predbat's adjusted house load prediction based on the variance of today's actual load to predicted load -- **PV** - Shows today's predicted solar generation under the PV, PV10 and PV90 scenarios alongside today's actual solar generation -- **PV7** - Similar to the PV chart, but shows actual solar generation and forecast for the last 7 days including today +- **PV** - Shows today's predicted solar power generation under the PV, PV10 and PV90 scenarios alongside today's actual solar power generation +- **PV7** - Similar to the PV chart, but shows actual solar power generation and forecast for the last 7 days including today +- **PVAccuracy** - Shows how accurate the PV energy forecast is, comparing cumulative PV forecast energy for today to today's actual cumulative solar energy generation - **Load ML** - Shows the correlation between your actual house load and the [Load ML predictions](load-ml.md), charting current prediction, the 1 hour in the future prediction, and the 8 hours future prediction - **LoadMLPower** - Similar to the Load ML chart, but also plots actual PV production, predicted PV production and temperature predictions. - **MarginalCosts** - Shows the marginal cost of consuming extra electricity at different load levels (1, 2, 4, 8 kWh) across upcoming time windows. @@ -170,8 +171,7 @@ You can restart individual Predbat components if required. ### Editor View -The editor view allows you to edit `apps.yaml` as text directly within the web interface. If you make a syntax error then the error will be highlighted and save -will be disabled pending a fix. +The editor view allows you to edit `apps.yaml` as text directly within the web interface. If you make a syntax error then the error will be highlighted and save will be disabled pending a fix. image of Predbat Editor view @@ -189,6 +189,19 @@ It gives the hierarchy of threads, and their status; and the Predbat code object These are intended for debugging and developer activities, in normal use you can ignore this view! +### Metrics View + +The Metrics view provides a self-contained dashboard giving an overview of Predbat and what's happening with your batteries. The dashboard auto-refreshes every 30 seconds and contains the following 5 sections: + +- **System Health** - shows a set of system health cards including confirming that Predbat is running, the configuration and plan are valid, how long since the last Predbat run, that there are no component errors and the amount of data history that Predbat is using +- **Battery Status** - shows battery SoC doughnut and power meters for current battery charge, discharge, house load, PV, grid import and grid export +- **Energy Today** - shows total energy today for house load, grid import, grid export and PV generation +- **Cost & Savings** - shows electricity cost today and yesterday, and savings achieved yesterday from having solar and battery and from using predbat +- **API & Solar Status** - shows API health (requests, failures and last call) made by Predbat to Axle, Solcast/Forecast.Solar, GivEnergy Cloud, Fox ESS Cloud, Solis Cloud, and Open Meteo (Temperature for LoadML). Data is only shown for components that are active, i.e. if Predbat is not using the GivEnergy Cloud integration, no API call metrics are shown.
+Solar status shows Solcast API calls (Predbat Solcast direct only) and PV Calibration Scaling (worst day, best day and total) + +![image](images/web-interface-metrics-view.png) + ### Docs View Provides a quick link to the [Predbat documentation](https://springfall2008.github.io/batpred/). From 7acc09ec2858530848a94510c8e5913d03df9cb4 Mon Sep 17 00:00:00 2001 From: Geoffrey Coan <142018870+gcoan@users.noreply.github.com> Date: Mon, 18 May 2026 06:09:48 +0000 Subject: [PATCH 3/9] #3934 iboost daily reset --- docs/apps-yaml.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/apps-yaml.md b/docs/apps-yaml.md index 3df88183b..29b65375d 100644 --- a/docs/apps-yaml.md +++ b/docs/apps-yaml.md @@ -891,6 +891,8 @@ To disable, set it to 1440. - **iboost_energy_today** - Set to a sensor which tracks the amount of energy sent to your solar diverter, which can also be used to subtract from your historical load for more accurate predictions. +The iboost energy sensor should reset to zero each day so if your source sensor doesn't, then its recommended to wrap it in a utility meter and configure Predbat to use the utility meter. + ## Inverter control configurations ### **inverter_limit** From da5635f1e5728ea5728acb6562b099ee98cbec53 Mon Sep 17 00:00:00 2001 From: Geoffrey Coan <142018870+gcoan@users.noreply.github.com> Date: Mon, 18 May 2026 06:21:07 +0000 Subject: [PATCH 4/9] Added soc_max_calculated to output_data --- docs/apps-yaml.md | 2 +- docs/output-data.md | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/apps-yaml.md b/docs/apps-yaml.md index 29b65375d..784282270 100644 --- a/docs/apps-yaml.md +++ b/docs/apps-yaml.md @@ -1748,7 +1748,7 @@ rather than the usual *givtcp_SERIAL_NUMBER_soc* GivTCP entity so everything lin Default false. When set to true Predbat will automatically calculate `battery_scaling` based on historical charge data rather than using the static value above. The calculation uses `find_battery_size()` to estimate the actual usable battery capacity from historical charging periods and -compares it to the nominal capacity (`soc_max`). A 7-day rolling history of daily estimates is stored in a new sensor +compares it to the nominal capacity (`soc_max`). A 7-day rolling history of daily estimates is stored in the sensor `sensor.predbat_soc_max_calculated` (or `sensor.predbat_soc_max_calculated_N` for inverter N > 0). The sensor state is the trimmed mean of the history (the highest and lowest samples are discarded when 3 or more data points exist, giving a stable average that is robust to occasional outliers). diff --git a/docs/output-data.md b/docs/output-data.md index 7684bdc08..9a9d80f8d 100644 --- a/docs/output-data.md +++ b/docs/output-data.md @@ -503,6 +503,10 @@ You'll need to change the hard-coded timestamp "2024-12-12..." to the date/time *TIP:* If your inverter is ever replaced and you want to reset the inverter register writes back to zero, simply update the entity state of predbat.inverter_register_writes using Settings / Developer Tools / States and search for the entity. +## Battery data + +- sensor.predbat_soc_max_calculated[_N] - Created if [automatic battery size scaling is enabled in apps.yaml](apps-yaml.md#battery-size-scaling), contains a 7 day rolling history of daily estimates of usable battery capacity, calculated from historical charging data compared to nominal capacity. + ## Car data - binary_sensor.predbat_car_charging_slot - A binary sensor indicating when to charge your car (if car planning is enabled) - which can be used in an automation From ed0ee23221faa9b7188e624d5a86db6b6b68b254 Mon Sep 17 00:00:00 2001 From: Geoffrey Coan <142018870+gcoan@users.noreply.github.com> Date: Mon, 18 May 2026 23:32:59 +0000 Subject: [PATCH 5/9] Add error checking to Octopus saving session join, only send joined notification if join was successful --- apps/predbat/octopus.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/predbat/octopus.py b/apps/predbat/octopus.py index d3a08435b..154903de4 100644 --- a/apps/predbat/octopus.py +++ b/apps/predbat/octopus.py @@ -2781,7 +2781,7 @@ def fetch_octopus_sessions(self): octopus_saving_slots = [] if "octopus_saving_session" in self.args: saving_rate = 200 # Default rate if not reported - octopoints_per_penny = self.get_arg("octopus_saving_session_octopoints_per_penny", 8) # Default 8 octopoints per found + octopoints_per_penny = self.get_arg("octopus_saving_session_octopoints_per_penny", 8) # Default 8 octopoints per penny joined_events = [] available_events = [] @@ -2811,17 +2811,22 @@ def fetch_octopus_sessions(self): saving_rate = octopoints_kwh / octopoints_per_penny # Octopoints per pence else: saving_rate = saving_rate # Use default if not specified - if code: # Join the new Octopus saving event and send an alert + if code: # Join the new Octopus saving event and send an alert if successfully joined self.log("Octopus: Joining Octopus saving event code {} {}-{} at rate {} p/kWh".format(code, start_time.strftime("%a %d/%m %H:%M"), end_time.strftime("%H:%M"), saving_rate)) entity_id_join = self.get_arg("octopus_saving_session_join", indirect=False) if entity_id_join: # Join via selector - self.call_service_wrapper("select/select_option", entity_id=entity_id_join, option=code) + cmd = "select/select_option, entity_id={}, option={}".format(entity_id_join, code) + result = self.call_service_wrapper("select/select_option", entity_id=entity_id_join, option=code) else: # Join via octopus event (Bottle Cap Dave) - self.call_service_wrapper("octopus_energy/join_octoplus_saving_session_event", event_code=code, entity_id=entity_id) - if self.get_arg("set_event_notify"): - self.call_notify("Predbat: Joined Octopus saving event {}-{}, {} p/kWh".format(start_time.strftime("%a %d/%m %H:%M"), end_time.strftime("%H:%M"), saving_rate)) + cmd = "octopus_energy/join_octoplus_saving_session_event, event_code={}, entity_id={}".format(code, entity_id) + result = self.call_service_wrapper("octopus_energy/join_octoplus_saving_session_event", event_code=code, entity_id=entity_id) + if result: + if self.get_arg("set_event_notify"): + self.call_notify("Predbat: Joined Octopus saving event {}-{}, {} p/kWh".format(start_time.strftime("%a %d/%m %H:%M"), end_time.strftime("%H:%M"), saving_rate)) + else: + self.log("Warn: Unable to join Octoplus saving event with command {}, result was {}".format(cmd, result)) self.octopus_last_joined_try = self.now_utc # Default saving session rate for when octopoints_per_kwh is not available From e74cc2b3eb10b20b3c3da5b6ceb93cbdacd46172 Mon Sep 17 00:00:00 2001 From: Geoffrey Coan <142018870+gcoan@users.noreply.github.com> Date: Mon, 18 May 2026 23:51:10 +0000 Subject: [PATCH 6/9] #3801 use module name in predbat notifications instead of hard coded 'predbat' --- apps/predbat/axle.py | 2 +- apps/predbat/inverter.py | 22 +++++++++++----------- apps/predbat/octopus.py | 2 +- apps/predbat/output.py | 2 +- apps/predbat/predbat.py | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/apps/predbat/axle.py b/apps/predbat/axle.py index 9abff01ad..c6f4d2b46 100644 --- a/apps/predbat/axle.py +++ b/apps/predbat/axle.py @@ -368,7 +368,7 @@ async def _fetch_byok_event(self): if self.get_arg("set_event_notify"): local_start = start_time.astimezone(self.local_tz) local_end = end_time.astimezone(self.local_tz) - self.call_notify("Predbat: Scheduled Axle VPP event {}-{}, {} p/kWh".format(local_start.strftime("%a %d/%m %H:%M"), local_end.strftime("%H:%M"), self.pence_per_kwh)) + self.call_notify("{}: Scheduled Axle VPP event {}-{}, {} p/kWh".format(self.prefix, local_start.strftime("%a %d/%m %H:%M"), local_end.strftime("%H:%M"), self.pence_per_kwh)) self.cleanup_event_history() self.publish_axle_event() diff --git a/apps/predbat/inverter.py b/apps/predbat/inverter.py index baf3fd7a9..7b9c9a659 100644 --- a/apps/predbat/inverter.py +++ b/apps/predbat/inverter.py @@ -116,7 +116,7 @@ def auto_restart(self, reason): self.log("Warn: Calling restart service {}".format(service)) self.base.call_service_wrapper(service) if self.base.get_arg("set_system_notify"): - self.base.call_notify("Auto-restart service {} called due to: {}".format(service, reason)) + self.base.call_notify("{}: Auto-restart service {} called due to: {}".format(self.base.prefix, service, reason)) self.sleep(15) raise Exception("Auto-restart triggered") else: @@ -1620,7 +1620,7 @@ def adjust_reserve(self, reserve): else: self.write_and_poll_value("reserve", self.base.get_arg("reserve", indirect=False, index=self.id, required_unit="%"), reserve) if self.base.set_inverter_notify: - self.base.call_notify("Predbat: Inverter {} Target Reserve has been changed to {}% at {}".format(self.id, dp0(reserve), self.base.time_now_str())) + self.base.call_notify("{}: Inverter {} Target Reserve has been changed to {}% at {}".format(self.base.prefix, self.id, dp0(reserve), self.base.time_now_str())) self.mqtt_message(topic="set/reserve", payload=reserve) else: self.base.log("Inverter {} Current reserve is {}%, already at target".format(self.id, dp0(current_reserve))) @@ -1702,7 +1702,7 @@ def adjust_charge_rate(self, new_rate, notify=True): self.set_current_from_power("charge", new_rate) if notify and self.base.set_inverter_notify: - self.base.call_notify("Predbat: Inverter {} charge rate changes to {}W at {}".format(self.id, new_rate, self.base.time_now_str())) + self.base.call_notify("{}: Inverter {} charge rate changes to {}W at {}".format(self.base.prefix, self.id, new_rate, self.base.time_now_str())) self.mqtt_message(topic="set/charge_rate", payload=new_rate) def adjust_discharge_rate(self, new_rate, notify=True): @@ -1740,7 +1740,7 @@ def adjust_discharge_rate(self, new_rate, notify=True): self.set_current_from_power("discharge", new_rate) if notify and self.base.set_inverter_notify: - self.base.call_notify("Predbat: Inverter {} discharge rate changes to {}W at {}".format(self.id, new_rate, self.base.time_now_str())) + self.base.call_notify("{}: Inverter {} discharge rate changes to {}W at {}".format(self.base.prefix, self.id, new_rate, self.base.time_now_str())) self.mqtt_message(topic="set/discharge_rate", payload=new_rate) def adjust_battery_target(self, soc, isCharging=False, isExporting=False): @@ -1786,7 +1786,7 @@ def adjust_battery_target(self, soc, isCharging=False, isExporting=False): self.press_and_poll_button() if self.base.set_inverter_notify: - self.base.call_notify("Predbat: Inverter {} Target SoC has been changed to {}% at {}".format(self.id, soc, self.base.time_now_str())) + self.base.call_notify("{}: Inverter {} Target SoC has been changed to {}% at {}".format(self.base.prefix, self.id, soc, self.base.time_now_str())) self.mqtt_message(topic="set/target_soc", payload=soc) else: self.base.log("Inverter {} Current Target SoC is {}%, already at target".format(self.id, current_soc)) @@ -2037,7 +2037,7 @@ def adjust_pause_mode(self, pause_charge=False, pause_discharge=False): self.write_and_poll_option("pause_mode", entity_mode, new_pause_mode) if self.base.set_inverter_notify: - self.base.call_notify("Predbat: Inverter {} pause mode to set {} at time {}".format(self.id, new_pause_mode, self.base.time_now_str())) + self.base.call_notify("{}: Inverter {} pause mode to set {} at time {}".format(self.base.prefix, self.id, new_pause_mode, self.base.time_now_str())) self.base.log("Inverter {} set pause mode to {}".format(self.id, new_pause_mode)) @@ -2110,7 +2110,7 @@ def adjust_inverter_mode(self, force_export, changed_start_end=False): # Notify if self.base.set_inverter_notify: - self.base.call_notify("Predbat: Inverter {} Force export set to {} at time {}".format(self.id, force_export, self.base.time_now_str())) + self.base.call_notify("{}: Inverter {} Force export set to {} at time {}".format(self.base.prefix, self.id, force_export, self.base.time_now_str())) self.base.log("Inverter {} set force export to {}".format(self.id, force_export)) @@ -2396,7 +2396,7 @@ def adjust_force_export(self, force_export, new_start_time=None, new_end_time=No # Notify if changed_start_end: if self.base.set_inverter_notify: - self.base.call_notify("Predbat: Inverter {} Export time slot set to {} - {} at time {}".format(self.id, new_start, new_end, self.base.time_now_str())) + self.base.call_notify("{}: Inverter {} Export time slot set to {} - {} at time {}".format(self.base.prefix, self.id, new_start, new_end, self.base.time_now_str())) def disable_charge_window(self, notify=True): """ @@ -2444,7 +2444,7 @@ def disable_charge_window(self, notify=True): self.enable_charge_discharge_with_time_current("charge", False) if self.base.set_inverter_notify and notify: - self.base.call_notify("Predbat: Inverter {} Disabled scheduled charging at {}".format(self.id, self.base.time_now_str())) + self.base.call_notify("{}: Inverter {} Disabled scheduled charging at {}".format(self.base.prefix, self.id, self.base.time_now_str())) self.base.log("Inverter {} Turning off scheduled charge".format(self.id)) @@ -2807,7 +2807,7 @@ def adjust_charge_window(self, charge_start_time, charge_end_time, minutes_now): self.rest_setChargeSlot1(new_start, new_end) if self.base.set_inverter_notify: - self.base.call_notify("Predbat: Inverter {} Charge window change to: {} - {} at {}".format(self.id, new_start, new_end, self.base.time_now_str())) + self.base.call_notify("{}: Inverter {} Charge window change to: {} - {} at {}".format(self.base.prefix, self.id, new_start, new_end, self.base.time_now_str())) self.base.log("Inverter {} Updated start and end charge window to {} - {} (old {} - {})".format(self.id, new_start, new_end, old_start, old_end)) if (old_charge_schedule_enable == "off" or have_disabled) and (new_start != new_end): @@ -2824,7 +2824,7 @@ def adjust_charge_window(self, charge_start_time, charge_end_time, minutes_now): # Only notify if it's a real change and not a temporary one if old_charge_schedule_enable == "off" and self.base.set_inverter_notify: - self.base.call_notify("Predbat: Inverter {} Enabling scheduled charging at {}".format(self.id, self.base.time_now_str())) + self.base.call_notify("{}: Inverter {} Enabling scheduled charging at {}".format(self.base.prefix, self.id, self.base.time_now_str())) self.charge_enable_time = True diff --git a/apps/predbat/octopus.py b/apps/predbat/octopus.py index 154903de4..c686a4a23 100644 --- a/apps/predbat/octopus.py +++ b/apps/predbat/octopus.py @@ -2824,7 +2824,7 @@ def fetch_octopus_sessions(self): result = self.call_service_wrapper("octopus_energy/join_octoplus_saving_session_event", event_code=code, entity_id=entity_id) if result: if self.get_arg("set_event_notify"): - self.call_notify("Predbat: Joined Octopus saving event {}-{}, {} p/kWh".format(start_time.strftime("%a %d/%m %H:%M"), end_time.strftime("%H:%M"), saving_rate)) + self.call_notify("{}: Joined Octopus saving event {}-{}, {} p/kWh".format(self.prefix, start_time.strftime("%a %d/%m %H:%M"), end_time.strftime("%H:%M"), saving_rate)) else: self.log("Warn: Unable to join Octoplus saving event with command {}, result was {}".format(cmd, result)) self.octopus_last_joined_try = self.now_utc diff --git a/apps/predbat/output.py b/apps/predbat/output.py index b9c18af2b..e9221b251 100644 --- a/apps/predbat/output.py +++ b/apps/predbat/output.py @@ -2412,7 +2412,7 @@ def record_status(self, message, debug="", had_errors=False, notify=False, extra # Already in error state, do not notify second error in a single run (spam) pass else: - self.call_notify("Predbat status change to: " + message + extra) + self.call_notify("{} status change to: {} {}".format(self.prefix, message, extra)) self.previous_status = message error_count = self.get_state_wrapper(self.prefix + ".status", attribute="error_count", default=0) diff --git a/apps/predbat/predbat.py b/apps/predbat/predbat.py index 9ebd86ee0..3e59a6ce0 100644 --- a/apps/predbat/predbat.py +++ b/apps/predbat/predbat.py @@ -1174,7 +1174,7 @@ def download_predbat_version(self, version): if files: # Notify before killing threads so the WebSocket is still healthy if self.get_arg("set_system_notify"): - self.call_notify("Predbat: update to: {}".format(version)) + self.call_notify("{}: update to: {}".format(self.prefix, version)) # Kill the current threads self.log("Kill current threads before update") From 875cb5151d2af0dfd8c1f2f1316c0b0ecd9dcacb Mon Sep 17 00:00:00 2001 From: Geoffrey Coan <142018870+gcoan@users.noreply.github.com> Date: Thu, 21 May 2026 14:36:06 +0000 Subject: [PATCH 7/9] capitalise predbat prefix in alert notifications --- apps/predbat/axle.py | 3 ++- apps/predbat/inverter.py | 22 +++++++++++----------- apps/predbat/octopus.py | 3 ++- apps/predbat/output.py | 2 +- apps/predbat/predbat.py | 2 +- apps/predbat/userinterface.py | 6 +++--- 6 files changed, 20 insertions(+), 18 deletions(-) diff --git a/apps/predbat/axle.py b/apps/predbat/axle.py index c6f4d2b46..8d8f6de9b 100644 --- a/apps/predbat/axle.py +++ b/apps/predbat/axle.py @@ -368,7 +368,8 @@ async def _fetch_byok_event(self): if self.get_arg("set_event_notify"): local_start = start_time.astimezone(self.local_tz) local_end = end_time.astimezone(self.local_tz) - self.call_notify("{}: Scheduled Axle VPP event {}-{}, {} p/kWh".format(self.prefix, local_start.strftime("%a %d/%m %H:%M"), local_end.strftime("%H:%M"), self.pence_per_kwh)) + msg = "Scheduled Axle VPP event " + local_start.strftime("%a %d/%m %H:%M") + "-" + local_end.strftime("%H:%M") + self.pence_per_kwh + " p/kWh" + self.call_notify(f"{self.prefix.capitalize()}: {msg}") self.cleanup_event_history() self.publish_axle_event() diff --git a/apps/predbat/inverter.py b/apps/predbat/inverter.py index 7b9c9a659..fb813d12c 100644 --- a/apps/predbat/inverter.py +++ b/apps/predbat/inverter.py @@ -116,7 +116,7 @@ def auto_restart(self, reason): self.log("Warn: Calling restart service {}".format(service)) self.base.call_service_wrapper(service) if self.base.get_arg("set_system_notify"): - self.base.call_notify("{}: Auto-restart service {} called due to: {}".format(self.base.prefix, service, reason)) + self.base.call_notify(f"{self.base.prefix.capitalize()}: Auto-restart service {service} called due to: {reason}") self.sleep(15) raise Exception("Auto-restart triggered") else: @@ -1620,7 +1620,7 @@ def adjust_reserve(self, reserve): else: self.write_and_poll_value("reserve", self.base.get_arg("reserve", indirect=False, index=self.id, required_unit="%"), reserve) if self.base.set_inverter_notify: - self.base.call_notify("{}: Inverter {} Target Reserve has been changed to {}% at {}".format(self.base.prefix, self.id, dp0(reserve), self.base.time_now_str())) + self.base.call_notify(f"{self.base.prefix.capitalize()}: Inverter {self.id} Target Reserve has been changed to {dp0(reserve)}% at {self.base.time_now_str()}") self.mqtt_message(topic="set/reserve", payload=reserve) else: self.base.log("Inverter {} Current reserve is {}%, already at target".format(self.id, dp0(current_reserve))) @@ -1702,7 +1702,7 @@ def adjust_charge_rate(self, new_rate, notify=True): self.set_current_from_power("charge", new_rate) if notify and self.base.set_inverter_notify: - self.base.call_notify("{}: Inverter {} charge rate changes to {}W at {}".format(self.base.prefix, self.id, new_rate, self.base.time_now_str())) + self.base.call_notify(f"{self.base.prefix.capitalize()}: Inverter {self.id} charge rate changes to {new_rate}W at {self.base.time_now_str()}") self.mqtt_message(topic="set/charge_rate", payload=new_rate) def adjust_discharge_rate(self, new_rate, notify=True): @@ -1740,7 +1740,7 @@ def adjust_discharge_rate(self, new_rate, notify=True): self.set_current_from_power("discharge", new_rate) if notify and self.base.set_inverter_notify: - self.base.call_notify("{}: Inverter {} discharge rate changes to {}W at {}".format(self.base.prefix, self.id, new_rate, self.base.time_now_str())) + self.base.call_notify(f"{self.base.prefix.capitalize()}: Inverter {self.id} discharge rate changes to {new_rate}W at {self.base.time_now_str()}") self.mqtt_message(topic="set/discharge_rate", payload=new_rate) def adjust_battery_target(self, soc, isCharging=False, isExporting=False): @@ -1786,7 +1786,7 @@ def adjust_battery_target(self, soc, isCharging=False, isExporting=False): self.press_and_poll_button() if self.base.set_inverter_notify: - self.base.call_notify("{}: Inverter {} Target SoC has been changed to {}% at {}".format(self.base.prefix, self.id, soc, self.base.time_now_str())) + self.base.call_notify(f"{self.base.prefix.capitalize()}: Inverter {self.id} Target SoC has been changed to {soc}% at {self.base.time_now_str()}") self.mqtt_message(topic="set/target_soc", payload=soc) else: self.base.log("Inverter {} Current Target SoC is {}%, already at target".format(self.id, current_soc)) @@ -2037,7 +2037,7 @@ def adjust_pause_mode(self, pause_charge=False, pause_discharge=False): self.write_and_poll_option("pause_mode", entity_mode, new_pause_mode) if self.base.set_inverter_notify: - self.base.call_notify("{}: Inverter {} pause mode to set {} at time {}".format(self.base.prefix, self.id, new_pause_mode, self.base.time_now_str())) + self.base.call_notify(f"{self.base.prefix.capitalize()}: Inverter {self.id} pause mode to set {new_pause_mode} at time {self.base.time_now_str()}") self.base.log("Inverter {} set pause mode to {}".format(self.id, new_pause_mode)) @@ -2110,7 +2110,7 @@ def adjust_inverter_mode(self, force_export, changed_start_end=False): # Notify if self.base.set_inverter_notify: - self.base.call_notify("{}: Inverter {} Force export set to {} at time {}".format(self.base.prefix, self.id, force_export, self.base.time_now_str())) + self.base.call_notify(f"{self.base.prefix.capitalize()}: Inverter {self.id} Force export set to {force_export} at time {self.base.time_now_str()}") self.base.log("Inverter {} set force export to {}".format(self.id, force_export)) @@ -2396,7 +2396,7 @@ def adjust_force_export(self, force_export, new_start_time=None, new_end_time=No # Notify if changed_start_end: if self.base.set_inverter_notify: - self.base.call_notify("{}: Inverter {} Export time slot set to {} - {} at time {}".format(self.base.prefix, self.id, new_start, new_end, self.base.time_now_str())) + self.base.call_notify(f"{self.base.prefix.capitalize()}: Inverter {self.id} Export time slot set to {new_start} - {new_end} at time {self.base.time_now_str()}") def disable_charge_window(self, notify=True): """ @@ -2444,7 +2444,7 @@ def disable_charge_window(self, notify=True): self.enable_charge_discharge_with_time_current("charge", False) if self.base.set_inverter_notify and notify: - self.base.call_notify("{}: Inverter {} Disabled scheduled charging at {}".format(self.base.prefix, self.id, self.base.time_now_str())) + self.base.call_notify(f"{self.base.prefix.capitalize()}: Inverter {self.id} Disabled scheduled charging at {self.base.time_now_str()}") self.base.log("Inverter {} Turning off scheduled charge".format(self.id)) @@ -2807,7 +2807,7 @@ def adjust_charge_window(self, charge_start_time, charge_end_time, minutes_now): self.rest_setChargeSlot1(new_start, new_end) if self.base.set_inverter_notify: - self.base.call_notify("{}: Inverter {} Charge window change to: {} - {} at {}".format(self.base.prefix, self.id, new_start, new_end, self.base.time_now_str())) + self.base.call_notify(f"{self.base.prefix.capitalize()}: Inverter {self.id} Charge window change to: {new_start} - {new_end} at {self.base.time_now_str()}") self.base.log("Inverter {} Updated start and end charge window to {} - {} (old {} - {})".format(self.id, new_start, new_end, old_start, old_end)) if (old_charge_schedule_enable == "off" or have_disabled) and (new_start != new_end): @@ -2824,7 +2824,7 @@ def adjust_charge_window(self, charge_start_time, charge_end_time, minutes_now): # Only notify if it's a real change and not a temporary one if old_charge_schedule_enable == "off" and self.base.set_inverter_notify: - self.base.call_notify("{}: Inverter {} Enabling scheduled charging at {}".format(self.base.prefix, self.id, self.base.time_now_str())) + self.base.call_notify(f"{self.base.prefix.capitalize()}: Inverter {self.id} Enabling scheduled charging at {self.base.time_now_str()}") self.charge_enable_time = True diff --git a/apps/predbat/octopus.py b/apps/predbat/octopus.py index c686a4a23..d539bc025 100644 --- a/apps/predbat/octopus.py +++ b/apps/predbat/octopus.py @@ -2824,7 +2824,8 @@ def fetch_octopus_sessions(self): result = self.call_service_wrapper("octopus_energy/join_octoplus_saving_session_event", event_code=code, entity_id=entity_id) if result: if self.get_arg("set_event_notify"): - self.call_notify("{}: Joined Octopus saving event {}-{}, {} p/kWh".format(self.prefix, start_time.strftime("%a %d/%m %H:%M"), end_time.strftime("%H:%M"), saving_rate)) + msg = "Joined Octopus saving event " + start_time.strftime("%a %d/%m %H:%M") + "-" + end_time.strftime("%H:%M") ", " + saving_rate + " p/kWh" + self.call_notify(f"{self.prefix.capitalize()}: {msg}") else: self.log("Warn: Unable to join Octoplus saving event with command {}, result was {}".format(cmd, result)) self.octopus_last_joined_try = self.now_utc diff --git a/apps/predbat/output.py b/apps/predbat/output.py index e9221b251..32312593a 100644 --- a/apps/predbat/output.py +++ b/apps/predbat/output.py @@ -2412,7 +2412,7 @@ def record_status(self, message, debug="", had_errors=False, notify=False, extra # Already in error state, do not notify second error in a single run (spam) pass else: - self.call_notify("{} status change to: {} {}".format(self.prefix, message, extra)) + self.call_notify(f"{self.prefix.capitalize()} status change to: {message} {extra}") self.previous_status = message error_count = self.get_state_wrapper(self.prefix + ".status", attribute="error_count", default=0) diff --git a/apps/predbat/predbat.py b/apps/predbat/predbat.py index 3e59a6ce0..18f195ede 100644 --- a/apps/predbat/predbat.py +++ b/apps/predbat/predbat.py @@ -1174,7 +1174,7 @@ def download_predbat_version(self, version): if files: # Notify before killing threads so the WebSocket is still healthy if self.get_arg("set_system_notify"): - self.call_notify("{}: update to: {}".format(self.prefix, version)) + self.call_notify(f"{self.prefix.capitalize()}: update to: {version}") # Kill the current threads self.log("Kill current threads before update") diff --git a/apps/predbat/userinterface.py b/apps/predbat/userinterface.py index c8a307921..249a9a906 100644 --- a/apps/predbat/userinterface.py +++ b/apps/predbat/userinterface.py @@ -605,7 +605,7 @@ async def async_restore_settings_yaml(self, filename): self.log("Restore setting: {} = {} (was {})".format(item["name"], item["default"], item["value"])) await self.async_expose_config(item["name"], item["default"], event=True) if self.get_arg("set_system_notify"): - await self.async_call_notify("Predbat settings restored from default") + await self.async_call_notify(f"{self.prefix.capitalize()} settings restored from default") else: filepath = os.path.join(self.save_restore_dir, filename) if os.path.exists(filepath): @@ -620,7 +620,7 @@ async def async_restore_settings_yaml(self, filename): self.log("Restore setting: {} = {} (was {})".format(item["name"], item["value"], current["value"])) await self.async_expose_config(item["name"], item["value"], event=True) if self.get_arg("set_system_notify"): - await self.async_call_notify("Predbat settings restored from {}".format(filename)) + await self.async_call_notify(f"{self.prefix.capitalize()} settings restored from {filename}") await self.async_expose_config("saverestore", None) def load_current_config(self): @@ -692,7 +692,7 @@ async def async_save_settings_yaml(self, filename=None): yaml.dump(self.CONFIG_ITEMS, file) self.log("Saved Predbat settings to {}".format(filepath_p)) if self.get_arg("set_system_notify"): - await self.async_call_notify("Predbat settings saved to {}".format(filename)) + await self.async_call_notify(f"{self.prefix.capitalize()} settings saved to {filename}") def read_debug_yaml(self, filename): """ From 49fe9062cf6cd082a4ceab94bfbfa303a6a797a5 Mon Sep 17 00:00:00 2001 From: Geoffrey Coan <142018870+gcoan@users.noreply.github.com> Date: Thu, 21 May 2026 14:39:51 +0000 Subject: [PATCH 8/9] Updated plan doc to include Axle in $ prefix --- apps/predbat/octopus.py | 2 +- docs/predbat-plan-card.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/predbat/octopus.py b/apps/predbat/octopus.py index d539bc025..241417d5d 100644 --- a/apps/predbat/octopus.py +++ b/apps/predbat/octopus.py @@ -2824,7 +2824,7 @@ def fetch_octopus_sessions(self): result = self.call_service_wrapper("octopus_energy/join_octoplus_saving_session_event", event_code=code, entity_id=entity_id) if result: if self.get_arg("set_event_notify"): - msg = "Joined Octopus saving event " + start_time.strftime("%a %d/%m %H:%M") + "-" + end_time.strftime("%H:%M") ", " + saving_rate + " p/kWh" + msg = "Joined Octopus saving event " + start_time.strftime("%a %d/%m %H:%M") + "-" + end_time.strftime("%H:%M") + ", " + saving_rate + " p/kWh" self.call_notify(f"{self.prefix.capitalize()}: {msg}") else: self.log("Warn: Unable to join Octoplus saving event with command {}, result was {}".format(cmd, result)) diff --git a/docs/predbat-plan-card.md b/docs/predbat-plan-card.md index ebeb7fa8f..b51cb2a3a 100644 --- a/docs/predbat-plan-card.md +++ b/docs/predbat-plan-card.md @@ -53,9 +53,9 @@ Rate symbols (import and export): - ? ⅆ - Rate that has been modified based on **input_number.predbat_metric_future_rate_offset_import** or **input_number.predbat_metric_future_rate_offset_export** - ? ⚖ - Rate that has been estimated using future rate estimation data (e.g. Nordpool) -- = - Rate that has been overridden by the user's apps.yaml -- ± - Rate that has been adjusted with a rate offset in the user's apps.yaml -- $ - Rate that has been adjusted for an Octopus Saving session +- = - Rate that has been overridden by the user's `apps.yaml` +- ± - Rate that has been adjusted with a rate offset in the user's `apps.yaml` +- $ - Rate that has been adjusted for an Octopus Saving session or Axle event - ? - Rate that has not yet been defined and the previous day's data was used instead Battery SoC symbols: From 5ebaf3d1d3c936add56e2368ff8867a95023821b Mon Sep 17 00:00:00 2001 From: Geoffrey Coan <142018870+gcoan@users.noreply.github.com> Date: Thu, 21 May 2026 22:49:03 +0000 Subject: [PATCH 9/9] fix sigenergy, luxpower and kostal inverter setup formatting issues --- docs/inverter-setup.md | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/docs/inverter-setup.md b/docs/inverter-setup.md index 28ae8441a..4fae2494f 100644 --- a/docs/inverter-setup.md +++ b/docs/inverter-setup.md @@ -589,7 +589,7 @@ Max value: (Inverter Battery max charge in watt) input_number.predbat_discharge_rate # this is used to set battery discharge to zero Min value: 0 Max value: (Inverter Battery max discharge in watt) -```text +``` - To control the Kostal inverter you need to use a modbus/tcp connection, this is not a part of the Kostal integration. Add the following modbus configuration to your `configuration.yaml`: @@ -1348,8 +1348,7 @@ triggers: entity_id: automation.luxpower_freeze_charge_watchdog mode: single - - ``` +``` **Enable Freeze Charging** @@ -1367,7 +1366,7 @@ If you have a LuxPower inverter with the **Charge Last** feature, enable the Pre **Note** Freeze Exporting requires fewer supporting automations than Freeze Charging, as it relies primarily on inverter-side behaviour. No additional watchdog or guard logic is required. - In your `apps.yaml` file: +In your `apps.yaml` file: - Look for `support_discharge_freeze` in the inverter section and change `False` to `True` - Uncomment the last two lines of the `discharge_stop_service` section so Predbat turns `switch.lux_charge_last` off when Freeze exporting stops. @@ -1390,7 +1389,7 @@ After Predbat recomputes, you may see some dark grey **FrzExp** slots in the sta ```yaml name: Predbat Ready entity_id: input_boolean.predbat_ready -```text +``` The `predbat_ready` helper prevents automation actions until LuxPower entities are fully available after startup. Ensure it is On after it has been created. @@ -1663,20 +1662,20 @@ Add the following automations to `automations.yaml` (or configure via the UI): entity_id: number.sigen_plant_grid_import_limitation value: 100 - - id: automation_sigen_ess_max_charging_limit_input_number_action - alias: Predbat max charging limit action - description: Mapper from input_number.charge_rate to number sigen_plant_ess_max_charging_limit - triggers: - - trigger: state - entity_id: input_number.charge_rate - actions: - - action: number.set_value - target: - entity_id: number.sigen_plant_ess_max_charging_limit - data: - value: '{{ [(states(''input_number.charge_rate'') | float / 1000) | round(2), - states(''sensor.sigen_inverter_ess_rated_charging_power'') | float] | min}}' - mode: single +- id: automation_sigen_ess_max_charging_limit_input_number_action + alias: Predbat max charging limit action + description: Mapper from input_number.charge_rate to number sigen_plant_ess_max_charging_limit + triggers: + - trigger: state + entity_id: input_number.charge_rate + actions: + - action: number.set_value + target: + entity_id: number.sigen_plant_ess_max_charging_limit + data: + value: '{{ [(states(''input_number.charge_rate'') | float / 1000) | round(2), + states(''sensor.sigen_inverter_ess_rated_charging_power'') | float] | min}}' + mode: single - id: automation_sigen_ess_max_discharging_limit_input_number_action alias: Predbat max discharging limit action