Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
c95a05c
draft
LKuemmel Sep 24, 2025
d9e1084
change update order
ndrsnhs Sep 25, 2025
51ea8ee
improve syntax
ndrsnhs Sep 26, 2025
f607d2e
add trace_malloc
LKuemmel Sep 26, 2025
390df07
without list clean up (as in master)
LKuemmel Sep 26, 2025
2d4f58f
loglevel
LKuemmel Sep 26, 2025
d1e987d
Revert "fix auto phase switch for pv charging with min current"
LKuemmel Sep 26, 2025
1987d68
Merge pull request #2787 from openWB/revert-2776-fix_pv_charging
LKuemmel Sep 26, 2025
dc035b3
Merge pull request #2785 from ndrsnhs/fix-secondary-update-order
LKuemmel Sep 26, 2025
20c2b65
fix force soc update after tag/mac identification
LKuemmel Sep 26, 2025
2317e90
flake8
LKuemmel Sep 26, 2025
9e60d0a
Revert "improve syntax"
vuffiraa72 Sep 27, 2025
1e1fddf
fix type in device.py
benderl Sep 29, 2025
caccbef
Merge pull request #2791 from benderl/fix-huawei-kit
benderl Sep 29, 2025
9e97c8a
Merge pull request #2790 from vuffiraa72/fast-return-false-while-chec…
benderl Sep 29, 2025
f054c10
Koala: fix BaseCarousel resize handling
benderl Sep 30, 2025
d9e79e5
Koala: fix flow chart pv animation
benderl Sep 30, 2025
6ffa5cd
Merge pull request #2793 from benderl/fixes
benderl Sep 30, 2025
d4a867d
Build Web Theme: Koala
benderl Sep 30, 2025
6ee63a5
Cards: fix flow chart pv animation
benderl Sep 30, 2025
b9f2aca
Build Display Theme: Cards
benderl Sep 30, 2025
584e633
sonnenbatterie: fix rest api2 grid power sign
benderl Sep 30, 2025
335744f
backup: extend mosquitto flush timeout
benderl Sep 30, 2025
14cf281
Merge pull request #2797 from benderl/fixes
benderl Sep 30, 2025
3f18921
read currents from Pro3EM correctly
ndrsnhs Sep 30, 2025
82639c8
Merge pull request #2799 from ndrsnhs/Shelly-Pro3EM-inverter/-bat-fix
benderl Oct 1, 2025
0c8ba36
build settings ui
benderl Oct 1, 2025
c1a0c61
Merge pull request #2802 from benderl/build-ui
benderl Oct 1, 2025
625d2a1
adjust exported register
ndrsnhs Oct 2, 2025
fa0386f
satellite precise current
LKuemmel Oct 7, 2025
81d3950
vwgroup/skoda: fix double ZZ in timestamp string
rleidner Oct 7, 2025
833a866
fix
LKuemmel Oct 8, 2025
1a75d97
pass float current
LKuemmel Oct 8, 2025
6d715ff
Merge pull request #2809 from openWB/feature_fix_satellite
LKuemmel Oct 8, 2025
d77ef51
use filehandler for smarthome
LKuemmel Oct 13, 2025
b79316d
revert queue handler
LKuemmel Sep 22, 2025
41dabdc
Revert "Keep log messages from last full run and last run with error …
LKuemmel Oct 14, 2025
1b3335a
fix
LKuemmel Oct 14, 2025
df77654
ocpp: add '/' to url if missing
LKuemmel Oct 14, 2025
888c097
Revert "Revert "Keep log messages from last full run and last run wit…
LKuemmel Oct 15, 2025
15fc979
fix in-mem handler
LKuemmel Oct 15, 2025
ef40ba3
typo
LKuemmel Oct 15, 2025
22474c3
fix smarthome
LKuemmel Oct 15, 2025
0740c9f
Revert "fix smarthome"
LKuemmel Oct 15, 2025
9dac7b7
Revert "use filehandler for smarthome"
LKuemmel Oct 15, 2025
fc7d0e4
fix phase switch for pv and eco charging
LKuemmel Oct 15, 2025
d502860
Merge pull request #2818 from LKuemmel/fix_pv_charging
LKuemmel Oct 15, 2025
11d60bc
remove tracemalloc
LKuemmel Oct 15, 2025
e457305
typo
LKuemmel Oct 15, 2025
4f1bb96
Merge pull request #2788 from LKuemmel/fix-soc
LKuemmel Oct 15, 2025
99281b8
Merge pull request #2808 from rleidner/soc_vwgroup_p0
LKuemmel Oct 15, 2025
41caf5c
Merge pull request #2816 from LKuemmel/ocpp
LKuemmel Oct 15, 2025
18f5b22
Merge pull request #2819 from openWB/feature_mem
LKuemmel Oct 15, 2025
b771268
Merge pull request #2805 from ndrsnhs/huawei-emma-pv-total-pv-fix
LKuemmel Oct 15, 2025
bf65603
build UI
LKuemmel Oct 15, 2025
6af7364
Merge pull request #2824 from LKuemmel/web
LKuemmel Oct 15, 2025
408122a
rename eco phases setting (#2820)
LKuemmel Oct 15, 2025
50eb1a0
Build Web Theme: Colors
LKuemmel Oct 15, 2025
bdea7d2
Trigger display thme cards build (#2825)
LKuemmel Oct 16, 2025
91314e9
Build Display Theme: Cards
LKuemmel Oct 16, 2025
bff1206
Trigger display theme colors build (#2826)
LKuemmel Oct 16, 2025
93b9c51
Build Display Theme: Colors
LKuemmel Oct 16, 2025
50d90ba
Trigger web theme koala build (#2827)
LKuemmel Oct 16, 2025
aeb9555
Build Web Theme: Koala
LKuemmel Oct 16, 2025
5be188f
Merge remote-tracking branch 'upstream/master' into release-merge
LKuemmel Oct 16, 2025
096c891
update version 2.1.8-Patch.2
LKuemmel Oct 16, 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
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion packages/control/algorithm/algorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def _check_auto_phase_switch_delay(self) -> None:
if cp.data.set.charging_ev != -1:
charging_ev = cp.data.set.charging_ev_data
control_parameter = cp.data.control_parameter
if cp.cp_ev_chargemode_support_phase_switch():
if cp.cp_state_hw_support_phase_switch() and control_parameter.template_phases == 0:
# Gibt die Stromstärke und Phasen zurück, mit denen nach der Umschaltung geladen werden
# soll. Falls keine Umschaltung erforderlich ist, werden Strom und Phasen, die übergeben
# wurden, wieder zurückgegeben.
Expand Down
10 changes: 7 additions & 3 deletions packages/control/algorithm/integration_test/pv_charging_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,9 +223,9 @@ def test_surplus(params: ParamsSurplus, all_cp_pv_charging_3p, all_cp_charging_3
data.data.counter_data["counter6"].data.set.raw_currents_left = params.raw_currents_left_counter6
mock_get_component_name_by_id = Mock(return_value="Garage")
monkeypatch.setattr(loadmanagement, "get_component_name_by_id", mock_get_component_name_by_id)
data.data.cp_data["cp3"].data.set.charge_template.data.chargemode.pv_charging.phases_to_use = 1
data.data.cp_data["cp4"].data.set.charge_template.data.chargemode.pv_charging.phases_to_use = 1
data.data.cp_data["cp5"].data.set.charge_template.data.chargemode.pv_charging.phases_to_use = 1
for i in range(3, 6):
data.data.cp_data[f"cp{i}"].data.set.charge_template.data.chargemode.pv_charging.phases_to_use = 1
data.data.cp_data[f"cp{i}"].data.control_parameter.template_phases = 1

# execution
Algorithm().calc_current()
Expand Down Expand Up @@ -276,6 +276,8 @@ def test_phase_switch(all_cp_pv_charging_3p, all_cp_charging_3p, monkeypatch):
"cp3"].data.control_parameter.state = ChargepointState.CHARGING_ALLOWED
data.data.cp_data[
"cp3"].data.control_parameter.timestamp_last_phase_switch = 1652682252
for i in range(3, 6):
data.data.cp_data[f"cp{i}"].data.control_parameter.template_phases = 0

# execution
Algorithm().calc_current()
Expand All @@ -298,6 +300,8 @@ def test_phase_switch_1p_3p(all_cp_pv_charging_1p, monkeypatch):
data.data.cp_data["cp3"].data.control_parameter.timestamp_last_phase_switch = 1652682252
data.data.cp_data["cp4"].data.get.currents = [0, 0, 0]
data.data.cp_data["cp5"].data.get.currents = [0, 0, 0]
for i in range(3, 6):
data.data.cp_data[f"cp{i}"].data.control_parameter.template_phases = 0

# execution
Algorithm().calc_current()
Expand Down
6 changes: 4 additions & 2 deletions packages/control/algorithm/surplus_controlled.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,12 @@ def check_submode_pv_charging(self) -> None:
for cp in get_chargepoints_by_chargemodes(CONSIDERED_CHARGE_MODES_PV_ONLY):
try:
def phase_switch_necessary() -> bool:
return cp.cp_ev_chargemode_support_phase_switch() and cp.data.get.phases_in_use != 1
return (cp.cp_state_hw_support_phase_switch() and
cp.data.get.phases_in_use != 1 and
cp.data.control_parameter.template_phases == 0)
control_parameter = cp.data.control_parameter
if cp.chargemode_changed or cp.submode_changed:
if control_parameter.state == ChargepointState.CHARGING_ALLOWED:
if (control_parameter.state in CHARGING_STATES):
if cp.data.set.charging_ev_data.ev_template.data.prevent_charge_stop is False:
threshold = evu_counter.calc_switch_off_threshold(cp)[0]
if evu_counter.calc_raw_surplus() - cp.data.set.required_power < threshold:
Expand Down
51 changes: 18 additions & 33 deletions packages/control/chargepoint/chargepoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ def check_phase_switch_completed(self):
if self.data.control_parameter.state == ChargepointState.WAIT_FOR_USING_PHASES:
if check_timestamp(self.data.control_parameter.timestamp_charge_start,
charging_ev.ev_template.data.keep_charge_active_duration) is False:
if self.cp_ev_support_phase_switch() and self.failed_phase_switches_reached():
if self.hw_supports_phase_switch() and self.failed_phase_switches_reached():
if phase_switch.phase_switch_thread_alive(self.num) is False:
self.data.control_parameter.state = ChargepointState.PHASE_SWITCH_AWAITED
if self._is_phase_switch_required() is False:
Expand All @@ -467,7 +467,7 @@ def initiate_phase_switch(self):
Pub().pub("openWB/set/chargepoint/"+str(self.num)+"/set/phases_to_use",
self.data.control_parameter.phases)
self.data.set.phases_to_use = self.data.control_parameter.phases
if self.cp_ev_support_phase_switch():
if self.hw_supports_phase_switch():
if self._is_phase_switch_required():
# Wenn die Umschaltverzögerung aktiv ist, darf nicht umgeschaltet werden.
if (self.data.control_parameter.state != ChargepointState.PERFORMING_PHASE_SWITCH and
Expand Down Expand Up @@ -569,7 +569,7 @@ def hw_bidi_capable(self) -> BidiState:
else:
return BidiState.BIDI_CAPABLE

def set_phases(self, phases: int) -> int:
def set_phases(self, phases: int, template_phases: int) -> int:
charging_ev = self.data.set.charging_ev_data
phases = min(phases, self.get_max_phase_hw())

Expand All @@ -584,12 +584,13 @@ def set_phases(self, phases: int) -> int:
phases = self.data.get.phases_in_use
else:
phases = self.data.control_parameter.phases
elif self.cp_ev_support_phase_switch() is False:
elif self.hw_supports_phase_switch() is False:
# sonst passt die Phasenzahl nicht bei Autos, die eine Phase weg schalten.
log.info(f"Phasenumschaltung an Ladepunkt {self.num} wird durch die Hardware nicht unterstützt.")
phases = phases
if phases != self.data.control_parameter.phases:
self.data.control_parameter.phases = phases
self.data.control_parameter.template_phases = template_phases
return phases

def check_cp_max_current(self, required_current: float, phases: int) -> float:
Expand Down Expand Up @@ -698,18 +699,18 @@ def update(self, ev_list: Dict[str, Ev]) -> None:
if charging_possible:
try:
charging_ev = self._get_charging_ev(vehicle, ev_list)
state, message_ev, submode, required_current, phases = charging_ev.get_required_current(
state, message_ev, submode, required_current, template_phases = charging_ev.get_required_current(
self.data.set.charge_template,
self.data.control_parameter,
self.get_max_phase_hw(),
self.cp_ev_support_phase_switch(),
self.hw_supports_phase_switch(),
self.template.data.charging_type,
self.data.control_parameter.timestamp_chargemode_changed or create_timestamp(),
self.data.set.log.imported_since_plugged,
self.hw_bidi_capable(),
self.data.get.phases_in_use)
phases = self.get_phases_by_selected_chargemode(phases)
phases = self.set_phases(phases)
required_phases = self.get_phases_by_selected_chargemode(template_phases)
required_phases = self.set_phases(required_phases, template_phases)
self._pub_connected_vehicle(charging_ev)
required_current = self.chargepoint_module.add_conversion_loss_to_current(required_current)
self.set_chargemode_changed(submode)
Expand Down Expand Up @@ -778,7 +779,9 @@ def update(self, ev_list: Dict[str, Ev]) -> None:
try:
# check für charging stop or charging interruption, if so force a soc query for the ev
if self.data.set.charge_state_prev and self.data.get.charge_state is False:
Pub().pub(f"openWB/set/vehicle/{self.data.config.ev}/get/force_soc_update", True)
Pub().pub(
f"openWB/set/vehicle/{vehicle if vehicle != -1 else self.data.config.ev}/get/force_soc_update",
True)
log.info(f"SoC-Abfrage nach Ladeunterbrechung, cp{self.num}, ev{self.data.config.ev}")
except Exception:
log.exception(f"Fehler bei Ladestop,cp{self.num}")
Expand All @@ -801,7 +804,9 @@ def update(self, ev_list: Dict[str, Ev]) -> None:
(self.data.get.plug_state is False and self.data.set.plug_state_prev) or
(self.data.get.soc_timestamp and self.data.set.charging_ev_data.data.get.soc_timestamp and
self.data.get.soc_timestamp > self.data.set.charging_ev_data.data.get.soc_timestamp)):
Pub().pub(f"openWB/set/vehicle/{self.data.config.ev}/get/force_soc_update", True)
Pub().pub(
f"openWB/set/vehicle/{vehicle if vehicle != -1 else self.data.config.ev}/get/force_soc_update",
True)
log.debug("SoC nach Anstecken")
self.set_state_and_log(message)
except Exception:
Expand Down Expand Up @@ -900,41 +905,21 @@ def _pub_connected_vehicle(self, vehicle: Ev):
except Exception:
log.exception("Fehler im Prepare-Modul")

def cp_ev_chargemode_support_phase_switch(self) -> bool:
if (self.cp_ev_support_phase_switch() and
def cp_state_hw_support_phase_switch(self) -> bool:
if (self.hw_supports_phase_switch() and
self.data.get.charge_state and
self.chargemode_support_phase_switch() and
(self.data.control_parameter.state == ChargepointState.CHARGING_ALLOWED or
self.data.control_parameter.state == ChargepointState.PHASE_SWITCH_DELAY)):
return self.failed_phase_switches_reached()
else:
return False

def cp_ev_support_phase_switch(self) -> bool:
def hw_supports_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 or
self.data.set.log.imported_since_plugged == 0))

def chargemode_support_phase_switch(self) -> bool:
control_parameter = self.data.control_parameter
pv_auto_switch = ((control_parameter.chargemode == Chargemode.PV_CHARGING or
control_parameter.chargemode == Chargemode.ECO_CHARGING) and
(control_parameter.submode == Chargemode.PV_CHARGING or
control_parameter.submode == Chargemode.INSTANT_CHARGING) and
self.data.set.charge_template.data.chargemode.pv_charging.phases_to_use == 0)
for p in self.data.set.charge_template.data.chargemode.scheduled_charging.plans:
if p.id == self.data.control_parameter.current_plan:
phases_to_use_pv = p.phases_to_use_pv
break
else:
phases_to_use_pv = 1
scheduled_auto_switch = (
control_parameter.chargemode == Chargemode.SCHEDULED_CHARGING and
control_parameter.submode == Chargemode.PV_CHARGING and
phases_to_use_pv == 0)
return (pv_auto_switch or scheduled_auto_switch)

def failed_phase_switches_reached(self) -> bool:
if ((data.data.general_data.data.chargemode_config.retry_failed_phase_switches and
self.data.control_parameter.failed_phase_switches > self.MAX_FAILED_PHASE_SWITCHES) or
Expand Down
1 change: 1 addition & 0 deletions packages/control/chargepoint/control_parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class ControlParameter:
state: ChargepointState = field(default=ChargepointState.NO_CHARGING_ALLOWED,
metadata={"topic": "control_parameter/state"})
submode: Chargemode_enum = field(default=Chargemode_enum.STOP, metadata={"topic": "control_parameter/submode"})
template_phases: int = field(default=None, metadata={"topic": "control_parameter/template_phases"})
timestamp_charge_start: Optional[float] = field(
default=None, metadata={"topic": "control_parameter/timestamp_charge_start"})
timestamp_chargemode_changed: Optional[float] = field(
Expand Down
4 changes: 2 additions & 2 deletions packages/control/chargepoint/get_phases_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,15 +160,15 @@ def __init__(self,
def test_set_phases(monkeypatch, cp: Chargepoint, params: SetPhasesParams):
# setup
mock_phase_switch_supported = Mock(name="phase_switch_supported", return_value=params.phase_switch_supported)
monkeypatch.setattr(Chargepoint, "cp_ev_support_phase_switch", mock_phase_switch_supported)
monkeypatch.setattr(Chargepoint, "hw_supports_phase_switch", mock_phase_switch_supported)
cp.data.get.phases_in_use = params.phases_in_use
cp.data.set.log.imported_since_plugged = params.imported_since_plugged
charging_ev_data = cp.data.set.charging_ev_data
charging_ev_data.ev_template.data.prevent_phase_switch = params.prevent_phase_switch
cp.data.control_parameter.phases = params.phases_in_use

# execution
phases = cp.set_phases(params.phases)
phases = cp.set_phases(params.phases, 3)

# evaluation
assert phases == params.expected_phases
2 changes: 1 addition & 1 deletion packages/control/counter.py
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ def switch_on_timer_expired(self, chargepoint: Chargepoint) -> None:
max_phases_power = ev_template.data.min_current * ev_template.data.max_phases * 230
if (control_parameter.submode == Chargemode.PV_CHARGING and
chargepoint.data.set.charge_template.data.chargemode.pv_charging.phases_to_use == 0 and
chargepoint.cp_ev_support_phase_switch() and
chargepoint.hw_supports_phase_switch() and
self.get_usable_surplus(feed_in_yield) > max_phases_power):
control_parameter.phases = ev_template.data.max_phases
msg += self.SWITCH_ON_MAX_PHASES.format(ev_template.data.max_phases)
Expand Down
13 changes: 12 additions & 1 deletion packages/control/optional_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,20 @@ def rfid_factory() -> Rfid:
class Ocpp:
active: bool = False
boot_notification_sent: bool = False
url: Optional[str] = None
_url: Optional[str] = None
version: str = "ocpp1.6"

@property
def url(self) -> Optional[str]:
return self._url

@url.setter
def url(self, value: Optional[str]):
if value is not None and not value.endswith("/"):
self._url = value + "/"
else:
self._url = value


def ocpp_factory() -> Ocpp:
return Ocpp()
Expand Down
20 changes: 10 additions & 10 deletions packages/helpermodules/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,16 @@ def systemUpdate(self, connection_id: str, payload: dict) -> None:
Pub().pub("openWB/system/update_in_progress", False)
return
parent_file = Path(__file__).resolve().parents[2]
if not SubData.general_data.data.extern and SubData.system_data["system"].data["secondary_auto_update"]:
for cp in SubData.cp_data.values():
# if chargepoint is external_openwb and not the second CP of duo and version is Release
if (
cp.chargepoint.chargepoint_module.config.type == 'external_openwb' and
cp.chargepoint.chargepoint_module.config.configuration.duo_num == 0 and
cp.chargepoint.data.get.current_branch == "Release"
):
time.sleep(2)
self.secondaryChargepointUpdate({"data": {"chargepoint": f"cp{cp.chargepoint.num}"}})
if "branch" in payload["data"] and "tag" in payload["data"]:
pub_user_message(
payload, connection_id,
Expand All @@ -833,16 +843,6 @@ def systemUpdate(self, connection_id: str, payload: dict) -> None:
run_command([
str(parent_file / "runs" / "update_self.sh"),
SubData.system_data["system"].data["current_branch"]])
if not SubData.general_data.data.extern and SubData.system_data["system"].data["secondary_auto_update"]:
for cp in SubData.cp_data.values():
# if chargepoint is external_openwb and not the second CP of duo and version is Release
if (
cp.chargepoint.chargepoint_module.config.type == 'external_openwb' and
cp.chargepoint.chargepoint_module.config.configuration.duo_num == 0 and
cp.chargepoint.data.get.current_branch == "Release"
):
time.sleep(2)
self.secondaryChargepointUpdate({"data": {"chargepoint": f"cp{cp.chargepoint.num}"}})

def systemFetchVersions(self, connection_id: str, payload: dict) -> None:
log.info("Fetch versions requested")
Expand Down
Loading