Skip to content
Closed
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
71 changes: 50 additions & 21 deletions packages/helpermodules/changed_values_handler.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
from dataclasses import fields, is_dataclass
from copy import deepcopy
from dataclasses import dataclass, fields, is_dataclass
from enum import Enum
import logging
from threading import Event
from typing import Dict, List, Tuple
from typing import Any, Dict, List, Optional, Tuple
from control import data

from control.data import Data
from dataclass_utils import asdict
from helpermodules.pub import Pub

Expand Down Expand Up @@ -64,43 +63,73 @@
# self.data = SampleData()


@dataclass
class ChangedValuesSnapshot:
bat_all_data: Any
cp_all_data: Any
consumer_all_data: Any
counter_all_data: Any
optional_data: Any
pv_all_data: Any
cp_data: Dict[str, Any]
bat_data: Dict[str, Any]
counter_data: Dict[str, Any]
consumer_data: Dict[str, Any]
pv_data: Dict[str, Any]


class ChangedValuesHandler:
def __init__(self, event_module_update_completed: Event) -> None:
self.prev_data: Data = Data(event_module_update_completed)
def __init__(self) -> None:
self.prev_data: Optional[ChangedValuesSnapshot] = None

def store_initial_values(self):
try:
# speichern der Daten zum Zyklus-Beginn, um später die geänderten Werte zu ermitteln
self.prev_data.copy_data()
# Snapshot des Arbeitszustands, den der Handler anschließend verändert.
current_data = data.data
self.prev_data = ChangedValuesSnapshot(
bat_all_data=deepcopy(current_data.bat_all_data.data),
cp_all_data=deepcopy(current_data.cp_all_data.data.get),
consumer_all_data=deepcopy(current_data.consumer_all_data.data),
counter_all_data=deepcopy(current_data.counter_all_data.data),
optional_data=deepcopy(current_data.optional_data.data),
pv_all_data=deepcopy(current_data.pv_all_data.data),
cp_data={key: deepcopy(value.data) for key, value in current_data.cp_data.items()},
bat_data={key: deepcopy(value.data) for key, value in current_data.bat_data.items()},
counter_data={key: deepcopy(value.data) for key, value in current_data.counter_data.items()},
consumer_data={key: deepcopy(value.data) for key, value in current_data.consumer_data.items()},
pv_data={key: deepcopy(value.data) for key, value in current_data.pv_data.items()},
)
except Exception as e:
log.exception(e)

def pub_changed_values(self):
try:
if self.prev_data is None:
return
# veröffentlichen der geänderten Werte
self._update_value("openWB/set/bat/", self.prev_data.bat_all_data.data, data.data.bat_all_data.data)
self._update_value("openWB/set/chargepoint/", self.prev_data.cp_all_data.data.get,
self._update_value("openWB/set/bat/", self.prev_data.bat_all_data, data.data.bat_all_data.data)
self._update_value("openWB/set/chargepoint/", self.prev_data.cp_all_data,
data.data.cp_all_data.data.get)
self._update_value("openWB/set/consumer/", self.prev_data.consumer_all_data.data,
self._update_value("openWB/set/consumer/", self.prev_data.consumer_all_data,
data.data.consumer_all_data.data)
self._update_value("openWB/set/counter/", self.prev_data.counter_all_data.data,
self._update_value("openWB/set/counter/", self.prev_data.counter_all_data,
data.data.counter_all_data.data)
self._update_value("openWB/set/optional/", self.prev_data.optional_data.data,
self._update_value("openWB/set/optional/", self.prev_data.optional_data,
data.data.optional_data.data)
self._update_value("openWB/set/pv/", self.prev_data.pv_all_data.data,
self._update_value("openWB/set/pv/", self.prev_data.pv_all_data,
data.data.pv_all_data.data)
for key, value in data.data.cp_data.items():
self._update_value(f"openWB/set/chargepoint/{value.num}/", self.prev_data.cp_data[key].data, value.data)
self._update_value(f"openWB/set/chargepoint/{value.num}/", self.prev_data.cp_data[key], value.data)
for key, value in data.data.bat_data.items():
self._update_value(f"openWB/set/bat/{value.num}/", self.prev_data.bat_data[key].data, value.data)
self._update_value(f"openWB/set/bat/{value.num}/", self.prev_data.bat_data[key], value.data)
for key, value in data.data.counter_data.items():
self._update_value(f"openWB/set/counter/{value.num}/",
self.prev_data.counter_data[key].data, value.data)
self.prev_data.counter_data[key], value.data)
for key, value in data.data.consumer_data.items():
self._update_value(f"openWB/set/consumer/{value.num}/",
self.prev_data.consumer_data[key].data, value.data)
self.prev_data.consumer_data[key], value.data)
for key, value in data.data.pv_data.items():
self._update_value(f"openWB/set/pv/{value.num}/", self.prev_data.pv_data[key].data, value.data)
self._update_value(f"openWB/set/pv/{value.num}/", self.prev_data.pv_data[key], value.data)
# chargepoint, ev template, autolock, time and scheduled charging plans mutable_by_algorithm immer false
except Exception as e:
log.exception(e)
Expand Down Expand Up @@ -146,8 +175,8 @@ def _update_value(self, topic_prefix, data_inst_previous, data_inst):


class ChangedValuesContext:
def __init__(self, event_module_update_completed: Event):
self.changed_values_handler = ChangedValuesHandler(event_module_update_completed)
def __init__(self):
self.changed_values_handler = ChangedValuesHandler()

def __enter__(self):
self.changed_values_handler.store_initial_values()
Expand Down
36 changes: 33 additions & 3 deletions packages/helpermodules/changed_values_handler_test.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
from dataclasses import dataclass, field
from enum import IntEnum
from types import SimpleNamespace
from typing import Dict, List, Optional, Tuple
from unittest.mock import Mock

import pytest

from dataclass_utils import asdict
from dataclass_utils.factories import currents_list_factory
from control import data
from helpermodules.changed_values_handler import ChangedValuesHandler

NONE_TYPE = type(None)
Expand Down Expand Up @@ -106,12 +108,40 @@ class Params:
@pytest.mark.parametrize("params", cases, ids=[c.name for c in cases])
def test_update_value(params: Params, mock_pub: Mock, monkeypatch):
# setup
handler = ChangedValuesHandler(Mock())
handler = ChangedValuesHandler()

# execution
handler._update_value("openWB/", SampleData(), params.sample_data)

# evaluation
assert len(mock_pub.method_calls) - 1 == params.expected_calls
assert len(mock_pub.method_calls) == params.expected_calls
if params.expected_calls > 0:
assert mock_pub.method_calls[1].args == params.expected_pub_call
assert mock_pub.method_calls[0].args == params.expected_pub_call


def test_store_initial_values_snapshots_current_data(monkeypatch):
# setup
source = SimpleNamespace(
bat_all_data=SimpleNamespace(data={"value": [1]}),
cp_all_data=SimpleNamespace(data=SimpleNamespace(get={"value": [2]})),
consumer_all_data=SimpleNamespace(data={"value": [3]}),
counter_all_data=SimpleNamespace(data={"value": [4]}),
optional_data=SimpleNamespace(data={"value": [5]}),
pv_all_data=SimpleNamespace(data={"value": [6]}),
cp_data={"cp0": SimpleNamespace(data={"value": [7]})},
bat_data={},
counter_data={},
consumer_data={},
pv_data={},
)
monkeypatch.setattr(data, "data", source, raising=False)
handler = ChangedValuesHandler()

# execution
handler.store_initial_values()
source.cp_data["cp0"].data["value"].append(8)

# evaluation
assert handler.prev_data is not None
assert handler.prev_data.cp_data["cp0"] == {"value": [7]}
assert handler.prev_data.cp_all_data == {"value": [2]}
8 changes: 5 additions & 3 deletions packages/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def handler_with_control_interval():
wait_for_module_update_completed(loadvars_.event_module_update_completed,
"openWB/set/system/device/module_update_completed")
data.data.copy_data()
with ChangedValuesContext(loadvars_.event_module_update_completed):
with ChangedValuesContext():
self.heartbeat = True
if data.data.system_data["system"].data["perform_update"]:
data.data.system_data["system"].perform_update()
Expand Down Expand Up @@ -180,7 +180,8 @@ def handler5MinAlgorithm(self):
ausführt, die nur alle 5 Minuten ausgeführt werden müssen.
"""
try:
with ChangedValuesContext(loadvars_.event_module_update_completed):
data.data.copy_data()
with ChangedValuesContext():
entries = save_log()
daily_totals = update_daily_yields(entries)
if daily_totals is not None:
Expand Down Expand Up @@ -233,6 +234,7 @@ def handler5Min(self):
@__with_handler_lock(error_threshold=60)
def handler_midnight(self):
try:
data.data.copy_data()
today = timecheck.create_timestamp_YYYYMMDD()
previous_day = timecheck.get_relative_date_string(today, day_offset=-1)
save_daily_source_totals(previous_day)
Expand All @@ -245,7 +247,7 @@ def handler_midnight(self):
thread_errors_path = Path(Path(__file__).resolve().parents[1]/"ramdisk"/"thread_errors.log")
with thread_errors_path.open("w") as f:
f.write("")
with ChangedValuesContext(loadvars_.event_module_update_completed):
with ChangedValuesContext():
for consumer in data.data.consumer_data.values():
consumer.midnight_handler()
except Exception:
Expand Down
Loading