Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 48 additions & 36 deletions src/eos_connect.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@ def charging_state_callback(new_state):
# update the base control with the new charging state
base_control.set_current_evcc_charging_state(evcc_interface.get_charging_state())
base_control.set_current_evcc_charging_mode(evcc_interface.get_charging_mode())

logger.info("[MAIN] EVCC Event - Charging state changed to: %s", new_state)
change_control_state()

Expand Down Expand Up @@ -387,22 +386,26 @@ def __init__(self, update_interval):
self.last_request_response = {
"request": json.dumps(
{
"state": "waiting for first optimization run",
"status": "Awaiting first optimization run",
},
indent=4,
),
"response": json.dumps(
{
"state": "initializing",
"message": "waiting for finishing first optimization run",
"status": "starting up",
"message": (
"The first request has been sent to EOS and is now waiting for "
"the completion of the first optimization run."
),
},
indent=4,
),
}
self.current_state = {
"request_state": None,
"last_request_timestamp": None,
"last_response_timestamp": None,
# initialize with startup time stamp to avoid confusion in gui
"last_response_timestamp": datetime.now(time_zone).isoformat(),
"next_run": None,
}
self._update_thread = None
Expand All @@ -426,14 +429,18 @@ def __set_state_request(self):
Sets the current state of the optimization scheduler.
"""
self.current_state["request_state"] = "request send"
self.current_state["last_request_timestamp"] = datetime.now(time_zone).isoformat()
self.current_state["last_request_timestamp"] = datetime.now(
time_zone
).isoformat()

def __set_state_response(self):
"""
Sets the current state of the optimization scheduler.
"""
self.current_state["request_state"] = "response received"
self.current_state["last_response_timestamp"] = datetime.now(time_zone).isoformat()
self.current_state["last_response_timestamp"] = datetime.now(
time_zone
).isoformat()

def __set_state_next_run(self, next_run_time):
"""
Expand Down Expand Up @@ -606,11 +613,14 @@ def change_control_state():
if config_manager.config["inverter"]["type"] == "fronius_gen24":
inverter_en = True

current_overall_state = base_control.get_current_overall_state_number()
current_overall_state_text = base_control.get_current_overall_state()

# Check if the overall state of the inverter was changed recently
if base_control.was_overall_state_changed_recently(180):
logger.debug("[Main] Overall state changed recently")
# MODE_CHARGE_FROM_GRID
if base_control.get_current_overall_state() == 0:
if current_overall_state == 0:
# get the current ac charge demand and set it to the inverter according
# to the max dynamic charge power of the battery based on SOC
tgt_charge_power = min(
Expand All @@ -621,59 +631,58 @@ def change_control_state():
inverter_interface.set_mode_force_charge(tgt_charge_power)
logger.info(
"[Main] Inverter mode set to %s with %s W (_____|||||_____)",
base_control.get_state_mapping().get(
base_control.get_current_overall_state(), "unknown state"
),
current_overall_state_text,
tgt_charge_power,
)
# MODE_AVOID_DISCHARGE
elif base_control.get_current_overall_state() == 1:
elif current_overall_state == 1:
if inverter_en:
inverter_interface.set_mode_avoid_discharge()
logger.info(
"[Main] Inverter mode set to %s (_____-----_____)",
base_control.get_state_mapping().get(
base_control.get_current_overall_state(), "unknown state"
),
current_overall_state_text,
)
# MODE_DISCHARGE_ALLOWED
elif base_control.get_current_overall_state() == 2:
elif current_overall_state == 2:
if inverter_en:
inverter_interface.set_mode_allow_discharge()
logger.info(
"[Main] Inverter mode set to %s (_____+++++_____)",
base_control.get_state_mapping().get(
base_control.get_current_overall_state(), "unknown state"
),
current_overall_state_text,
)
# MODE_AVOID_DISCHARGE_EVCC_FAST
elif base_control.get_current_overall_state() == 3:
elif current_overall_state == 3:
if inverter_en:
inverter_interface.set_mode_avoid_discharge()
logger.info(
"[Main] Inverter mode set to %s (_____-+-+-_____)",
base_control.get_state_mapping().get(
base_control.get_current_overall_state(), "unknown state"
),
"[Main] Inverter mode set to %s (_____+---+_____)",
current_overall_state_text,
)
# MODE_DISCHARGE_ALLOWED_EVCC_PV
elif current_overall_state == 4:
if inverter_en:
inverter_interface.set_mode_allow_discharge()
logger.info(
"[Main] Inverter mode set to %s (_____-+++-_____)",
current_overall_state_text,
)
elif base_control.get_current_overall_state() == 4:
# MODE_DISCHARGE_ALLOWED_EVCC_MIN_PV
elif current_overall_state == 5:
if inverter_en:
inverter_interface.set_mode_allow_discharge()
logger.info(
"[Main] Inverter mode set to %s (_____-+-+-_____)",
base_control.get_state_mapping().get(
base_control.get_current_overall_state(), "unknown state"
),
"[Main] Inverter mode set to %s (_____+-+-+_____)",
current_overall_state_text,
)
elif base_control.get_current_overall_state() < 0:
elif current_overall_state < 0:
logger.warning("[Main] Inverter mode not initialized yet")
return True
# Log the current state if no recent changes were made
current_state = base_control.get_current_overall_state()

logger.info(
"[Main] Overall state not changed recently"
+ " - remaining in current state: %s (_____OOOOO_____)",
base_control.get_state_mapping().get(current_state, "unknown state"),
current_overall_state_text,
)
return False

Expand Down Expand Up @@ -738,8 +747,8 @@ def get_controls():
current_discharge_allowed = base_control.get_current_discharge_allowed()
current_battery_soc = battery_interface.get_current_soc()
base_control.set_current_battery_soc(current_battery_soc)
current_inverter_mode = base_control.get_current_overall_state(False)
current_inverter_mode_num = base_control.get_current_overall_state()
current_inverter_mode = base_control.get_current_overall_state()
current_inverter_mode_num = base_control.get_current_overall_state_number()

response_data = {
"current_states": {
Expand All @@ -755,13 +764,16 @@ def get_controls():
},
"battery": {
"soc": current_battery_soc,
"max_charge_power_dyn": battery_interface.get_max_charge_power_dyn(),
"max_charge_power_dyn": battery_interface.get_max_charge_power_dyn(),
},
"state": optimization_scheduler.get_current_state(),
"eos_connect_version": __version__,
"timestamp": datetime.now(time_zone).isoformat(),
"api_version": "0.0.1",
}
return Response(json.dumps(response_data, indent=4), content_type="application/json")
return Response(
json.dumps(response_data, indent=4), content_type="application/json"
)


if __name__ == "__main__":
Expand Down
61 changes: 45 additions & 16 deletions src/interfaces/base_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,16 @@
MODE_DISCHARGE_ALLOWED = 2
MODE_AVOID_DISCHARGE_EVCC_FAST = 3
MODE_DISCHARGE_ALLOWED_EVCC_PV = 4
MODE_DISCHARGE_ALLOWED_EVCC_MIN_PV = 5

state_mapping = {
0: "MODE_CHARGE_FROM_GRID",
1: "MODE_AVOID_DISCHARGE",
2: "MODE_DISCHARGE_ALLOWED",
3: "MODE_AVOID_DISCHARGE_EVCC_FAST",
4: "MODE_DISCHARGE_ALLOWED_EVCC_PV",
-1: "MODE Startup",
0: "MODE CHARGE FROM GRID",
1: "MODE AVOID DISCHARGE",
2: "MODE DISCHARGE ALLOWED",
3: "MODE AVOID DISCHARGE EVCC FAST",
4: "MODE DISCHARGE ALLOWED EVCC PV",
5: "MODE DISCHARGE ALLOWED EVCC MIN+PV",
}


Expand All @@ -38,11 +41,11 @@ def __init__(self, config, timezone):
self.current_ac_charge_demand = 0
self.last_ac_charge_demand = 0
self.current_dc_charge_demand = 0
self.current_discharge_allowed = 1
self.current_discharge_allowed = -1
self.current_evcc_charging_state = False
self.current_evcc_charging_mode = False
# startup with None to force a writing to the inverter
self.current_overall_state = None
self.current_overall_state = -1
self.current_battery_soc = 0
self.time_zone = timezone
self.config = config
Expand Down Expand Up @@ -85,15 +88,12 @@ def get_current_discharge_allowed(self):
"""
return self.current_discharge_allowed

def get_current_overall_state(self, number=True):
def get_current_overall_state(self):
"""
Returns the current overall state.
"""
if number:
return self.current_overall_state
else:
# Return the string representation of the state
return state_mapping.get(self.current_overall_state, "unknown state")
# Return the string representation of the state
return state_mapping.get(self.current_overall_state, "unknown state")

def get_current_overall_state_number(self):
"""
Expand Down Expand Up @@ -190,14 +190,17 @@ def set_current_overall_state(self):
new_state = MODE_CHARGE_FROM_GRID
elif self.current_discharge_allowed > 0:
new_state = MODE_DISCHARGE_ALLOWED
else:
elif self.current_discharge_allowed == 0:
new_state = MODE_AVOID_DISCHARGE
else:
new_state = -1
# check if the grid charge demand has changed
grid_charge_value_changed = (
self.current_ac_charge_demand != self.last_ac_charge_demand
)

# override overall state if EVCC charging state is active and in mode fast charge and discharge is allowed
# override overall state if EVCC charging state is active and
# in mode fast charge and discharge is allowed
if (
new_state == MODE_DISCHARGE_ALLOWED
and self.current_evcc_charging_state
Expand All @@ -206,7 +209,33 @@ def set_current_overall_state(self):
new_state = MODE_AVOID_DISCHARGE_EVCC_FAST
logger.info(
"[BASE_CTRL] EVCC charging state is active,"
+ " setting overall state to MODE_AVOID_DISCHARGE"
+ " setting overall state to MODE_AVOID_DISCHARGE_EVCC_FAST"
)

# override overall state if EVCC charging state is active and
# in mode pv charge and discharge is allowed
if (
new_state == MODE_DISCHARGE_ALLOWED
and self.current_evcc_charging_state
and self.current_evcc_charging_mode == "pv"
):
new_state = MODE_DISCHARGE_ALLOWED_EVCC_PV
logger.info(
"[BASE_CTRL] EVCC charging state is active,"
+ " setting overall state to MODE_DISCHARGE_ALLOWED_EVCC_PV"
)

# override overall state if EVCC charging state is active and
# in mode pv charge and discharge is allowed
if (
new_state == MODE_DISCHARGE_ALLOWED
and self.current_evcc_charging_state
and self.current_evcc_charging_mode == "minpv"
):
new_state = MODE_DISCHARGE_ALLOWED_EVCC_MIN_PV
logger.info(
"[BASE_CTRL] EVCC charging state is active,"
+ " setting overall state to MODE_DISCHARGE_ALLOWED_EVCC_MIN_PV"
)

if new_state != self.current_overall_state or grid_charge_value_changed:
Expand Down
2 changes: 1 addition & 1 deletion src/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = 'snapshot-v0.1.4'
__version__ = 'develop-v0.1.34'
Loading