Skip to content

Commit

Permalink
[ skip ci ] adjustments to qos and retain flags, bigfix for inverter …
Browse files Browse the repository at this point in the history
…mode changes, (pseudo)randomize client id, formatting
  • Loading branch information
JoshuaDodds committed Apr 7, 2024
1 parent 167fc1a commit 932ee4a
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 16 deletions.
3 changes: 2 additions & 1 deletion lib/clients/mqtt_client_factory.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import json
import threading
import time
import random
import paho.mqtt.client as mqtt

from lib.constants import retrieve_mqtt_subcribed_topics, logging, DzEndpoints, cerboGxEndpoint, systemId0
Expand All @@ -17,7 +18,7 @@ def __new__(cls, *args, **kwargs):
cls._instance = super(VictronClient, cls).__new__(cls)
return cls._instance

def __init__(self, client_id="victron_client", host=cerboGxEndpoint, keepalive=45, port=1883):
def __init__(self, client_id=f"victron_client-{random.randint(100000, 999999)}", host=cerboGxEndpoint, keepalive=45, port=1883):
# To prevent re-initialization if __init__ is called again
if hasattr(self, '_initialized') and self._initialized:
return
Expand Down
15 changes: 8 additions & 7 deletions lib/energy_broker.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import time
import schedule as scheduler

from lib.constants import logging, systemId0, PythonToVictronWeekdayNumberConversion, dotenv_config
from paho.mqtt import publish
from lib.constants import logging, systemId0, PythonToVictronWeekdayNumberConversion, dotenv_config, cerboGxEndpoint
from lib.helpers import get_seasonally_adjusted_max_charge_slots, calculate_max_discharge_slots_needed, publish_message
from lib.tibber_api import lowest_48h_prices, lowest_24h_prices
from lib.notifications import pushover_notification
Expand Down Expand Up @@ -258,10 +259,10 @@ def schedule_victron_ess_charging(hour, schedule=0, duration=3600, day=0):
soc = 95
start = hour * 3600

publish_message(f"{topic_stub}Duration", payload=f"{{\"value\": {duration}}}", retain=False)
publish_message(f"{topic_stub}Soc", payload=f"{{\"value\": {soc}}}", retain=False)
publish_message(f"{topic_stub}Start", payload=f"{{\"value\": {start}}}", retain=False)
publish_message(f"{topic_stub}Day", payload=f"{{\"value\": {weekday}}}", retain=False)
publish_message(f"{topic_stub}Duration", payload=f"{{\"value\": {duration}}}", retain=True)
publish_message(f"{topic_stub}Soc", payload=f"{{\"value\": {soc}}}", retain=True)
publish_message(f"{topic_stub}Start", payload=f"{{\"value\": {start}}}", retain=True)
publish_message(f"{topic_stub}Day", payload=f"{{\"value\": {weekday}}}", retain=True)

logging.info(f"EnergyBroker: Adding schedule entry for day:{weekday}, duration:{duration}, start: {start}")

Expand All @@ -284,10 +285,10 @@ def set_inverter_mode(mode: int):
1 = charger only mode - inverter will not switch on, batteries will not be discharged
"""
mode_name = {1: "Charging Only Mode", 3: "Normal Inverter Mode"}
topic = f"W/{systemId0}/vebus/276/Mode"
topic = f"W/{systemId0}/vebus/276/Mode" # TODO: move to constants.py

if mode and mode == 1 or mode == 3:
publish_message(topic, payload=f"{{\"value\": {mode}}}", retain=False)
publish.single(topic, payload=f"{{\"value\": {mode}}}", qos=1, retain=False, hostname=cerboGxEndpoint, port=1883)
logging.info(f"EnergyBroker.Utils.set_inverter_mode: {__name__} has set Multiplus-II's mode to {mode_name.get(mode)}")
else:
logging.info(f"EnergyBroker.Utils.set_inverter_mode: {__name__} Error setting mode to {mode_name.get(mode)}. This is not a valid mode.")
5 changes: 4 additions & 1 deletion lib/tesla_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def __init__(self):
logging.info(f"TeslaApi: Init complete.")

def __del__(self):
# self.cleanup()
self.cleanup()
logging.info(f"TeslaApi (__del__): Exiting...")

def update_vehicle_status(self, force=False):
Expand All @@ -58,7 +58,9 @@ def update_vehicle_status(self, force=False):
or force):
logging.debug(
f"TeslaApi(update_vehicle_statue): (called from: {__name__}): retrieving latest vehicle state... Last update was at: {self.last_update_ts_hr}")

vehicle_data = self.get_vehicle_data()

if vehicle_data:
self.get_vehicle_name(vehicle_data)
self.battery_soc(vehicle_data)
Expand All @@ -76,6 +78,7 @@ def update_vehicle_status(self, force=False):
self.update_mqtt_and_domoticz()
else:
logging.info(f"TeslaApi: Connection timed out. Last update was at: {self.last_update_ts_hr}")

else:
logging.info(f"TeslaApi: Last vehicle status update was at: {self.last_update_ts_hr}. Skipping new request to mothership (Tesla API)")

Expand Down
14 changes: 7 additions & 7 deletions lib/victron_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ def ac_power_setpoint(watts=None, override_ess_net_mettering=True):
publish_message(Topics['system0']['ess_net_metering_overridden'], message="True", retain=True)

STATE.set(key='ac_power_setpoint', value=f"{watts}")
publish.single(TopicsWritable['system0']['ac_power_setpoint'], payload=_msg, qos=0, retain=True, hostname=cerboGxEndpoint, port=1883)
publish.single(TopicsWritable['system0']['ac_power_setpoint'], payload=_msg, qos=1, retain=True, hostname=cerboGxEndpoint, port=1883)

def minimum_ess_soc(percent: int = 10):
if percent:
_msg = f"{{\"value\": {percent}}}"
logging.info(f"Setting battery sustain percent to: {percent}%")
publish.single(TopicsWritable['system0']['minimum_ess_soc'], payload=_msg, qos=0, retain=True, hostname=cerboGxEndpoint, port=1883)
publish.single(TopicsWritable['system0']['minimum_ess_soc'], payload=_msg, qos=1, retain=True, hostname=cerboGxEndpoint, port=1883)

def restore_default_battery_max_voltage():
logging.info(f"Victron Integration: Restoring max charge voltage to {float_voltage}V before shutdown...")
Expand All @@ -43,25 +43,25 @@ def regulate_battery_max_voltage(ess_soc):

try:
if int(ess_soc) == float(dotenv_config('MINIMUM_ESS_SOC')) and current_max_charge_voltage != float_voltage:
publish.single(TopicsWritable["system0"]["max_charge_voltage"], payload=f"{{\"value\": {float_voltage}}}", qos=0, retain=False, hostname=cerboGxEndpoint, port=1883)
publish.single(TopicsWritable["system0"]["max_charge_voltage"], payload=f"{{\"value\": {float_voltage}}}", qos=1, retain=False, hostname=cerboGxEndpoint, port=1883)
logging.info(f"Victron Integration: Adjusting max charge voltage to {float_voltage}V due to battery SOC at {ess_soc}%")
publish.single("Tesla/vehicle0/solar/ess_max_charge_voltage", payload=f"{{\"value\": \"{float_voltage}\"}}", qos=0, retain=True, hostname=cerboGxEndpoint, port=1883)

elif int(ess_soc) < float(dotenv_config('MINIMUM_ESS_SOC')) and current_max_charge_voltage != max_voltage:
publish.single(TopicsWritable["system0"]["max_charge_voltage"], payload=f"{{\"value\": {max_voltage}}}", qos=0, retain=False, hostname=cerboGxEndpoint, port=1883)
publish.single(TopicsWritable["system0"]["max_charge_voltage"], payload=f"{{\"value\": {max_voltage}}}", qos=1, retain=False, hostname=cerboGxEndpoint, port=1883)
logging.info(f"Victron Integration: Adjusting max charge voltage to {max_voltage}V due to battery SOC {ess_soc}% of {dotenv_config('MINIMUM_ESS_SOC')}%")
publish.single("Tesla/vehicle0/solar/ess_max_charge_voltage", payload=f"{{\"value\": \"{max_voltage}\"}}", qos=0, retain=True, hostname=cerboGxEndpoint, port=1883)

elif int(ess_soc) >= float(dotenv_config('MAXIMUM_ESS_SOC')) and current_max_charge_voltage != float(dotenv_config('BATTERY_FULL_VOLTAGE')):
publish.single(TopicsWritable["system0"]["max_charge_voltage"], payload=f"{{\"value\": \"{battery_full_voltage}\"}}", qos=0, retain=False, hostname=cerboGxEndpoint, port=1883)
publish.single(TopicsWritable["system0"]["max_charge_voltage"], payload=f"{{\"value\": \"{battery_full_voltage}\"}}", qos=1, retain=False, hostname=cerboGxEndpoint, port=1883)
logging.info(f"Victron Integration: Adjusting max charge voltage to {battery_full_voltage} due to battery SOC reaching {dotenv_config('MAXIMUM_ESS_SOC')}% or higher")
publish.single("Tesla/vehicle0/solar/ess_max_charge_voltage", payload=f"{{\"value\": \"{battery_full_voltage}\"}}", qos=0, retain=True, hostname=cerboGxEndpoint, port=1883)
publish.single("Tesla/vehicle0/solar/ess_max_charge_voltage", payload=f"{{\"value\": \"{battery_full_voltage}\"}}", qos=1, retain=True, hostname=cerboGxEndpoint, port=1883)
# when battery is full, return Minumum batt SOC (unless grid fails) to 5%
minimum_ess_soc(5)

else:
logging.debug(f"Victron Integration: No Action. Battery max charge voltage is appropriately set at {current_max_charge_voltage}V with ESS SOC at {ess_soc}%")
publish.single("Tesla/vehicle0/solar/ess_max_charge_voltage", payload=f"{{\"value\": \"{current_max_charge_voltage}\"}}", qos=0, retain=True, hostname=cerboGxEndpoint, port=1883)
publish.single("Tesla/vehicle0/solar/ess_max_charge_voltage", payload=f"{{\"value\": \"{current_max_charge_voltage}\"}}", qos=1, retain=True, hostname=cerboGxEndpoint, port=1883)

return True

Expand Down

0 comments on commit 932ee4a

Please sign in to comment.