Skip to content

Commit dabe0a0

Browse files
committed
Revert "Feature integrated charging plans (openWB#2498)"
This reverts commit acfc3a1.
1 parent 9d0a8d6 commit dabe0a0

529 files changed

Lines changed: 2747 additions & 673 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/control/chargepoint/chargepoint.py

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
Tag-Liste: Tags, mit denen der Ladepunkt freigeschaltet werden kann. Ist diese leer, kann mit jedem Tag der Ladepunkt
1515
freigeschaltet werden.
1616
"""
17+
import copy
1718
from dataclasses import asdict
1819
import dataclasses
1920
import logging
@@ -33,6 +34,7 @@
3334
from control.ev.ev import Ev
3435
from control import phase_switch
3536
from control.chargepoint.chargepoint_state import CHARGING_STATES, ChargepointState
37+
from helpermodules.abstract_plans import ScheduledChargingPlan, TimeChargingPlan
3638
from helpermodules.broker import BrokerClient
3739
from helpermodules.phase_mapping import convert_single_evu_phase_to_cp_phase
3840
from helpermodules.pub import Pub
@@ -778,8 +780,41 @@ def __get_payload(client, userdata, msg):
778780
Pub().pub(topic, "")
779781

780782
def update_charge_template(self, charge_template: ChargeTemplate) -> None:
781-
Pub().pub(f"openWB/set/chargepoint/{self.num}/set/charge_template",
782-
dataclasses.asdict(charge_template.data))
783+
self._clear_template_topics(f'openWB/chargepoint/{self.num}/set/charge_template/#')
784+
self.data.set.charge_template = copy.deepcopy(charge_template)
785+
pub_template = copy.deepcopy(self.data.set.charge_template.data)
786+
pub_template = dataclasses.asdict(pub_template)
787+
pub_template["chargemode"]["scheduled_charging"]["plans"].clear()
788+
pub_template["time_charging"]["plans"].clear()
789+
Pub().pub(f"openWB/set/chargepoint/{self.num}/set/charge_template", pub_template)
790+
for id, plan in self.data.set.charge_template.data.time_charging.plans.items():
791+
Pub().pub(f"openWB/set/chargepoint/{self.num}/set/charge_template/time_charging/plans/{id}",
792+
dataclasses.asdict(plan))
793+
for id, plan in self.data.set.charge_template.data.chargemode.scheduled_charging.plans.items():
794+
Pub().pub(f"openWB/set/chargepoint/{self.num}/set/charge_template/chargemode/scheduled_charging/plans/{id}",
795+
dataclasses.asdict(plan))
796+
797+
def update_bare_charge_template(self, charge_template: ChargeTemplate) -> None:
798+
self._clear_template_topics(f"openWB/chargepoint/{self.num}/set/charge_template")
799+
self.data.set.charge_template = copy.deepcopy(charge_template)
800+
pub_template = copy.deepcopy(self.data.set.charge_template.data)
801+
pub_template = dataclasses.asdict(pub_template)
802+
pub_template["chargemode"]["scheduled_charging"]["plans"].clear()
803+
pub_template["time_charging"]["plans"].clear()
804+
Pub().pub(f"openWB/set/chargepoint/{self.num}/set/charge_template", pub_template)
805+
806+
def update_charge_template_scheduled_plan(self, plan: ScheduledChargingPlan) -> None:
807+
self._clear_template_topics(
808+
f"openWB/chargepoint/{self.num}/set/charge_template/chargemode/scheduled_charging/plans/{plan.id}")
809+
Pub().pub(f"openWB/set/chargepoint/{self.num}"
810+
f"/set/charge_template/chargemode/scheduled_charging/plans/{plan.id}",
811+
dataclasses.asdict(plan))
812+
813+
def update_charge_template_time_plan(self, plan: TimeChargingPlan) -> None:
814+
self._clear_template_topics(
815+
f"openWB/chargepoint/{self.num}/set/charge_template/time_charging/plans/{plan.id}")
816+
Pub().pub(f"openWB/set/chargepoint/{self.num}/set/charge_template/time_charging/plans/{plan.id}",
817+
dataclasses.asdict(plan))
783818

784819
def _pub_connected_vehicle(self, vehicle: Ev):
785820
""" published die Daten, die zur Anzeige auf der Hauptseite benötigt werden.
@@ -857,7 +892,8 @@ def chargemode_support_phase_switch(self) -> bool:
857892
scheduled_auto_switch = (
858893
control_parameter.chargemode == Chargemode.SCHEDULED_CHARGING and
859894
control_parameter.submode == Chargemode.PV_CHARGING and
860-
phases_to_use_pv == 0)
895+
self.data.set.charge_template.data.chargemode.scheduled_charging.plans[
896+
str(self.data.control_parameter.current_plan)].phases_to_use_pv == 0)
861897
return (pv_auto_switch or scheduled_auto_switch)
862898

863899
def failed_phase_switches_reached(self) -> bool:

packages/control/chargepoint/chargepoint_template.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
from dataclasses import asdict, dataclass, field
22
import logging
33
import traceback
4-
from typing import List
4+
from typing import Dict, List
55

66
from control import data
77
from control.ev import ev as ev_module
88
from control.chargepoint.charging_type import ChargingType
9-
from dataclass_utils.factories import empty_list_factory
9+
from dataclass_utils.factories import empty_dict_factory, empty_list_factory
1010
from helpermodules.abstract_plans import AutolockPlan
1111
from helpermodules import timecheck
1212

@@ -16,13 +16,18 @@
1616

1717
def get_chargepoint_template_default():
1818
default = asdict(CpTemplateData())
19+
default["autolock"].pop("plans")
1920
return default
2021

2122

23+
def get_autolock_plan_default():
24+
return asdict(AutolockPlan())
25+
26+
2227
@dataclass
2328
class Autolock:
2429
active: bool = False
25-
plans: List[AutolockPlan] = field(default_factory=empty_list_factory)
30+
plans: Dict[int, AutolockPlan] = field(default_factory=empty_dict_factory)
2631
wait_for_charging_end: bool = False
2732

2833

packages/control/ev/charge_template.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,41 @@
22
import datetime
33
import logging
44
import traceback
5-
from typing import List, Optional, Tuple
5+
from typing import Optional, Tuple
66

77
from control import data
88
from control.chargepoint.charging_type import ChargingType
99
from control.ev.ev_template import EvTemplate
10-
from dataclass_utils.factories import empty_list_factory
11-
from helpermodules.abstract_plans import Limit, TimeChargingPlan, limit_factory, ScheduledChargingPlan
10+
from dataclass_utils.factories import empty_dict_factory
11+
from helpermodules.abstract_plans import Limit, limit_factory, ScheduledChargingPlan
1212
from helpermodules import timecheck
1313
log = logging.getLogger(__name__)
1414

1515

1616
def get_new_charge_template() -> dict:
1717
ct_default = asdict(ChargeTemplateData())
18+
ct_default["chargemode"]["scheduled_charging"].pop("plans")
19+
ct_default["time_charging"].pop("plans")
1820
return ct_default
1921

2022

2123
def get_charge_template_default() -> dict:
2224
ct_default = asdict(ChargeTemplateData(name="Standard-Lade-Profil"))
25+
ct_default["chargemode"]["scheduled_charging"].pop("plans")
26+
ct_default["time_charging"].pop("plans")
2327
return ct_default
2428

2529

2630
@dataclass
2731
class ScheduledCharging:
28-
plans: List[ScheduledChargingPlan] = field(default_factory=empty_list_factory, metadata={
32+
plans: dict = field(default_factory=empty_dict_factory, metadata={
2933
"topic": ""}) # Dict[int,ScheduledChargingPlan] wird bei der dict to dataclass Konvertierung nicht unterstützt
3034

3135

3236
@dataclass
3337
class TimeCharging:
3438
active: bool = False
35-
plans: List[TimeChargingPlan] = field(default_factory=empty_list_factory, metadata={
39+
plans: dict = field(default_factory=empty_dict_factory, metadata={
3640
"topic": ""}) # Dict[int, TimeChargingPlan] wird bei der dict to dataclass Konvertierung nicht unterstützt
3741

3842

@@ -310,7 +314,7 @@ def scheduled_charging_recent_plan(self,
310314
chargemode_switch_timestamp: float,
311315
control_parameter: ControlParameter) -> Optional[SelectedPlan]:
312316
plans_diff_end_date = []
313-
for p in self.data.chargemode.scheduled_charging.plans:
317+
for p in self.data.chargemode.scheduled_charging.plans.values():
314318
if p.active:
315319
if p.limit.selected == "soc" and soc is None:
316320
raise ValueError("Um Zielladen mit SoC-Ziel nutzen zu können, bitte ein SoC-Modul konfigurieren "
@@ -335,9 +339,7 @@ def scheduled_charging_recent_plan(self,
335339
plan_id = list(plan_dict.keys())[0]
336340
plan_end_time = list(plan_dict.values())[0]
337341

338-
for p in self.data.chargemode.scheduled_charging.plans:
339-
if p.id == plan_id:
340-
plan = p
342+
plan = self.data.chargemode.scheduled_charging.plans[str(plan_id)]
341343

342344
remaining_time, missing_amount, phases, duration = self._calc_remaining_time(
343345
plan, plan_end_time, soc, ev_template, used_amount, max_hw_phases, phase_switch_supported,

packages/control/ev/charge_template_test.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ def test_search_plan(check_duration_return1: Tuple[Optional[float], bool],
207207
plan_mock_0 = Mock(spec=ScheduledChargingPlan, active=True, current=14, id=0, limit=Limit(selected="amount"))
208208
plan_mock_1 = Mock(spec=ScheduledChargingPlan, active=True, current=14, id=1, limit=Limit(selected="amount"))
209209
plan_mock_2 = Mock(spec=ScheduledChargingPlan, active=True, current=14, id=2, limit=Limit(selected="amount"))
210-
ct.data.chargemode.scheduled_charging.plans = [plan_mock_0, plan_mock_1, plan_mock_2]
210+
ct.data.chargemode.scheduled_charging.plans = {"0": plan_mock_0, "1": plan_mock_1, "2": plan_mock_2}
211211

212212
# execution
213213
selected_plan = ct.scheduled_charging_recent_plan(
@@ -231,7 +231,7 @@ def test_scheduled_charging_recent_plan_fulfilled(monkeypatch):
231231
plan_mock_0 = Mock(spec=ScheduledChargingPlan, active=True, current=14, id=0, limit=Limit(selected="amount"))
232232
plan_mock_1 = Mock(spec=ScheduledChargingPlan, active=True, current=14, id=1, limit=Limit(selected="amount"))
233233
plan_mock_2 = Mock(spec=ScheduledChargingPlan, active=True, current=14, id=2, limit=Limit(selected="amount"))
234-
ct.data.chargemode.scheduled_charging.plans = [plan_mock_0, plan_mock_1, plan_mock_2]
234+
ct.data.chargemode.scheduled_charging.plans = {"0": plan_mock_0, "1": plan_mock_1, "2": plan_mock_2}
235235

236236
# execution
237237
selected_plan = ct.scheduled_charging_recent_plan(
@@ -285,7 +285,7 @@ def test_scheduled_charging_calc_current(plan_data: SelectedPlan,
285285
plan = ScheduledChargingPlan(active=True, id=0)
286286
plan.limit.selected = selected
287287
# json verwandelt Keys in strings
288-
ct.data.chargemode.scheduled_charging.plans = [plan]
288+
ct.data.chargemode.scheduled_charging.plans = {"0": plan}
289289
if plan_data:
290290
plan_data.plan = plan
291291

@@ -319,9 +319,9 @@ def test_scheduled_charging_calc_current_electricity_tariff(loading_hour, expect
319319
# setup
320320
ct = ChargeTemplate(0)
321321
plan = ScheduledChargingPlan(active=True)
322-
plan.et_active = True
323322
plan.limit.selected = "soc"
324-
ct.data.chargemode.scheduled_charging.plans = [plan]
323+
ct.data.chargemode.scheduled_charging.plans = {"0": plan}
324+
ct.data.chargemode.scheduled_charging.plans["0"].et_active = True
325325
# für Github-Test keinen Zeitstempel verwenden
326326
mock_et_get_loading_hours = Mock(return_value=[datetime.datetime(
327327
year=2022, month=5, day=16, hour=8, minute=0).timestamp()])

packages/dataclass_utils/_dataclass_from_dict.py

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import inspect
33
from inspect import FullArgSpec, isclass
44
import typing
5-
from typing import TypeVar, Type, Union, get_args, get_origin
5+
from typing import TypeVar, Type, Union, get_origin
66

77
T = TypeVar('T')
88

@@ -46,20 +46,15 @@ def _get_argument_value(arg_spec: FullArgSpec, index: int, parameters: dict):
4646

4747

4848
def _dataclass_from_dict_recurse(value, requested_type: Type[T]):
49-
if get_origin(requested_type) == list:
50-
# Extrahiere den generischen Typ der Liste
51-
if get_args(requested_type):
52-
generic_type = get_args(requested_type)[0]
53-
# Konvertiere jedes Element der Liste in den generischen Typ
54-
return [_dataclass_from_dict_recurse(item, generic_type) for item in value]
55-
5649
if isinstance(value, dict) and not (
5750
_is_optional_of_dict(requested_type) or
5851
issubclass(requested_type if isclass(requested_type) else type(bool), dict)):
5952
return dataclass_from_dict(requested_type, value)
60-
if isinstance(requested_type, type) and issubclass(requested_type, Enum):
61-
return requested_type(value)
62-
return value
53+
else:
54+
if isinstance(requested_type, type) and issubclass(requested_type, Enum):
55+
return requested_type(value)
56+
else:
57+
return value
6358

6459

6560
def _is_optional_of_dict(requested_type):

packages/helpermodules/abstract_plans.py

Lines changed: 7 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,8 @@
22
from typing import List, Optional
33

44

5-
def once_period_factory() -> List:
6-
return [datetime.datetime.today().strftime("%Y-%m-%d"), datetime.datetime.today().strftime("%Y-%m-%d")]
7-
8-
9-
def once_date_factory() -> List:
10-
return datetime.datetime.today().strftime("%Y-%m-%d")
5+
def once_factory() -> List:
6+
return [datetime.datetime.today().strftime("%Y%m%d"), datetime.datetime.today().strftime("%Y%m%d")]
117

128

139
def weekly_factory() -> List:
@@ -30,25 +26,14 @@ def limit_factory() -> Limit:
3026

3127

3228
@dataclass
33-
class FrequencyPeriod:
34-
selected: str = "daily"
35-
once: List[str] = field(default_factory=once_period_factory)
36-
weekly: List[bool] = field(default_factory=weekly_factory)
37-
38-
39-
def frequency_period_factory() -> FrequencyPeriod:
40-
return FrequencyPeriod()
41-
42-
43-
@dataclass
44-
class FrequencyDate:
29+
class Frequency:
4530
selected: str = "daily"
46-
once: str = field(default_factory=once_date_factory)
31+
once: List[str] = field(default_factory=once_factory)
4732
weekly: List[bool] = field(default_factory=weekly_factory)
4833

4934

50-
def frequency_date_factory() -> FrequencyDate:
51-
return FrequencyDate()
35+
def frequency_factory() -> Frequency:
36+
return Frequency()
5237

5338

5439
@dataclass
@@ -66,20 +51,19 @@ def scheduled_limit_factory() -> ScheduledLimit:
6651
@dataclass
6752
class PlanBase:
6853
active: bool = True
54+
frequency: Frequency = field(default_factory=frequency_factory)
6955

7056

7157
@dataclass
7258
class TimeframePlan(PlanBase):
7359
time: List[str] = field(default_factory=time_factory) # ToDo: aktuelle Zeit verwenden + 1 Stunde
74-
frequency: FrequencyPeriod = field(default_factory=frequency_period_factory)
7560

7661

7762
@dataclass
7863
class ScheduledChargingPlan(PlanBase):
7964
current: int = 14
8065
dc_current: float = 145
8166
et_active: bool = False
82-
frequency: FrequencyDate = field(default_factory=frequency_date_factory)
8367
id: Optional[int] = None
8468
name: str = "neuer Zielladen-Plan"
8569
limit: ScheduledLimit = field(default_factory=scheduled_limit_factory)
@@ -97,5 +81,4 @@ class TimeChargingPlan(TimeframePlan):
9781

9882
@dataclass
9983
class AutolockPlan(TimeframePlan):
100-
id: Optional[int] = None
10184
name: str = "neuer Plan für Sperren nach Uhrzeit"

0 commit comments

Comments
 (0)