Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
81e5b75
draft
LKuemmel Jun 16, 2026
57e1bcd
draft
LKuemmel Jun 16, 2026
76c5563
fixes
LKuemmel Jun 17, 2026
cd8acd3
fixes
LKuemmel Jun 18, 2026
2a4c38c
Anlauferkennung, Betriebsmodus zurücksetzen, Befehle für Pläne (#3588)
LKuemmel Jun 24, 2026
87fccde
on time, fixes (#3612)
LKuemmel Jun 30, 2026
3bf3eae
on_time accessible via 1883 (#3626)
LKuemmel Jul 3, 2026
c33d18d
Add Consumer tab and cards to koala web theme (#3630)
Brett-S-OWB Jul 6, 2026
0ed595c
imported and exported for consumers; daily, monthly log; daily yields…
LKuemmel Jul 8, 2026
a6a79c8
Consumer cards in carousel - small screen mobile view (#3637)
Brett-S-OWB Jul 17, 2026
3f7c4b3
Intergrate consumers in koala theme charts (#3672)
Brett-S-OWB Jul 20, 2026
629af75
Add consumer component to display flow chart (#3673)
Brett-S-OWB Jul 21, 2026
5795c02
energy percentage, set usage per json, several fixes (#3705)
LKuemmel Jul 24, 2026
2c53c6e
improve wait for start
LKuemmel Jul 24, 2026
0095742
shelly, pytest (#3730)
LKuemmel Jul 29, 2026
b3b1e74
fix colors, lookup dict names and colors for consumers (#3736)
LKuemmel Jul 30, 2026
fa6884e
hide mode controls for consumer measurement only (#3715)
Brett-S-OWB Aug 3, 2026
da5cbeb
update consumer-configuration-access (user management) (#3743)
Brett-S-OWB Aug 4, 2026
4a47e30
diagram colors, pytests, remove extra meters from log data (#3742)
LKuemmel Aug 5, 2026
5fa8f97
ammend
LKuemmel Aug 6, 2026
68c8c47
fix_merge
LKuemmel Aug 7, 2026
ee275bc
switch mode on card
LKuemmel Jul 31, 2026
9f78985
update consumer button groups
Brett-S-OWB Jul 31, 2026
778544e
update message - data order in consumer card
Brett-S-OWB Jul 31, 2026
5ed84b4
linting
benderl Aug 7, 2026
f44fd2f
reapply lost changes from #3715
benderl Aug 7, 2026
90a6114
usage type self controlled (#3775)
LKuemmel Aug 7, 2026
c068076
review (#3776)
LKuemmel Aug 7, 2026
51db3a6
calc on time (#3777)
LKuemmel Aug 7, 2026
233a587
pytest (#3786)
LKuemmel Aug 10, 2026
ae2a7ed
fixes (#3794)
LKuemmel Aug 11, 2026
26cca8e
Reworked IDM and Lambda consumer and add Ovum (#3737)
seaspotter Aug 17, 2026
9b477f3
split PR: remove moduls except mqtt
LKuemmel Aug 18, 2026
62ae011
fix loadmanagement, clean up (#3819)
LKuemmel Aug 18, 2026
4460ac2
fix versions
LKuemmel Aug 19, 2026
2fcea59
fix merge error
LKuemmel Aug 21, 2026
32ddf10
consider non charging for consumers and update consumer state message…
LKuemmel Aug 21, 2026
7d35cc2
fix rebase
LKuemmel Aug 24, 2026
e9ed009
pass data object as parameter in set_power_limit methode (#3854)
LKuemmel Aug 25, 2026
f9615ef
fix some type hints (#3866)
benderl Aug 28, 2026
88e80c3
fix reset of consumer state string (#3887)
benderl Sep 7, 2026
28fad7d
pass data object as parameter in set_power_limit methode, review (#3…
LKuemmel Sep 8, 2026
ecd4d6b
Verbraucher: Fixes für Löschen & Hinzufügen (#3909)
LKuemmel Sep 9, 2026
6330dd9
Verbraucher: Fixes für Topics und Anlauferkennung (#3911)
LKuemmel Sep 9, 2026
ef33f89
fix thread handling (#3912)
LKuemmel Sep 9, 2026
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
11 changes: 10 additions & 1 deletion data/config/mosquitto/local/openwb_local.conf
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# openwb-version:20
# openwb-version:21
listener 1886 localhost
allow_anonymous true

Expand Down Expand Up @@ -28,6 +28,15 @@ topic openWB/chargepoint/+/get/# out 2
topic openWB/chargepoint/+/config/# out 2
topic openWB/chargepoint/template/# out 2

topic openWB/consumer/get/# out 2

topic openWB/consumer/+/module out 2
topic openWB/consumer/+/config out 2
topic openWB/consumer/+/extra_meter out 2
topic openWB/consumer/+/usage out 2
topic openWB/consumer/+/get/# out 2
topic openWB/consumer/+/set/# out 2

topic openWB/internal_chargepoint/# out 2

topic openWB/io/# out 2
Expand Down
104 changes: 104 additions & 0 deletions data/config/mosquitto/public/default-dynamic-security.json
Original file line number Diff line number Diff line change
Expand Up @@ -1109,6 +1109,24 @@
"priority": 0,
"allow": true
},
{
"acltype": "publishClientSend",
"topic": "openWB/set/general/chargemode_config/surplus/consumer/switch_on_delay",
"priority": 0,
"allow": true
},
{
"acltype": "publishClientSend",
"topic": "openWB/set/general/chargemode_config/surplus/consumer/switch_off_delay",
"priority": 0,
"allow": true
},
{
"acltype": "publishClientSend",
"topic": "openWB/set/general/chargemode_config/surplus/consumer/switch_off_threshold",
"priority": 0,
"allow": true
},
{
"acltype": "publishClientReceive",
"topic": "openWB/system/security/access/SurplusChargeConfiguration",
Expand Down Expand Up @@ -1168,6 +1186,24 @@
"topic": "openWB/general/chargemode_config/surplus/vehicle/switch_off_delay",
"priority": 0,
"allow": true
},
{
"acltype": "publishClientReceive",
"topic": "openWB/general/chargemode_config/surplus/consumer/switch_on_delay",
"priority": 0,
"allow": true
},
{
"acltype": "publishClientReceive",
"topic": "openWB/general/chargemode_config/surplus/consumer/switch_off_delay",
"priority": 0,
"allow": true
},
{
"acltype": "publishClientReceive",
"topic": "openWB/general/chargemode_config/surplus/consumer/switch_off_threshold",
"priority": 0,
"allow": true
}
]
},
Expand Down Expand Up @@ -1745,6 +1781,61 @@
}
]
},
{
"rolename": "consumer-configuration-access",
"textname": "Zugang zu den Verbrauchereinstellungen",
"textdescription": "Erlaubt den Zugang zu den Verbrauchereinstellungen.",
"acls": [
{
"acltype": "publishClientSend",
"topic": "openWB/consumer/+/config",
"priority": 0,
"allow": true
},
{
"acltype": "publishClientSend",
"topic": "openWB/consumer/+/module",
"priority": 0,
"allow": true
},
{
"acltype": "publishClientSend",
"topic": "openWB/consumer/+/usage",
"priority": 0,
"allow": true
},
{
"acltype": "publishClientReceive",
"topic": "openWB/consumer/+/config",
"priority": 0,
"allow": true
},
{
"acltype": "publishClientReceive",
"topic": "openWB/consumer/+/module",
"priority": 0,
"allow": true
},
{
"acltype": "publishClientReceive",
"topic": "openWB/consumer/+/usage",
"priority": 0,
"allow": true
},
{
"acltype": "publishClientReceive",
"topic": "openWB/system/configurable/consumers",
"priority": 0,
"allow": true
},
{
"acltype": "publishClientReceive",
"topic": "openWB/optional/ep/configured",
"priority": 0,
"allow": true
}
]
},
{
"rolename": "vehicle-configuration-access",
"textname": "Zugang zu den Fahrzeugeinstellungen",
Expand Down Expand Up @@ -2849,6 +2940,19 @@
}
]
},
{
"rolename": "consumer-sum-access",
"textname": "Leserechte für Verbrauchersummendaten",
"textdescription": "Erlaubt das Empfangen von Daten für die Summe aller Verbraucher.",
"acls": [
{
"acltype": "publishClientReceive",
"topic": "openWB/consumer/get/+",
"priority": 0,
"allow": true
}
]
},
{
"rolename": "tenant-energy-configuration-access",
"textname": "Leserechte für Mieterstromdaten",
Expand Down
56 changes: 56 additions & 0 deletions data/config/mosquitto/public/role-templates.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,62 @@
"allow": true
}
]
},
{
"rolename": "consumer-<id>-access",
"textname": "Leserechte für Verbraucher <id>",
"textdescription": "Erlaubt das Empfangen von Daten für Verbraucher <id>.",
"acls": [
{
"acltype": "publishClientSend",
"topic": "openWB/set/consumer/<id>/usage",
"priority": 0,
"allow": true
},
{
"acltype": "publishClientSend",
"topic": "openWB/set/command/+/todo/addConsumerSchedulePlan",
"priority": 0,
"allow": true
},
{
"acltype": "publishClientSend",
"topic": "openWB/set/command/+/todo/addConsumerTimePlan",
"priority": 0,
"allow": true
},
{
"acltype": "publishClientReceive",
"topic": "openWB/consumer/<id>/#",
"priority": 0,
"allow": true
}
]
},
{
"rolename": "consumer-<id>-write-access",
"textname": "Schreibrechte für MQTT-Verbraucher <id>",
"textdescription": "Erlaubt das Senden von Daten für Verbraucher <id>.",
"acls": [
{
"acltype": "publishClientSend",
"topic": "openWB/set/mqtt/consumer/<id>/get/#",
"priority": 0,
"allow": true
},
{
"acltype": "publishClientReceive",
"topic": "openWB/set/mqtt/consumer/<id>/get/#",
"priority": 0,
"allow": true
},
{
"acltype": "publishClientReceive",
"topic": "openWB/mqtt/consumer/<id>/#",
"priority": 0,
"allow": true
}
]
},
{
"rolename": "vehicle-<id>-access",
Expand Down
3 changes: 1 addition & 2 deletions packages/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,7 @@ def data_hc_counter_() -> None:
config=Mock(spec=Config, phase_1=1),
get=Mock(spec=Get, currents=[30, 0, 0], power=6900,
daily_imported=10000, daily_exported=0, imported=56000,
fault_state=0),
set=Mock(spec=Set, loadmanagement_available=True)))}
fault_state=0)))}
data.data.pv_data.update({"pv1": Mock(spec=Pv, data=Mock(
spec=PvData, get=Mock(spec=PvGet, power=-10000, daily_exported=6000, exported=27000, currents=None,
fault_state=0)))})
Expand Down
65 changes: 33 additions & 32 deletions packages/control/algorithm/additional_current.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import logging

from control import data
from control.algorithm import common
from control.algorithm.chargemodes import CONSIDERED_CHARGE_MODES_ADDITIONAL_CURRENT
from control.limiting_value import LoadmanagementLimit
from control.load_protocol import Load
from control.loadmanagement import Loadmanagement
from control.chargepoint.chargepoint import Chargepoint
from control.algorithm.filter_chargepoints import (get_chargepoints_by_mode_and_counter,
get_preferenced_chargepoint_charging)
from control.algorithm.filter_chargepoints import (filtered_loads_to_str, get_grouped_loads_by_mode_and_counter,
get_preferenced_load_charging)

log = logging.getLogger(__name__)

Expand All @@ -19,44 +18,46 @@ def __init__(self) -> None:

def set_additional_current(self) -> None:
common.reset_current_by_chargemode(CONSIDERED_CHARGE_MODES_ADDITIONAL_CURRENT)
for mode_tuple, counter in common.mode_and_counter_generator(CONSIDERED_CHARGE_MODES_ADDITIONAL_CURRENT):
preferenced_chargepoints, preferenced_cps_without_set_current = get_preferenced_chargepoint_charging(
get_chargepoints_by_mode_and_counter(mode_tuple, f"counter{counter.num}"))
if preferenced_chargepoints:
common.update_raw_data(preferenced_chargepoints)
log.info(f"Mode-Tuple {mode_tuple[0]} - {mode_tuple[1]} - {mode_tuple[2]}, Zähler {counter.num}")
for cp, group in data.data.counter_all_data.generator_cps_by_loadmanagement_prios(
preferenced_chargepoints):
missing_currents, counts = common.get_missing_currents_left(group)
available_currents, limit = Loadmanagement().get_available_currents(missing_currents, counter, cp)
log.debug(f"cp {cp.num} available currents {available_currents} missing currents "
for counter in common.counter_generator():
preferenced_loads_groups, preferenced_loads_without_set_current = get_preferenced_load_charging(
get_grouped_loads_by_mode_and_counter(CONSIDERED_CHARGE_MODES_ADDITIONAL_CURRENT,
f"counter{counter.num}"))
for preferenced_loads in preferenced_loads_groups:
common.update_raw_data(preferenced_loads)
if len(preferenced_loads) > 0:
log.info(f"Zähler {counter.num}, Verbraucher {filtered_loads_to_str(preferenced_loads)}")
while len(preferenced_loads):
load = preferenced_loads[0]
missing_currents, counts = common.get_missing_currents_left(preferenced_loads)
available_currents, limit = Loadmanagement().get_available_currents(missing_currents, counter, load)
log.debug(f"load {load.num} available currents {available_currents} missing currents "
f"{missing_currents} limit {limit.message}")
if limit.limiting_value is not None:
cp.data.control_parameter.limit = limit
available_for_cp = common.available_current_for_cp(cp, counts, available_currents, missing_currents)
load.data.control_parameter.limit = limit
available_for_cp = common.available_current_for_load(
load, counts, available_currents, missing_currents)
current = common.get_current_to_set(
cp.data.set.current, available_for_cp, cp.data.set.target_current)
self._set_loadmangement_message(current, limit, cp)
load.data.set.current, available_for_cp, load.data.set.target_current)
self._set_loadmangement_message(current, limit, load)
common.set_current_counterdiff(
cp.data.control_parameter.min_current,
load.data.control_parameter.min_current,
current,
cp)
if preferenced_cps_without_set_current:
for cp in preferenced_cps_without_set_current:
cp.data.set.current = cp.data.set.target_current
load)
preferenced_loads.pop(0)
for load in preferenced_loads_without_set_current:
load.data.set.current = load.data.set.target_current

# tested
def _set_loadmangement_message(self,
current: float,
limit: LoadmanagementLimit,
chargepoint: Chargepoint) -> None:
load: Load) -> None:
# Strom muss an diesem Zähler geändert werden
log.debug(
f"current {current} target {chargepoint.data.set.target_current} set current {chargepoint.data.set.current}"
f" required currents {chargepoint.data.control_parameter.required_currents}")
if (current != max(chargepoint.data.set.target_current, chargepoint.data.set.current or 0) and
f"current {current} target {load.data.set.target_current} set current {load.data.set.current}"
f" required currents {load.data.control_parameter.required_currents}")
if (current != max(load.data.set.target_current, load.data.set.current or 0) and
# Strom erreicht nicht die vorgegebene Stromstärke
round(current, 2) != round(max(
chargepoint.data.control_parameter.required_currents), 2)):
chargepoint.set_state_and_log(f"Es kann nicht mit der vorgegebenen Stromstärke geladen werden"
f"{limit.message}")
load.data.control_parameter.required_currents), 2)):
load.set_state_and_log(f"Es kann nicht mit der vorgegebenen Stromstärke geladen werden"
f"{limit.message}")
55 changes: 28 additions & 27 deletions packages/control/algorithm/bidi_charging.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import logging
from control import data
from control.algorithm.chargemodes import CONSIDERED_CHARGE_MODES_BIDI_DISCHARGE
from control.algorithm.filter_chargepoints import get_chargepoints_with_required_current_by_chargemode
from control.algorithm.filter_chargepoints import filtered_loads_to_str, get_loads_by_chargemodes
from control.chargepoint.chargepoint import Chargepoint
from helpermodules.phase_handling import voltages_mean

log = logging.getLogger(__name__)
Expand All @@ -15,30 +16,30 @@ def set_bidi(self):
grid_counter = data.data.counter_all_data.get_evu_counter()
log.debug(f"Nullpunktanpassung {grid_counter.data.set.surplus_power_left}W")
zero_point_adjustment = grid_counter
for mode_tuple in CONSIDERED_CHARGE_MODES_BIDI_DISCHARGE:
preferenced_cps = get_chargepoints_with_required_current_by_chargemode(mode_tuple)
if preferenced_cps:
log.info(
f"Mode-Tuple {mode_tuple[0]} - {mode_tuple[1]} - {mode_tuple[2]}, Zähler {grid_counter.num}")
for cp, group in data.data.counter_all_data.generator_cps_by_loadmanagement_prios(preferenced_cps):
zero_point_adjustment = grid_counter.data.set.surplus_power_left / len(group)
log.debug(f"Nullpunktanpassung für LP{cp.num}: verbleibende Leistung {zero_point_adjustment}W")
missing_currents = [zero_point_adjustment / cp.data.get.phases_in_use /
230 for i in range(0, cp.data.get.phases_in_use)]
missing_currents += [0] * (3 - len(missing_currents))
if zero_point_adjustment > 0:
if cp.data.set.charging_ev_data.charge_template.bidi_charging_allowed(
cp.data.control_parameter.current_plan, cp.data.set.charging_ev_data.data.get.soc):
for index in range(0, 3):
missing_currents[index] = min(cp.data.control_parameter.required_current,
missing_currents[index])
else:
log.info(f"LP{cp.num}: Nur bidirektional entladen erlaubt, da SoC-Limit erreicht.")
missing_currents = [0, 0, 0]
else:
preferenced_cps = get_loads_by_chargemodes(CONSIDERED_CHARGE_MODES_BIDI_DISCHARGE)
if preferenced_cps:
log.info(f"Verbraucher {filtered_loads_to_str(preferenced_cps)}")
while len(preferenced_cps):
cp: Chargepoint = preferenced_cps[0]
zero_point_adjustment = grid_counter.data.set.surplus_power_left / len(preferenced_cps)
log.debug(f"Nullpunktanpassung für LP{cp.num}: verbleibende Leistung {zero_point_adjustment}W")
missing_currents = [zero_point_adjustment / cp.data.get.phases_in_use /
230 for i in range(0, cp.data.get.phases_in_use)]
missing_currents += [0] * (3 - len(missing_currents))
if zero_point_adjustment > 0:
if cp.data.set.charging_ev_data.charge_template.bidi_charging_allowed(
cp.data.control_parameter.current_plan, cp.data.set.charging_ev_data.data.get.soc):
for index in range(0, 3):
missing_currents[index] = cp.check_min_max_current(missing_currents[index],
cp.data.get.phases_in_use)
grid_counter.update_surplus_values_left(missing_currents, voltages_mean(cp.data.get.voltages))
cp.data.set.current = missing_currents[0]
log.info(f"LP{cp.num}: Stromstärke {missing_currents}A")
missing_currents[index] = min(cp.data.control_parameter.required_current,
missing_currents[index])
else:
log.info(f"LP{cp.num}: Nur bidirektional entladen erlaubt, da SoC-Limit erreicht.")
missing_currents = [0, 0, 0]
else:
for index in range(0, 3):
missing_currents[index] = cp.check_min_max_current(missing_currents[index],
cp.data.get.phases_in_use)
grid_counter.update_surplus_values_left(missing_currents, voltages_mean(cp.data.get.voltages))
cp.data.set.current = missing_currents[0]
log.info(f"LP{cp.num}: Stromstärke {missing_currents}A")
preferenced_cps.pop(0)
Loading