From b3424d60198a8f789ce47af1d9946bbe5fdf645f Mon Sep 17 00:00:00 2001 From: fboundy Date: Thu, 15 Aug 2024 16:02:57 +0100 Subject: [PATCH 1/2] Fix #257 and partial fix for #261 --- apps/pv_opt/.test.py | 50 +++++++++++++++++++++++++++++++++++++++++++ apps/pv_opt/pv_opt.py | 6 +++++- apps/pv_opt/solax.py | 7 +++++- 3 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 apps/pv_opt/.test.py diff --git a/apps/pv_opt/.test.py b/apps/pv_opt/.test.py new file mode 100644 index 0000000..09a7f05 --- /dev/null +++ b/apps/pv_opt/.test.py @@ -0,0 +1,50 @@ +# %% +import pandas as pd +import numpy as np +import requests +from datetime import datetime +from datetime import time +import matplotlib.pyplot as plt +import yaml +from influxdb_client import InfluxDBClient, Point +from influxdb_client.client.write_api import SYNCHRONOUS + +import pvpy as pvpy + +entities = [ + "pv_total_power", + "battery_input_energy", + "battery_output_energy", + "grid_import_power", + "grid_export_power", + "bypass_load", + "house_load", +] + +token = "C1JXqu3wKSKVzGKs3n3Hu7sx1SG2L0RV8cjzt6gLUogh6DAfoik-aOMGJD8L1ZJm1Pj0JDWhTNw8brRem5aXpw==" +org = "ToppinHouse" +url = "http://192.168.4.181:8086" +bucket = "ToppinHouse" + +write_client = InfluxDBClient(url=url, token=token, org=org) +# Initialize the InfluxDB client +client = InfluxDBClient(url=url, token=token, org=org) +query_api = client.query_api() + +series = [] +for entity in entities: + query = f'from(bucket: "{bucket}") |> range(start: -36h) |> filter(fn: (r) => r.entity_id == "solis_{entity}")' + + # Execute the query + result = query_api.query(org=org, query=query) + + # Process the results + data = [{"Time": record.get_time(), "Value": record.get_value()} for record in result[-1].records] + series += [pd.DataFrame(data)] + series[-1] = series[-1].set_index("Time").resample("1min").mean().fillna(0)["Value"].rename(entity) +df = pd.concat(series, axis=1) +df = df.resample("5min").mean() +# Close the client +client.close() + +# %% diff --git a/apps/pv_opt/pv_opt.py b/apps/pv_opt/pv_opt.py index 6740668..9a517a0 100644 --- a/apps/pv_opt/pv_opt.py +++ b/apps/pv_opt/pv_opt.py @@ -2172,7 +2172,11 @@ def write_cost( "consumption", ] - cost = pd.DataFrame(pd.concat([cost_today, cost])).set_axis(["cost"], axis=1).fillna(0) + cost = ( + pd.DataFrame(pd.concat([df for df in [cost_today, cost] if len(df) > 0])) + .set_axis(["cost"], axis=1) + .fillna(0) + ) cost["cumulative_cost"] = cost["cost"].cumsum() for d in [df, cost]: diff --git a/apps/pv_opt/solax.py b/apps/pv_opt/solax.py index a3d7766..3eb5cbb 100644 --- a/apps/pv_opt/solax.py +++ b/apps/pv_opt/solax.py @@ -5,6 +5,7 @@ LIMITS = ["start", "end"] DIRECTIONS = ["charge"] WRITE_POLL_SLEEP_DURATION = 0.5 +BATTERY_VOLTAGE_DEFAULT = 100.0 INVERTER_DEFS = { "SOLAX_X1": { @@ -109,7 +110,11 @@ def control_charge(self, enable, **kwargs): power = kwargs.get("power") if power is not None: entity_id = self.host.config[f"id_max_charge_current"] - current = abs(round(power / self.host.get_config("battery_voltage"), 1)) + voltage = self.host.get_config("battery_voltage") + if voltage == 0: + voltage = BATTERY_VOLTAGE_DEFAULT + self.log(f"Read a battery voltage of zero. Assuming default of {BATTERY_VOLTAGE_DEFAULT}") + current = abs(round(power / voltage, 1)) current = min(current, self.host.get_config("battery_current_limit_amps")) self.log(f"Power {power:0.0f} = {current:0.1f}A at {self.host.get_config('battery_voltage')}V") From 74e09db681e14e88c12a30020ff01d95cf5419ce Mon Sep 17 00:00:00 2001 From: fboundy Date: Thu, 15 Aug 2024 16:17:34 +0100 Subject: [PATCH 2/2] 3.15.5 --- README.md | 3 ++- apps/pv_opt/pv_opt.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bd9692c..8724332 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ -# PV Opt: Home Assistant Solar/Battery Optimiser v3.15.4 +# PV Opt: Home Assistant Solar/Battery Optimiser v3.15.5 +

This documentation needs updating!

Solar / Battery Charging Optimisation for Home Assistant. This appDaemon application attempts to optimise charging and discharging of a home solar/battery system to minimise cost electricity cost on a daily basis using freely available solar forecast data from SolCast. This is particularly beneficial for Octopus Agile but is also benefeficial for other time-of-use tariffs such as Octopus Flux or simple Economy 7. diff --git a/apps/pv_opt/pv_opt.py b/apps/pv_opt/pv_opt.py index 9a517a0..2ac2468 100644 --- a/apps/pv_opt/pv_opt.py +++ b/apps/pv_opt/pv_opt.py @@ -12,7 +12,7 @@ from numpy import nan import re -VERSION = "3.15.4" +VERSION = "3.15.5" OCTOPUS_PRODUCT_URL = r"https://api.octopus.energy/v1/products/"