Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
ee33762
fix modal card height
benderl Sep 1, 2025
97c30bc
change charge point power data layout on small devices
benderl Sep 1, 2025
7aed61a
fix reactivity of vehicle table size
benderl Sep 1, 2025
46dc665
fix scheduled charging plan id (#2719)
LKuemmel Sep 1, 2025
bb64ba1
fix table search field position
benderl Sep 1, 2025
c64c7e6
dense table on compact view
benderl Sep 1, 2025
750968b
remove table border radius in compact mode
benderl Sep 1, 2025
07743c1
Merge pull request #2718 from benderl/koala
benderl Sep 1, 2025
10111cc
Build Web Theme: Koala
benderl Sep 1, 2025
3e86782
only lock cp if tag is no longer recognized (#2722)
ndrsnhs Sep 1, 2025
59f514b
sungrow fix pv_power (#2720)
ndrsnhs Sep 1, 2025
51f5928
reset power limit if bat control permitted is false (#2723)
LKuemmel Sep 2, 2025
b4f553c
improve diagrams for hybrid inverters using simcount (#2717)
ndrsnhs Sep 3, 2025
7334f49
improve log message (#2725)
LKuemmel Sep 3, 2025
c0994e5
add top ram processes in maintenance page
benderl Sep 4, 2025
d04bbe6
fix copying charge and ev templates
benderl Sep 4, 2025
85cd0ad
Merge pull request #2729 from benderl/fixes
benderl Sep 4, 2025
166f2dc
round history chart ticks
benderl Sep 2, 2025
9ba201b
Merge pull request #2724 from benderl/koala
benderl Sep 4, 2025
8c49215
Build Web Theme: Koala
benderl Sep 4, 2025
c37b466
build UI (#2730)
LKuemmel Sep 4, 2025
60f525c
Feature fix phases (#2728)
LKuemmel Sep 4, 2025
edf7369
colors web theme: fix mqtt connection settings
benderl Sep 5, 2025
8223d35
update discovery api url
benderl Sep 5, 2025
da9682e
Merge pull request #2732 from benderl/colors
benderl Sep 5, 2025
f2dc40b
Merge pull request #2733 from benderl/fixes
benderl Sep 5, 2025
064e926
fix trigger chargelog entry (#2735)
LKuemmel Sep 5, 2025
401403c
fix nibe (#2736)
LKuemmel Sep 5, 2025
bdc31b2
rewrite koala history chart x-axis labels
benderl Sep 8, 2025
a6b26dc
Merge pull request #2739 from benderl/fixes
benderl Sep 8, 2025
d13c243
Build Web Theme: Koala
benderl Sep 8, 2025
b06e26b
restart phase switch timer if threshold is missed (#2740)
LKuemmel Sep 8, 2025
570f1b7
fix pv: phase switch before charge start (#2741)
LKuemmel Sep 9, 2025
8493ffc
soc_bmwbc: fix quota issue (#2737)
rleidner Sep 9, 2025
dbd6b54
build settings
benderl Sep 9, 2025
1e09044
Merge pull request #2743 from benderl/build-ui
benderl Sep 9, 2025
cda6bcd
handle empty log file (#2738)
LKuemmel Sep 10, 2025
d900387
koala: fix pv min_current off value
benderl Sep 10, 2025
3e5abe6
Merge pull request #2747 from benderl/koala
benderl Sep 10, 2025
17c74b2
Build Web Theme: Koala
benderl Sep 10, 2025
9e0c8ef
restart display manager
benderl Sep 11, 2025
9137932
Merge pull request #2752 from benderl/fixes
benderl Sep 11, 2025
dab1393
Update version 2.1.8-RC.1
LKuemmel Sep 12, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
66 changes: 34 additions & 32 deletions packages/control/bat_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,40 +291,42 @@ def set_power_limit_controllable(self):

def get_power_limit(self):
if self.data.config.bat_control_permitted is False:
return
chargepoint_by_chargemodes = get_chargepoints_by_chargemodes(CONSIDERED_CHARGE_MODES_CHARGING)
# Falls aktive Steuerung an und Fahrzeuge laden und kein Überschuss im System ist,
# dann Speicherleistung begrenzen.
if (self.data.config.power_limit_mode != BatPowerLimitMode.NO_LIMIT.value and
len(chargepoint_by_chargemodes) > 0 and
data.data.cp_all_data.data.get.power > 100 and
self.data.get.power_limit_controllable and
self.data.get.power <= 0 and
data.data.counter_all_data.get_evu_counter().data.get.power >= -100):
if self.data.config.power_limit_mode == BatPowerLimitMode.LIMIT_STOP.value:
self.data.set.power_limit = 0
elif self.data.config.power_limit_mode == BatPowerLimitMode.LIMIT_TO_HOME_CONSUMPTION.value:
self.data.set.power_limit = data.data.counter_all_data.data.set.home_consumption * -1
log.debug(f"Speicher-Leistung begrenzen auf {self.data.set.power_limit/1000}kW")
else:
self.data.set.power_limit = None
control_range_low = data.data.general_data.data.chargemode_config.pv_charging.control_range[0]
control_range_high = data.data.general_data.data.chargemode_config.pv_charging.control_range[1]
control_range_center = control_range_high - (control_range_high - control_range_low) / 2
if len(chargepoint_by_chargemodes) == 0:
log.debug("Speicher-Leistung nicht begrenzen, "
"da keine Ladepunkte in einem Lademodus mit Netzbezug sind.")
elif data.data.cp_all_data.data.get.power <= 100:
log.debug("Speicher-Leistung nicht begrenzen, da kein Ladepunkt mit Netzbezug lädt.")
elif self.data.get.power_limit_controllable is False:
log.debug("Speicher-Leistung nicht begrenzen, da keine regelbaren Speicher vorhanden sind.")
elif self.data.get.power > 0:
log.debug("Speicher-Leistung nicht begrenzen, da kein Speicher entladen wird.")
elif data.data.counter_all_data.get_evu_counter().data.get.power < control_range_center + 80:
# Wenn der Regelbereich zB auf Bezug steht, darf auch die Leistung des Regelbereichs entladen werden.
log.debug("Speicher-Leistung nicht begrenzen, da EVU-Überschuss vorhanden ist.")
else:
chargepoint_by_chargemodes = get_chargepoints_by_chargemodes(CONSIDERED_CHARGE_MODES_CHARGING)
# Falls aktive Steuerung an und Fahrzeuge laden und kein Überschuss im System ist,
# dann Speicherleistung begrenzen.
if (self.data.config.power_limit_mode != BatPowerLimitMode.NO_LIMIT.value and
len(chargepoint_by_chargemodes) > 0 and
data.data.cp_all_data.data.get.power > 100 and
self.data.get.power_limit_controllable and
self.data.get.power <= 0 and
data.data.counter_all_data.get_evu_counter().data.get.power >= -100):
if self.data.config.power_limit_mode == BatPowerLimitMode.LIMIT_STOP.value:
self.data.set.power_limit = 0
elif self.data.config.power_limit_mode == BatPowerLimitMode.LIMIT_TO_HOME_CONSUMPTION.value:
self.data.set.power_limit = data.data.counter_all_data.data.set.home_consumption * -1
log.debug(f"Speicher-Leistung begrenzen auf {self.data.set.power_limit/1000}kW")
else:
log.debug("Speicher-Leistung nicht begrenzen.")
self.data.set.power_limit = None
control_range_low = data.data.general_data.data.chargemode_config.pv_charging.control_range[0]
control_range_high = data.data.general_data.data.chargemode_config.pv_charging.control_range[1]
control_range_center = control_range_high - (control_range_high - control_range_low) / 2
if len(chargepoint_by_chargemodes) == 0:
log.debug("Speicher-Leistung nicht begrenzen, "
"da keine Ladepunkte in einem Lademodus mit Netzbezug sind.")
elif data.data.cp_all_data.data.get.power <= 100:
log.debug("Speicher-Leistung nicht begrenzen, da kein Ladepunkt mit Netzbezug lädt.")
elif self.data.get.power_limit_controllable is False:
log.debug("Speicher-Leistung nicht begrenzen, da keine regelbaren Speicher vorhanden sind.")
elif self.data.get.power > 0:
log.debug("Speicher-Leistung nicht begrenzen, da kein Speicher entladen wird.")
elif data.data.counter_all_data.get_evu_counter().data.get.power < control_range_center + 80:
# Wenn der Regelbereich zB auf Bezug steht, darf auch die Leistung des Regelbereichs entladen
# werden.
log.debug("Speicher-Leistung nicht begrenzen, da EVU-Überschuss vorhanden ist.")
else:
log.debug("Speicher-Leistung nicht begrenzen.")
remaining_power_limit = self.data.set.power_limit
for bat_component in get_controllable_bat_components():
if self.data.set.power_limit is None:
Expand Down
18 changes: 12 additions & 6 deletions packages/control/chargelog/chargelog.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from enum import Enum
import json
import logging
import os
import pathlib
from typing import Any, Dict, List, Optional

Expand Down Expand Up @@ -250,13 +251,18 @@ def write_new_entry(new_entry):
filepath = str(_get_parent_file() / "data" / "charge_log" /
(timecheck.create_timestamp_YYYYMM() + ".json"))
try:
with open(filepath, "r", encoding="utf-8") as json_file:
content = json.load(json_file)
if os.path.exists(filepath) and os.path.getsize(filepath) == 0:
content = []
else:
with open(filepath, "r", encoding="utf-8") as json_file:
try:
content = json.load(json_file)
except json.decoder.JSONDecodeError:
corrupt_path = f"{filepath}.unparsable_{timecheck.create_timestamp()}"
os.rename(filepath, corrupt_path)
log.error(f"ChargeLog: Korrupte Datei umbenannt nach {corrupt_path}")
content = []
except FileNotFoundError:
# with open(filepath, "w", encoding="utf-8") as jsonFile:
# json.dump([], jsonFile)
# with open(filepath, "r", encoding="utf-8") as jsonFile:
# content = json.load(jsonFile)
content = []
content.append(new_entry)
write_and_check(filepath, content)
Expand Down
30 changes: 18 additions & 12 deletions packages/control/chargepoint/chargepoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,13 +160,15 @@ def _is_manual_lock_inactive(self) -> Tuple[bool, Optional[str]]:
# Vergleiche werden case-insensitive durchgeführt
# das vereinfacht die Eingabe, kann aber auch für falsche Treffer sorgen.
# 'fnmatch()' ist case-insensitive
match = False
for tag_id in self.template.data.valid_tags:
if ((self.data.get.rfid is not None and fnmatch(self.data.get.rfid, tag_id)) or
(self.data.get.vehicle_id is not None and fnmatch(self.data.get.vehicle_id, tag_id)) or
(self.data.set.rfid is not None and fnmatch(self.data.set.rfid, tag_id))):
Pub().pub(f"openWB/set/chargepoint/{self.num}/set/manual_lock", False)
# Wenn der Ladepunkt nach dem Abstecken gesperrt werden soll, und kein Fahrzeug angeschlossen ist wird gesperrt
if self.template.data.disable_after_unplug and self.data.get.plug_state is False:
match = True
if match:
Pub().pub(f"openWB/set/chargepoint/{self.num}/set/manual_lock", False)
elif self.template.data.disable_after_unplug and self.data.get.plug_state is False:
Pub().pub(f"openWB/set/chargepoint/{self.num}/set/manual_lock", True)

if self.data.set.manual_lock:
Expand Down Expand Up @@ -374,7 +376,7 @@ def _is_phase_switch_required(self) -> bool:
self.check_deviating_contactor_states(self.data.set.phases_to_use,
self.data.control_parameter.phases)) and
# Wenn der Ladevorgang gestartet wird, muss vor dem ersten Laden umgeschaltet werden.
self.data.set.current != 0):
self.data.set.current != 0 and self.data.get.charge_state is False):
phase_switch_required = True
if phase_switch_required:
# Umschaltung fehlgeschlagen
Expand All @@ -383,18 +385,18 @@ def _is_phase_switch_required(self) -> bool:
if self.data.control_parameter.failed_phase_switches > self.MAX_FAILED_PHASE_SWITCHES:
phase_switch_required = False
self.set_state_and_log(
"Keine Phasenumschaltung, da die maximale Anzahl an Fehlversuchen erreicht wurde. Die "
"aktuelle Phasenzahl wird bis zum Abstecken beibehalten.")
"Keine Phasenumschaltung, da die maximale Anzahl an Fehlversuchen erreicht wurde.")
self.data.control_parameter.failed_phase_switches += 1
else:
# Umschaltung vor Ladestart zulassen
if self.data.set.log.imported_since_plugged != 0:
if (self.data.set.log.imported_since_plugged != 0 and
self.data.control_parameter.failed_phase_switches > 0):
phase_switch_required = False
self.set_state_and_log(
"Keine Phasenumschaltung, da wiederholtes Anstoßen der Umschaltung in den übergreifenden "
"Ladeeinstellungen deaktiviert wurde. Die aktuelle "
"Phasenzahl wird bis zum Abstecken beibehalten.")
self.data.control_parameter.failed_phase_switches += 1
self.data.control_parameter.failed_phase_switches += 1
return phase_switch_required

STOP_CHARGING = ", dafür wird die Ladung unterbrochen."
Expand Down Expand Up @@ -723,6 +725,8 @@ def update(self, ev_list: Dict[str, Ev]) -> None:
data.data.counter_all_data.get_evu_counter().reset_switch_on_off(
self, charging_ev)
charging_ev.reset_phase_switch(self.data.control_parameter)
if self.chargemode_changed:
self.data.control_parameter.failed_phase_switches = 0
message = message_ev if message_ev else message
# Ein Eintrag muss nur erstellt werden, wenn vorher schon geladen wurde und auch danach noch
# geladen werden soll.
Expand Down Expand Up @@ -823,8 +827,9 @@ def _get_charging_ev(self, vehicle: int, ev_list: Dict[str, Ev]) -> Ev:
if self.data.set.charging_ev_prev != vehicle:
Pub().pub(f"openWB/set/vehicle/{charging_ev.num}/get/force_soc_update", True)
log.debug("SoC nach EV-Wechsel")
self.update_charge_template(charging_ev.charge_template)
if self.data.set.charge_template.data.id != charging_ev.charge_template.data.id:
# wenn vorher kein anderes Fahrzeug zugeordnet war, Ladeprofil nicht zurücksetzen
if ((self.data.set.charging_ev_prev != vehicle and self.data.set.charging_ev_prev != -1) or
(self.data.set.charge_template.data.id != charging_ev.charge_template.data.id)):
self.update_charge_template(charging_ev.charge_template)
self.data.set.charging_ev_data = charging_ev
self.data.set.charging_ev = vehicle
Expand Down Expand Up @@ -908,7 +913,8 @@ def cp_ev_chargemode_support_phase_switch(self) -> bool:
def cp_ev_support_phase_switch(self) -> bool:
return (self.data.config.auto_phase_switch_hw and
self.data.get.evse_signaling != EvseSignaling.HLC and
self.data.set.charging_ev_data.ev_template.data.prevent_phase_switch is False)
(self.data.set.charging_ev_data.ev_template.data.prevent_phase_switch is False or
self.data.set.log.imported_since_plugged == 0))

def chargemode_support_phase_switch(self) -> bool:
control_parameter = self.data.control_parameter
Expand All @@ -934,7 +940,7 @@ def failed_phase_switches_reached(self) -> bool:
(data.data.general_data.data.chargemode_config.retry_failed_phase_switches is False and
self.data.control_parameter.failed_phase_switches == 1)):
self.set_state_and_log(
"Keine automatische Umschaltung, da die maximale Anzahl an Fehlversuchen erreicht wurde. ")
"Keine Phasenumschaltung, da die maximale Anzahl an Fehlversuchen erreicht wurde. ")
return False
else:
return True
13 changes: 8 additions & 5 deletions packages/control/ev/ev.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,11 +353,13 @@ def auto_phase_switch(self,
waiting_time,
delay)[1])
control_parameter.state = ChargepointState.PHASE_SWITCH_DELAY
elif condition_msg:
if condition_msg == self.CURRENT_OUT_OF_NOMINAL_DIFFERENCE:
message = f"Keine Phasenumschaltung{condition_msg}"
else:
log.debug(f"Keine Phasenumschaltung{condition_msg}")
else:
if condition_msg:
if condition_msg == self.CURRENT_OUT_OF_NOMINAL_DIFFERENCE:
message = f"Keine Phasenumschaltung{condition_msg}"
else:
log.debug(f"Keine Phasenumschaltung{condition_msg}")
control_parameter.timestamp_phase_switch_buffer_start = None
else:
if condition:
# Timer laufen lassen
Expand All @@ -379,6 +381,7 @@ def auto_phase_switch(self,
).data.set.reserved_surplus -= max(0, required_reserved_power)
message = f"Verzögerung für die {direction_str} Phasen abgebrochen{condition_msg}"
control_parameter.state = ChargepointState.CHARGING_ALLOWED
control_parameter.timestamp_phase_switch_buffer_start = None

if message:
log.info(f"LP {cp_num}: {message}")
Expand Down
2 changes: 0 additions & 2 deletions packages/control/phase_switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ def _perform_phase_switch(chargepoint_module: AbstractChargepoint, phases: int,
time.sleep(5)
# Phasenumschaltung entsprechend Modul
chargepoint_module.switch_phases(phases, ev.ev_template.data.phase_switch_pause)
# Die Ladung wird in start_charging wieder gestartet, wenn phase_switch_timestamp wieder auf None gesetzt wird.
time.sleep(ev.ev_template.data.keep_charge_active_duration)
except Exception:
log.exception("Fehler im Phasenumschaltungs-Modul")

Expand Down
5 changes: 3 additions & 2 deletions packages/helpermodules/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ def addChargeTemplate(self, connection_id: str, payload: dict) -> None:
new_charge_template = asdict(new_charge_template)
else:
new_charge_template = get_new_charge_template()
new_charge_template["id"] = new_id
new_charge_template["id"] = new_id

Pub().pub("openWB/set/command/max_id/charge_template", new_id)
Pub().pub(f"openWB/set/vehicle/template/charge_template/{new_id}", new_charge_template)
Expand Down Expand Up @@ -648,8 +648,9 @@ def addEvTemplate(self, connection_id: str, payload: dict) -> None:
else:
new_ev_template = dataclass_utils.asdict(EvTemplateData())
new_id = self.max_id_ev_template + 1
Pub().pub(f'openWB/set/vehicle/template/ev_template/{new_id}', new_ev_template)
new_ev_template["id"] = new_id
self.max_id_ev_template = new_id
Pub().pub(f'openWB/set/vehicle/template/ev_template/{new_id}', new_ev_template)
Pub().pub("openWB/set/command/max_id/ev_template", new_id)
pub_user_message(
payload, connection_id,
Expand Down
Loading