Skip to content

Commit

Permalink
Merge pull request #294 from fboundy/solis-cloud
Browse files Browse the repository at this point in the history
Solis cloud tweaks
  • Loading branch information
fboundy authored Nov 15, 2024
2 parents 96cc6fb + 4a80957 commit 9c11da3
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 18 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# PV Opt: Home Assistant Solar/Battery Optimiser v3.18.0
# PV Opt: Home Assistant Solar/Battery Optimiser v3.18.1

<h2>This documentation needs updating!</h2>

Expand Down
31 changes: 23 additions & 8 deletions apps/pv_opt/pv_opt.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from numpy import nan
import re

VERSION = "3.18.0"
VERSION = "3.18.1"


OCTOPUS_PRODUCT_URL = r"https://api.octopus.energy/v1/products/"
Expand Down Expand Up @@ -464,7 +464,7 @@ def initialize(self):
self.log("")
self.log(f"******************* PV Opt v{VERSION} *******************")
self.log("")

self.io = False
self.debug = DEBUG
self.redact_regex = REDACT_REGEX

Expand Down Expand Up @@ -599,6 +599,7 @@ def _run_test(self):
self._log_inverterstatus(self.inverter.status)

def _check_for_io(self):
self.io = False
self.ulog("Checking for Intelligent Octopus")
entity_id = f"binary_sensor.octopus_energy_{self.get_config('octopus_account').lower().replace('-', '_')}_intelligent_dispatching"
io_dispatches = self.get_state(entity_id)
Expand Down Expand Up @@ -725,7 +726,7 @@ def _load_pv_system_model(self):

self.battery_model = pv.BatteryModel(
capacity=self.get_config("battery_capacity_wh"),
max_dod=self.get_config("maximum_dod_percent") / 100,
max_dod=self.get_config("maximum_dod_percent", 15) / 100,
current_limit_amps=self.get_config("battery_current_limit_amps", default=100),
voltage=self.get_config("battery_voltage", default=50),
)
Expand Down Expand Up @@ -989,6 +990,7 @@ def _load_contract(self):

self.rlog("")
self._load_saving_events()

self._check_for_io()

self.rlog("Finished loading contract")
Expand Down Expand Up @@ -1564,8 +1566,10 @@ def _expose_configs(self, over_write=True):
)

def status(self, status):
entity_id = f"sensor.{self.prefix.lower()}status"
entity_id = f"sensor.{self.prefix.lower()}_status"
attributes = {"last_updated": pd.Timestamp.now().strftime(DATE_TIME_FORMAT_LONG)}
# self.log(f">>> {status}")
# self.log(f">>> {entity_id}")
self.set_state(state=status, entity_id=entity_id, attributes=attributes)

@ad.app_lock
Expand Down Expand Up @@ -2300,9 +2304,16 @@ def _write_output(self):
attributes={"Summary": self.summary_costs},
)

if len(self.windows) > 0:
hass_start = self.charge_start_datetime
hass_end = self.charge_end_datetime
else:
hass_start = pd.Timestamp.now().floor("1D")
hass_end = hass_start

self.write_to_hass(
entity=f"sensor.{self.prefix}_charge_start",
state=self.charge_start_datetime,
state=hass_start,
attributes={
"friendly_name": "PV Opt Next Charge Period Start",
"device_class": "timestamp",
Expand All @@ -2325,7 +2336,7 @@ def _write_output(self):

self.write_to_hass(
entity=f"sensor.{self.prefix}_charge_end",
state=self.charge_end_datetime,
state=hass_end,
attributes={
"friendly_name": "PV Opt Next Charge Period End",
},
Expand Down Expand Up @@ -2582,8 +2593,12 @@ def load_consumption(self, start, end):
consumption_dow = self.get_config("day_of_week_weighting") * dfx.iloc[: len(temp)]
if len(consumption_dow) != len(consumption_mean):
self.log(">>> Inconsistent lengths in consumption arrays")
self.log(f">>> dow : {consumption_dow}")
self.log(f">>> mean: {consumption_mean}")
self.log(f">>> dow : {len(consumption_dow)}")
self.log(f">>> mean: {len(consumption_mean)}")
idx = consumption_dow.index.intersection(consumption_mean.index)
self.log(f"Clipping the consumption to the overlap ({len(idx)/24:0.1f} days)", level="WARNING")
consumption_mean = consumption_mean.loc[idx]
consumption_dow = consumption_dow.loc[idx]

consumption["consumption"] += pd.Series(
consumption_dow.to_numpy()
Expand Down
33 changes: 24 additions & 9 deletions apps/pv_opt/solis.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,8 @@ class SolisCloud:
"atRead": "/v2/api/atRead",
}

MAX_RETRIES = 5

def __init__(self, username, password, key_id, key_secret, plant_id, **kwargs):
self.username = username
self.key_id = key_id
Expand Down Expand Up @@ -321,6 +323,8 @@ def inverter_details(self):

if response.status_code == HTTPStatus.OK:
return response.json()["data"]
else:
return {"state": 0}

@property
def is_online(self):
Expand All @@ -331,14 +335,25 @@ def last_seen(self):
return pd.to_datetime(int(self.inverter_details["dataTimestamp"]), unit="ms")

def read_code(self, cid):
if self.token == "":
self.login()
body = self.get_body(inverterSn=self.inverter_sn, cid=cid)
headers = self.header(body, self.URLS["atRead"])
headers["token"] = self.token
response = requests.post(self.URLS["root"] + self.URLS["atRead"], data=body, headers=headers)
if response.status_code == HTTPStatus.OK:
return response.json()["data"]["msg"]
retries = 0
data = "ERROR"
while (data == "ERROR") and (retries < self.MAX_RETRIES):
if self.token == "":
self.login()
body = self.get_body(inverterSn=self.inverter_sn, cid=cid)
headers = self.header(body, self.URLS["atRead"])
headers["token"] = self.token
response = requests.post(self.URLS["root"] + self.URLS["atRead"], data=body, headers=headers)
if response.status_code == HTTPStatus.OK:
data = response.json()["data"]["msg"]
else:
data = "ERROR"

if data == "ERROR":
self.token = ""
retries += 1
else:
return data

def set_code(self, cid, value):
if self.token == "":
Expand Down Expand Up @@ -547,7 +562,7 @@ def _solis_control_charge_discharge(self, direction, enable, **kwargs):
"start": kwargs.get("start", None),
"end": kwargs.get("end", None),
}
power = kwargs.get("power")
power = kwargs.get("power", 0)

if times["start"] is not None:
times["start"] = times["start"].floor("1min")
Expand Down

0 comments on commit 9c11da3

Please sign in to comment.