Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
okaegi committed Sep 26, 2024
2 parents c03f9c9 + 58f345b commit a6c04c1
Show file tree
Hide file tree
Showing 647 changed files with 7,454 additions and 6,229 deletions.
37 changes: 37 additions & 0 deletions .github/workflows/build_display_theme_colors.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Build Display Theme Colors

on:
push:
paths:
- packages/modules/display_themes/colors/source/**
branches:
- master

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout Repository
uses: actions/checkout@v4

- name: Setup Node.js (v20)
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: packages/modules/display_themes/colors/source/package-lock.json

- name: Install Dependencies and Build
run: |
cd packages/modules/display_themes/colors/source
npm install
npm run build --if-present
- name: Commit and Push Changes
run: |
git config user.name "${{ github.actor }}"
git config user.email "${{ github.actor }}@users.noreply.github.com"
git add packages/modules/display_themes/colors/web
git commit -m "Build Display Theme: Colors"
git push
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ The following versions are maintained and supported:
## Reporting a Vulnerability

Please use the contact form at openwb.de for reporting a found vulnerability:
https://openwb.de/main/?page_id=484
<https://openwb.de/main/?page_id=484>
6 changes: 4 additions & 2 deletions data/config/mosquitto/mosquitto_local_init
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
#! /bin/sh

# openwb-version:1

# JFL 20190529: patched startup script for multiple mosquitto instances. Rename
# to an instance name, e.g. mosquitto_dev to initiate an instance expecting its
# config in /etc/mosquitto/mosquitto_dev (i.e. based on this script's name)

### BEGIN INIT INFO
# Provides: mosquitto
# Required-Start: $remote_fs $syslog
# Provides: mosquitto_local
# Required-Start: $remote_fs $syslog mosquitto
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
Expand Down
3 changes: 2 additions & 1 deletion data/config/openwb2.service
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# openwb-version:2
# openwb-version:4
[Unit]
Description="Regelung openWB 2.0"
After=mosquitto_local.service

[Service]
User=openwb
Expand Down
3 changes: 2 additions & 1 deletion data/config/openwbRemoteSupport.service
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# openwb-version:1
# openwb-version:3
[Unit]
Description="Remote Support Handler openWB 2.0"
After=mosquitto_local.service

[Service]
User=openwb
Expand Down
8 changes: 7 additions & 1 deletion docs/Cloud-Sicherung.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
_Einstellungen -> System -> System -> Sicherung/Wiederherstellung_

In den Sicherungseinstellungen kann ein Cloud-Dienst für automatische Sicherungen hinterlegt werden. Die Konfiguration des Cloud-Dienstes wird in diesem Wiki-Beitrag beschrieben. Folgende Anbieter werden unterstützt:
In den Sicherungseinstellungen kann ein Cloud-Dienst für automatische Sicherungen hinterlegt werden.
Die Konfiguration des Cloud-Dienstes wird in diesem Wiki-Beitrag beschrieben.

Automatische Sicherungen werden nur ausgeführt, wenn die openWB als *primary* konfiguriert (oder die einzige) ist.
Auf als *secondary* konfigurierten openWBs werden nur manuelle Sicherungen und Sicherungen vor einem Update (falls aktiviert) ausgeführt, da hier keine Arbeitsdaten (Log-Dateien) zu sichern sind.

Folgende Anbieter werden unterstützt:

* [NextCloud](https://github.com/openWB/core/wiki/NextCloud-als-Sicherungs-Cloud-einrichten)
* [Samba](https://github.com/openWB/core/wiki/Samba-als-Sicherung-einrichten)
8 changes: 7 additions & 1 deletion packages/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@
from control.counter_all import CounterAll
from control.pv import Pv, PvData
from control.pv import Get as PvGet
from helpermodules import pub, timecheck
from helpermodules import hardware_configuration, pub, timecheck


@pytest.fixture(autouse=True)
def mock_open_file(monkeypatch) -> None:
mock_config = Mock(return_value={"dc_charging": False, "openwb-version": 1, "max_c_socket": 32})
monkeypatch.setattr(hardware_configuration, "_read_configuration", mock_config)


@pytest.fixture(autouse=True)
Expand Down
11 changes: 8 additions & 3 deletions packages/control/algorithm/additional_current.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ def set_additional_current(self) -> None:
cp = preferenced_chargepoints[0]
missing_currents, counts = common.get_missing_currents_left(preferenced_chargepoints)
available_currents, limit = Loadmanagement().get_available_currents(missing_currents, counter)
log.debug(f"cp {cp.num} available currents {available_currents} missing currents "
f"{missing_currents} limit {limit}")
cp.data.control_parameter.limit = limit
available_for_cp = common.available_current_for_cp(cp, 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, counter)
common.set_current_counterdiff(
current - cp.data.set.charging_ev_data.ev_template.data.min_current,
cp.data.control_parameter.min_current,
current,
cp)
preferenced_chargepoints.pop(0)
Expand All @@ -50,9 +52,12 @@ def _set_loadmangement_message(self,
chargepoint: Chargepoint,
counter: Counter) -> 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
# Strom erreicht nicht die vorgegebene Stromstärke
current != max(
chargepoint.data.control_parameter.required_currents)):
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.value.format(get_component_name_by_id(counter.num))}")
4 changes: 2 additions & 2 deletions packages/control/algorithm/algorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def calc_current(self) -> None:
common.reset_current()
log.info("**Mindestrom setzen**")
self.min_current.set_min_current()
log.info("**Sollstrom setzen**")
log.info("**Soll-Strom setzen**")
common.reset_current_to_target_current()
self.additional_current.set_additional_current()
counter.limit_raw_power_left_to_surplus(self.evu_counter.calc_raw_surplus())
Expand All @@ -48,7 +48,7 @@ def calc_current(self) -> None:

def _check_auto_phase_switch_delay(self) -> None:
""" geht alle LP durch und prüft, ob eine Ladung aktiv ist, ob automatische Phasenumschaltung
möglich ist und ob ob ein Timer gestartet oder geChargemode.STOPpt werden muss oder ob
möglich ist und ob ob ein Timer gestartet oder gestoppt werden muss oder ob
ein Timer abgelaufen ist.
"""
for cp in data.data.cp_data.values():
Expand Down
52 changes: 33 additions & 19 deletions packages/control/algorithm/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from control.chargemode import Chargemode
from control.chargepoint.chargepoint import Chargepoint
from control.counter import Counter
from helpermodules.timecheck import check_timestamp
from modules.common.component_type import ComponentType

log = logging.getLogger(__name__)
Expand All @@ -29,6 +30,8 @@
(None, Chargemode.STOP, True),
(None, Chargemode.STOP, False))

LESS_CHARGING_TIMEOUT = 60

# tested


Expand Down Expand Up @@ -62,21 +65,27 @@ def mode_and_counter_generator(chargemodes: List) -> Iterable[Tuple[Tuple[Option
def get_min_current(chargepoint: Chargepoint) -> Tuple[List[float], List[int]]:
min_currents = [0.0]*3
counts = [0]*3
charging_ev_data = chargepoint.data.set.charging_ev_data
required_currents = chargepoint.data.control_parameter.required_currents
for i in range(3):
if required_currents[i] != 0:
counts[i] += 1
min_currents[i] = charging_ev_data.ev_template.data.min_current
min_currents[i] = chargepoint.data.control_parameter.min_current
else:
min_currents[i] = 0
return min_currents, counts

# tested


def set_current_counterdiff(diff: float, current: float, chargepoint: Chargepoint, surplus: bool = False) -> None:
def set_current_counterdiff(diff_curent: float,
current: float,
chargepoint: Chargepoint,
surplus: bool = False) -> None:
required_currents = chargepoint.data.control_parameter.required_currents
considered_current = consider_less_charging_chargepoint_in_loadmanagement(
chargepoint, current)
# gar nicht ladende Autos?
diff = max(considered_current - diff_curent, 0)
diffs = [diff if required_currents[i] != 0 else 0 for i in range(3)]
if max(diffs) > 0:
counters = data.data.counter_all_data.get_counters_to_check(chargepoint.num)
Expand All @@ -99,7 +108,7 @@ def get_current_to_set(set_current: float, diff: float, prev_current: float) ->
new_current = prev_current + diff
if set_current is not None:
if new_current > set_current:
log.debug("Neuer Sollstrom darf nicht höher als bisher gesetzter sein: "
log.debug("Neuer Soll-Strom darf nicht höher als bisher gesetzter sein: "
f"bisher {set_current}A, neuer {new_current}")
return set_current
return new_current
Expand All @@ -126,24 +135,23 @@ def available_current_for_cp(chargepoint: Chargepoint,
def update_raw_data(preferenced_chargepoints: List[Chargepoint],
diff_to_zero: bool = False,
surplus: bool = False) -> None:
"""alle CP, die schon einen Sollstrom haben, wieder rausrechnen, da dieser neu gesetzt wird
"""alle CP, die schon einen Soll-Strom haben, wieder herausrechnen, da dieser neu gesetzt wird
und die neue Differenz bei den Zählern eingetragen wird."""
for chargepoint in preferenced_chargepoints:
if consider_not_charging_chargepoint_in_loadmanagement(chargepoint):
continue
charging_ev_data = chargepoint.data.set.charging_ev_data
required_currents = chargepoint.data.control_parameter.required_currents
max_target_set_current = max(chargepoint.data.set.target_current, chargepoint.data.set.current or 0)
max_target_set_current = consider_less_charging_chargepoint_in_loadmanagement(
chargepoint, max_target_set_current)

if diff_to_zero is False:
if charging_ev_data.ev_template.data.min_current < max_target_set_current:
diffs = [charging_ev_data.ev_template.data.min_current -
if chargepoint.data.control_parameter.min_current < max_target_set_current:
diffs = [chargepoint.data.control_parameter.min_current -
max_target_set_current if required_currents[i] != 0 else 0 for i in range(3)]
else:
continue
else:
if charging_ev_data.ev_template.data.min_current <= max_target_set_current:
diffs = [-charging_ev_data.ev_template.data.min_current if required_currents[i]
if chargepoint.data.control_parameter.min_current <= max_target_set_current:
diffs = [-chargepoint.data.control_parameter.min_current if required_currents[i]
!= 0 else 0 for i in range(3)]
else:
continue
Expand All @@ -155,26 +163,32 @@ def update_raw_data(preferenced_chargepoints: List[Chargepoint],
data.data.counter_data[counter].update_values_left(diffs)


def consider_not_charging_chargepoint_in_loadmanagement(cp: Chargepoint) -> bool:
# tested
return data.data.counter_all_data.data.config.reserve_for_not_charging is False and max(cp.data.get.currents) == 0

def consider_less_charging_chargepoint_in_loadmanagement(cp: Chargepoint, set_current: float) -> bool:
if (data.data.counter_all_data.data.config.consider_less_charging is False and
((set_current -
cp.data.set.charging_ev_data.ev_template.data.nominal_difference) > max(cp.data.get.currents) and
cp.data.control_parameter.timestamp_charge_start is not None and
check_timestamp(cp.data.control_parameter.timestamp_charge_start, LESS_CHARGING_TIMEOUT) is False)):
log.debug(
f"LP {cp.num} lädt deutlich unter dem Sollstrom und wird nur mit {cp.data.get.currents}A berücksichtigt.")
return max(cp.data.get.currents)
else:
return set_current
# tested


def get_missing_currents_left(preferenced_chargepoints: List[Chargepoint]) -> Tuple[List[float], List[int]]:
missing_currents = [0.0]*3
counts = [0]*3
for chargepoint in preferenced_chargepoints:
charging_ev_data = chargepoint.data.set.charging_ev_data
required_currents = chargepoint.data.control_parameter.required_currents
for i in range(0, 3):
if required_currents[i] != 0:
counts[i] += 1
try:
missing_currents[i] += required_currents[i] - charging_ev_data.ev_template.data.min_current
missing_currents[i] += required_currents[i] - chargepoint.data.control_parameter.min_current
except KeyError:
missing_currents[i] += max(required_currents) - charging_ev_data.ev_template.data.min_current
missing_currents[i] += max(required_currents) - chargepoint.data.control_parameter.min_current
else:
missing_currents[i] += 0
return missing_currents, counts
Expand Down
32 changes: 16 additions & 16 deletions packages/control/algorithm/common_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,9 @@ def test_reset_current(set_current: int, expected_current: int):
@pytest.mark.parametrize(
"diff, required_currents, expected_set_current, expected_diffs",
[
pytest.param(2, [10, 0, 0], 8, [2, 0, 0], id="set diff one phase"),
pytest.param(2, [12]*3, 8, [2]*3, id="set diff three phases"),
pytest.param(8, [8]*3, 8, [8]*3, id="set min current three phases"),
pytest.param(0, [8]*3, 8, [0]*3, id="min current is already set, three phases"),
pytest.param(10, [10, 0, 0], 10, [2, 0, 0], id="set diff one phase"),
pytest.param(10, [12]*3, 10, [2]*3, id="set diff three phases"),
pytest.param(8, [8]*3, 8, [0]*3, id="min current is already set, three phases"),
])
def test_set_current_counterdiff(diff: float,
required_currents: List[float],
Expand All @@ -55,11 +54,11 @@ def test_set_current_counterdiff(diff: float,
data.data.counter_data = {"cp0": Mock(spec=Counter), "cp6": Mock(spec=Counter)}

# evaluation
common.set_current_counterdiff(diff, 8, cp)
common.set_current_counterdiff(8, diff, cp)

# assertion
assert cp.data.set.current == expected_set_current
if diff != 0:
if max(expected_diffs) != 0:
assert data.data._counter_data['cp0'].update_values_left.call_args_list[0][0][0] == expected_diffs
assert data.data._counter_data['cp6'].update_values_left.call_args_list[0][0][0] == expected_diffs

Expand Down Expand Up @@ -152,23 +151,24 @@ def setup_cp(num: int, required_currents) -> Chargepoint:


@pytest.mark.parametrize(
"reserve_for_not_charging, get_currents, expected_considered",
"consider_less_charging, get_currents, expected_considered",
[
pytest.param(True, [0]*3, False, id="reserve_for_not_charging active"),
pytest.param(True, [6]*3, False, id="reserve_for_not_charging active"),
pytest.param(False, [0]*3, True, id="not charging"),
pytest.param(False, [6]*3, False, id="charging"),
pytest.param(False, [6]*3, 6, id="not consider_less_charging, charging less"),
pytest.param(False, [10]*3, 10, id="not consider_less_charging, charging with set current"),
pytest.param(True, [0]*3, 10, id="consider_less_charging"),
])
def test_consider_not_charging_chargepoint_in_loadmanagement(reserve_for_not_charging: bool,
get_currents: List[float],
expected_considered: bool):
def test_consider_less_charging_chargepoint_in_loadmanagement(consider_less_charging: bool,
get_currents: List[float],
expected_considered: bool):
# setup
cp = Chargepoint(4, None)
cp.data.get.currents = get_currents
data.data.counter_all_data.data.config.reserve_for_not_charging = reserve_for_not_charging
cp.data.set.current = 10
cp.data.control_parameter.timestamp_charge_start = 1652683152
data.data.counter_all_data.data.config.consider_less_charging = consider_less_charging

# evaluation
considered = common.consider_not_charging_chargepoint_in_loadmanagement(cp)
considered = common.consider_less_charging_chargepoint_in_loadmanagement(cp, 10)

# assertion
assert considered == expected_considered
2 changes: 1 addition & 1 deletion packages/control/algorithm/filter_chargepoints_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def mock_cp(cp: Chargepoint, num: int):
Chargemode.INSTANT_CHARGING, False),
1, (Chargemode.SCHEDULED_CHARGING,
Chargemode.INSTANT_CHARGING, True),
[mock_cp1], id="cp2 is prioritised")
[mock_cp1], id="cp2 is prioritized")
])
def test_get_chargepoints_by_mode(set_mode_tuple: Tuple[Optional[str], str, bool],
charging_ev_1: int,
Expand Down
3 changes: 2 additions & 1 deletion packages/control/algorithm/integration_test/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def data_() -> None:
data.data.cp_data[f"cp{i}"].data.set.plug_time = f"12/01/2022, 15:0{i}:11"
data.data.cp_data[f"cp{i}"].data.set.charging_ev_data.ev_template.data.nominal_difference = 2
data.data.cp_data["cp3"].data.set.charging_ev_data.ev_template.data.min_current = 10
data.data.cp_data["cp3"].data.control_parameter.min_current = 10
data.data.bat_data.update({"bat2": Bat(2), "all": BatAll()})
data.data.pv_data.update({"pv1": Pv(1)})
data.data.counter_data.update({
Expand All @@ -46,7 +47,7 @@ def data_() -> None:
data.data.counter_data["counter6"].data.config.max_total_power = 11000
data.data.counter_all_data = CounterAll()
data.data.counter_all_data.data.get.hierarchy = NESTED_HIERARCHY
data.data.counter_all_data.data.config.reserve_for_not_charging = True
data.data.counter_all_data.data.config.consider_less_charging = True


@dataclass
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
def all_cp_instant_charging_1p():
for i in range(3, 6):
control_parameter = data.data.cp_data[f"cp{i}"].data.control_parameter
control_parameter.min_current = data.data.cp_data[
f"cp{i}"].data.set.charging_ev_data.ev_template.data.min_current
control_parameter.required_currents = [0]*3
control_parameter.required_currents[i-3] = 16
control_parameter.required_current = 16
Expand All @@ -34,6 +36,8 @@ def all_cp_charging_1p():
def all_cp_instant_charging_3p():
for i in range(3, 6):
control_parameter = data.data.cp_data[f"cp{i}"].data.control_parameter
control_parameter.min_current = data.data.cp_data[
f"cp{i}"].data.set.charging_ev_data.ev_template.data.min_current
control_parameter.required_currents = [16]*3
control_parameter.required_current = 16
control_parameter.chargemode = Chargemode.INSTANT_CHARGING
Expand Down
Loading

0 comments on commit a6c04c1

Please sign in to comment.