diff --git a/packages/conftest.py b/packages/conftest.py index cf2d3174b5..9c09f72b8a 100644 --- a/packages/conftest.py +++ b/packages/conftest.py @@ -12,7 +12,7 @@ def mock_today(monkeypatch) -> None: datetime_mock.today.return_value = datetime.datetime(2022, 5, 16, 8, 40, 52) monkeypatch.setattr(datetime, "datetime", datetime_mock) mock_today_timestamp = Mock(return_value=1652683252) - monkeypatch.setattr(timecheck, "create_timestamp_unix", mock_today_timestamp) + monkeypatch.setattr(timecheck, "create_timestamp", mock_today_timestamp) @pytest.fixture(autouse=True) diff --git a/packages/control/algorithm/filter_chargepoints.py b/packages/control/algorithm/filter_chargepoints.py index 804e00060e..4f236975dc 100644 --- a/packages/control/algorithm/filter_chargepoints.py +++ b/packages/control/algorithm/filter_chargepoints.py @@ -5,7 +5,6 @@ from control import data from control.algorithm import common from control.chargepoint.chargepoint import Chargepoint -from helpermodules.timecheck import convert_to_unix_timestamp log = logging.getLogger(__name__) @@ -95,7 +94,7 @@ def _get_preferenced_chargepoint(valid_chargepoints: List[Chargepoint]) -> List: chargepoints.update( (cp, cp.data.set.charging_ev_data.data.get.soc) for cp in chargepoints.keys()) elif condition_types[condition] == "plug_in": - chargepoints.update((cp, convert_to_unix_timestamp(cp.data.set.plug_time)) + chargepoints.update((cp, cp.data.set.plug_time) for cp in chargepoints.keys()) elif condition_types[condition] == "imported_since_plugged": chargepoints.update((cp, cp.data.set.log.imported_since_plugged) for cp in chargepoints.keys()) diff --git a/packages/control/algorithm/integration_test/pv_charging_test.py b/packages/control/algorithm/integration_test/pv_charging_test.py index 59cca90beb..59b116032c 100644 --- a/packages/control/algorithm/integration_test/pv_charging_test.py +++ b/packages/control/algorithm/integration_test/pv_charging_test.py @@ -127,9 +127,9 @@ def test_start_pv_delay(all_cp_pv_charging_3p, all_cp_not_charging, monkeypatch) for i in range(3, 6): assert data.data.cp_data[f"cp{i}"].data.set.current == 0 assert data.data.cp_data[ - "cp3"].data.control_parameter.timestamp_switch_on_off == "05/16/2022, 08:40:52" + "cp3"].data.control_parameter.timestamp_switch_on_off == 1652683252.0 assert data.data.cp_data[ - "cp4"].data.control_parameter.timestamp_switch_on_off == "05/16/2022, 08:40:52" + "cp4"].data.control_parameter.timestamp_switch_on_off == 1652683252.0 assert data.data.cp_data[ "cp5"].data.control_parameter.timestamp_switch_on_off is None assert data.data.counter_data["counter0"].data.set.raw_power_left == 31200 @@ -145,12 +145,12 @@ def test_pv_delay_expired(all_cp_pv_charging_3p, all_cp_not_charging, monkeypatc data.data.counter_data["counter6"].data.set.raw_currents_left = [16, 12, 14] data.data.counter_data["counter0"].data.set.reserved_surplus = 9000 data.data.cp_data[ - "cp3"].data.control_parameter.timestamp_switch_on_off = "05/16/2022, 08:39:45" + "cp3"].data.control_parameter.timestamp_switch_on_off = 1652683185.0 data.data.cp_data[ "cp3"].data.control_parameter.state = ChargepointState.SWITCH_ON_DELAY # nicht genug Überschuss für beide data.data.cp_data[ - "cp4"].data.control_parameter.timestamp_switch_on_off = "05/16/2022, 08:40:52" + "cp4"].data.control_parameter.timestamp_switch_on_off = 1652683252.0 data.data.cp_data[ "cp4"].data.control_parameter.state = ChargepointState.SWITCH_ON_DELAY data.data.cp_data[ @@ -239,7 +239,7 @@ def test_surplus(params: ParamsSurplus, all_cp_pv_charging_3p, all_cp_charging_3 raw_power_left=32580, raw_currents_left_counter0=[40]*3, raw_currents_left_counter6=[16]*3, - expected_timestamp_auto_phase_switch_cp3="05/16/2022, 08:40:52", + expected_timestamp_auto_phase_switch_cp3=1652683252.0, expected_timestamp_auto_phase_switch_cp4=None, expected_timestamp_auto_phase_switch_cp5=None, expected_current_cp3=10, @@ -253,7 +253,7 @@ def test_surplus(params: ParamsSurplus, all_cp_pv_charging_3p, all_cp_charging_3 raw_power_left=42580, raw_currents_left_counter0=[40]*3, raw_currents_left_counter6=[16]*3, - expected_timestamp_auto_phase_switch_cp3="05/16/2022, 08:40:52", + expected_timestamp_auto_phase_switch_cp3=1652683252.0, expected_timestamp_auto_phase_switch_cp4=None, expected_timestamp_auto_phase_switch_cp5=None, expected_current_cp3=32, diff --git a/packages/control/auto_phase_switch_test.py b/packages/control/auto_phase_switch_test.py index 75dfa0bc05..e832606863 100644 --- a/packages/control/auto_phase_switch_test.py +++ b/packages/control/auto_phase_switch_test.py @@ -31,7 +31,7 @@ class Params: def __init__(self, name: str, max_current_single_phase: int, - timestamp_auto_phase_switch: Optional[str], + timestamp_auto_phase_switch: Optional[float], phases_to_use: int, required_current: float, evu_surplus: int, @@ -43,7 +43,7 @@ def __init__(self, expected_current: float, expected_state: ChargepointState, expected_message: Optional[str] = None, - expected_timestamp_auto_phase_switch: Optional[str] = None) -> None: + expected_timestamp_auto_phase_switch: Optional[float] = None) -> None: self.name = name self.max_current_single_phase = max_current_single_phase self.timestamp_auto_phase_switch = timestamp_auto_phase_switch @@ -66,28 +66,28 @@ def __init__(self, phases_to_use=1, required_current=6, evu_surplus=-800, reserved_evu_overhang=0, get_currents=[15.6, 0, 0], get_power=3450, state=ChargepointState.CHARGING_ALLOWED, expected_phases_to_use=1, expected_current=6, expected_message="Umschaltverzögerung von 1 auf 3 Phasen für 7.0 Min aktiv.", - expected_timestamp_auto_phase_switch="05/16/2022, 08:40:52", + expected_timestamp_auto_phase_switch=1652683252.0, expected_state=ChargepointState.PHASE_SWITCH_DELAY), Params("1to3, not enough power, start timer", max_current_single_phase=16, timestamp_auto_phase_switch=None, phases_to_use=1, required_current=6, evu_surplus=-300, reserved_evu_overhang=0, get_currents=[15.6, 0, 0], get_power=3450, state=ChargepointState.CHARGING_ALLOWED, expected_phases_to_use=1, expected_current=6, expected_state=ChargepointState.CHARGING_ALLOWED), Params("1to3, enough power, timer not expired", max_current_single_phase=16, - timestamp_auto_phase_switch="05/16/2022, 08:35:52", phases_to_use=1, required_current=6, + timestamp_auto_phase_switch=1652682952.0, phases_to_use=1, required_current=6, evu_surplus=-1200, reserved_evu_overhang=460, get_currents=[15.6, 0, 0], get_power=3450, state=ChargepointState.PHASE_SWITCH_DELAY, expected_phases_to_use=1, expected_current=6, expected_message="Umschaltverzögerung von 1 auf 3 Phasen für 7.0 Min aktiv.", - expected_timestamp_auto_phase_switch="05/16/2022, 08:40:52", + expected_timestamp_auto_phase_switch=1652683252.0, expected_state=ChargepointState.PHASE_SWITCH_DELAY), Params("1to3, not enough power, timer not expired", max_current_single_phase=16, - timestamp_auto_phase_switch="05/16/2022, 08:35:52", phases_to_use=1, required_current=6, + timestamp_auto_phase_switch=1652682952.0, phases_to_use=1, required_current=6, evu_surplus=0, reserved_evu_overhang=460, get_currents=[15.6, 0, 0], get_power=3450, state=ChargepointState.PHASE_SWITCH_DELAY, expected_phases_to_use=1, expected_current=6, expected_message=f"Umschaltverzögerung von 1 auf 3 Phasen abgebrochen{Ev.NOT_ENOUGH_POWER}", - expected_timestamp_auto_phase_switch="05/16/2022, 08:40:52", + expected_timestamp_auto_phase_switch=1652683252.0, expected_state=ChargepointState.CHARGING_ALLOWED), Params("1to3, enough power, timer expired", max_current_single_phase=16, - timestamp_auto_phase_switch="05/16/2022, 08:32:52", phases_to_use=1, required_current=6, + timestamp_auto_phase_switch=1652682772.0, phases_to_use=1, required_current=6, evu_surplus=-1200, reserved_evu_overhang=460, get_currents=[15.6, 0, 0], get_power=3450, state=ChargepointState.PHASE_SWITCH_DELAY, expected_phases_to_use=3, expected_current=6, expected_state=ChargepointState.PHASE_SWITCH_DELAY_EXPIRED), @@ -97,25 +97,25 @@ def __init__(self, get_currents=[4.5, 4.4, 5.8], get_power=3381, state=ChargepointState.CHARGING_ALLOWED, expected_phases_to_use=3, expected_current=6, expected_message="Umschaltverzögerung von 3 auf 1 Phasen für 9.0 Min aktiv.", - expected_timestamp_auto_phase_switch="05/16/2022, 08:40:52", + expected_timestamp_auto_phase_switch=1652683252.0, expected_state=ChargepointState.PHASE_SWITCH_DELAY), Params("3to1, not enough power, timer not expired", max_current_single_phase=16, - timestamp_auto_phase_switch="05/16/2022, 08:35:52", + timestamp_auto_phase_switch=1652682952.0, phases_to_use=3, required_current=6, evu_surplus=0, reserved_evu_overhang=-460, get_currents=[4.5, 4.4, 5.8], get_power=3381, state=ChargepointState.PHASE_SWITCH_DELAY, expected_phases_to_use=3, expected_current=6, expected_message="Umschaltverzögerung von 3 auf 1 Phasen für 9.0 Min aktiv.", - expected_timestamp_auto_phase_switch="05/16/2022, 08:40:52", + expected_timestamp_auto_phase_switch=1652683252.0, expected_state=ChargepointState.PHASE_SWITCH_DELAY), Params("3to1, enough power, timer not expired", max_current_single_phase=16, - timestamp_auto_phase_switch="05/16/2022, 08:35:52", phases_to_use=3, required_current=6, + timestamp_auto_phase_switch=1652682952.0, phases_to_use=3, required_current=6, evu_surplus=-860, reserved_evu_overhang=0, get_currents=[4.5, 4.4, 5.8], get_power=3381, state=ChargepointState.PHASE_SWITCH_DELAY, expected_phases_to_use=3, expected_current=6, expected_message=f"Umschaltverzögerung von 3 auf 1 Phasen abgebrochen{Ev.ENOUGH_POWER}", - expected_timestamp_auto_phase_switch="05/16/2022, 08:40:52", + expected_timestamp_auto_phase_switch=1652683252.0, expected_state=ChargepointState.CHARGING_ALLOWED), Params("3to1, not enough power, timer expired", max_current_single_phase=16, - timestamp_auto_phase_switch="05/16/2022, 08:29:52", phases_to_use=3, required_current=6, + timestamp_auto_phase_switch=1652682592.0, phases_to_use=3, required_current=6, evu_surplus=0, reserved_evu_overhang=-460, get_currents=[4.5, 4.4, 5.8], get_power=3381, state=ChargepointState.PHASE_SWITCH_DELAY, expected_phases_to_use=1, expected_current=16, expected_state=ChargepointState.PHASE_SWITCH_DELAY_EXPIRED), diff --git a/packages/control/chargelog.py b/packages/control/chargelog.py index f3167a8f61..453336083d 100644 --- a/packages/control/chargelog.py +++ b/packages/control/chargelog.py @@ -53,7 +53,7 @@ def collect_data(chargepoint): f"counter {chargepoint.data.get.imported}") log_data.range_charged = log_data.imported_since_mode_switch / \ charging_ev.ev_template.data.average_consump * 100 - log_data.time_charged, _ = timecheck.get_difference_to_now(log_data.timestamp_start_charging) + log_data.time_charged = timecheck.get_difference_to_now(log_data.timestamp_start_charging) Pub().pub(f"openWB/set/chargepoint/{chargepoint.num}/set/log", asdict(log_data)) except Exception: log.exception("Fehler im Ladelog-Modul") @@ -235,8 +235,7 @@ def get_log_data(request: Dict): power = 0 costs = 0 for entry in log_data["entries"]: - duration = timecheck.duration_sum( - duration, entry["time"]["time_charged"]) + duration = duration + entry["time"]["time_charged"] range_charged += entry["data"]["range_charged"] mode += entry["data"]["imported_since_mode_switch"] power += entry["data"]["power"] diff --git a/packages/control/chargepoint/chargepoint.py b/packages/control/chargepoint/chargepoint.py index 26741424c6..1a83e46203 100644 --- a/packages/control/chargepoint/chargepoint.py +++ b/packages/control/chargepoint/chargepoint.py @@ -119,8 +119,8 @@ class Log: imported_since_mode_switch: float = 0 imported_since_plugged: float = 0 range_charged: float = 0 - time_charged: str = "00:00" - timestamp_start_charging: Optional[str] = None + time_charged: float = 0 + timestamp_start_charging: Optional[float] = None def connected_vehicle_factory() -> ConnectedVehicle: @@ -142,7 +142,7 @@ class Get: phases_in_use: int = 0 plug_state: bool = False power: float = 0 - rfid_timestamp: Optional[str] = None + rfid_timestamp: Optional[float] = None rfid: Optional[str] = None soc: Optional[float] = None soc_timestamp: Optional[int] = None @@ -170,7 +170,7 @@ class Set: manual_lock: bool = False phases_to_use: int = 0 plug_state_prev: bool = False - plug_time: Optional[str] = None + plug_time: Optional[float] = None required_power: float = 0 rfid: Optional[str] = None target_current: float = 0 # Sollstrom aus fest vorgegebener Stromstärke diff --git a/packages/control/chargepoint/control_parameter.py b/packages/control/chargepoint/control_parameter.py index 622db99c59..8583ad5a04 100644 --- a/packages/control/chargepoint/control_parameter.py +++ b/packages/control/chargepoint/control_parameter.py @@ -41,13 +41,13 @@ class ControlParameter: submode: Chargemode_enum = field( default=Chargemode_enum.STOP, metadata={"topic": "control_parameter/submode", "mutable_by_algorithm": True}) - timestamp_auto_phase_switch: Optional[str] = field( + timestamp_auto_phase_switch: Optional[float] = field( default=None, metadata={"topic": "control_parameter/timestamp_auto_phase_switch", "mutable_by_algorithm": True}) - timestamp_perform_phase_switch: Optional[str] = field( + timestamp_perform_phase_switch: Optional[float] = field( default=None, metadata={"topic": "control_parameter/timestamp_perform_phase_switch", "mutable_by_algorithm": True}) - timestamp_switch_on_off: Optional[str] = field( + timestamp_switch_on_off: Optional[float] = field( default=None, metadata={"topic": "control_parameter/timestamp_switch_on_off", "mutable_by_algorithm": True}) diff --git a/packages/control/counter_test.py b/packages/control/counter_test.py index 799b7a332f..dd75b4ce6c 100644 --- a/packages/control/counter_test.py +++ b/packages/control/counter_test.py @@ -102,23 +102,23 @@ class Params: cases = [ Params("Einschaltschwelle wurde unterschritten, Timer zurücksetzen", False, 1500, -119, - 1500, '05/16/2022, 08:40:50', ChargepointState.SWITCH_ON_DELAY, + 1500, 1652683250.0, ChargepointState.SWITCH_ON_DELAY, Counter.SWITCH_ON_FALLEN_BELOW.format(1500), None, 0), Params("Timer starten", False, 0, 1501, 1500, None, ChargepointState.NO_CHARGING_ALLOWED, - Counter.SWITCH_ON_WAITING.format(30), '05/16/2022, 08:40:52', 1500), + Counter.SWITCH_ON_WAITING.format(30), 1652683252.0, 1500), Params("Einschaltschwelle nicht erreicht", False, 0, 1499, 1500, None, ChargepointState.NO_CHARGING_ALLOWED, Counter.SWITCH_ON_NOT_EXCEEDED.format(1500), None, 0), Params("Einschaltschwelle läuft", False, 1500, 121, 1500, - '05/16/2022, 08:40:50', ChargepointState.SWITCH_ON_DELAY, None, '05/16/2022, 08:40:50', 1500), + 1652683250.0, ChargepointState.SWITCH_ON_DELAY, None, 1652683250.0, 1500), Params("Feed_in_limit, Einschaltschwelle wurde unterschritten, Timer zurücksetzen", True, 1500, - -681, 15000, '05/16/2022, 08:40:50', ChargepointState.SWITCH_ON_DELAY, + -681, 15000, 1652683250.0, ChargepointState.SWITCH_ON_DELAY, Counter.SWITCH_ON_FALLEN_BELOW.format(1500), None, 0), Params("Feed_in_limit, Timer starten", True, 0, 15001, 15000, None, ChargepointState.NO_CHARGING_ALLOWED, - Counter.SWITCH_ON_WAITING.format(30), '05/16/2022, 08:40:52', 1500), + Counter.SWITCH_ON_WAITING.format(30), 1652683252.0, 1500), Params("Feed_in_limit, Einschaltschwelle nicht erreicht", True, 0, 14999, 15000, None, ChargepointState.NO_CHARGING_ALLOWED, Counter.SWITCH_ON_NOT_EXCEEDED.format(1500), None, 0), Params("Feed_in_limit, Einschaltschwelle läuft", True, 1500, 15001, - 15000, '05/16/2022, 08:40:50', ChargepointState.SWITCH_ON_DELAY, None, '05/16/2022, 08:40:50', 1500), + 15000, 1652683250.0, ChargepointState.SWITCH_ON_DELAY, None, 1652683250.0, 1500), ] diff --git a/packages/control/ev.py b/packages/control/ev.py index 488634964a..b977d4e619 100644 --- a/packages/control/ev.py +++ b/packages/control/ev.py @@ -157,7 +157,7 @@ def set_factory() -> Set: @dataclass class Get: soc: int = 0 - soc_timestamp: Optional[str] = None + soc_timestamp: float = 0 force_soc_update: bool = False range: float = 0 fault_state: int = 0 diff --git a/packages/control/ev_test.py b/packages/control/ev_test.py index d8e076ee18..1f3078165f 100644 --- a/packages/control/ev_test.py +++ b/packages/control/ev_test.py @@ -1,3 +1,4 @@ +from typing import Optional from unittest.mock import Mock import pytest @@ -11,15 +12,15 @@ @pytest.mark.parametrize( "check_timestamp, charge_state, soc_timestamp, expected_request_soc", - [pytest.param(False, False, "", True, id="no soc_timestamp"), - pytest.param(True, False, "2022/05/16, 8:30:52", False, id="not charging, not expired"), - pytest.param(False, False, "2022/05/15, 20:30:52", True, id="not charging, expired"), - pytest.param(True, True, "2022/05/16, 8:36:52", False, id="charging, not expired"), - pytest.param(False, True, "2022/05/16, 8:35:50", True, id="charging, expired"), + [pytest.param(False, False, None, True, id="no soc_timestamp"), + pytest.param(True, False, 100, False, id="not charging, not expired"), + pytest.param(False, False, 100, True, id="not charging, expired"), + pytest.param(True, True, 100, False, id="charging, not expired"), + pytest.param(False, True, 100, True, id="charging, expired"), ]) def test_soc_interval_expired(check_timestamp: bool, charge_state: bool, - soc_timestamp: str, + soc_timestamp: Optional[float], expected_request_soc: bool, monkeypatch): # setup diff --git a/packages/control/general.py b/packages/control/general.py index 5a06ecd30c..c198640480 100644 --- a/packages/control/general.py +++ b/packages/control/general.py @@ -102,7 +102,7 @@ class GeneralData: grid_protection_active: bool = False grid_protection_configured: bool = True grid_protection_random_stop: int = 0 - grid_protection_timestamp: Optional[str] = "" + grid_protection_timestamp: Optional[float] = "" mqtt_bridge: bool = False price_kwh: float = 0.3 range_unit: str = "km" diff --git a/packages/helpermodules/measurement_logging/write_log.py b/packages/helpermodules/measurement_logging/write_log.py index 8a1b4259a1..fd76ebe8c2 100644 --- a/packages/helpermodules/measurement_logging/write_log.py +++ b/packages/helpermodules/measurement_logging/write_log.py @@ -95,7 +95,7 @@ def save_log(folder): date = timecheck.create_timestamp_time() else: date = timecheck.create_timestamp_YYYYMMDD() - current_timestamp = timecheck.create_timestamp_unix() + current_timestamp = timecheck.create_timestamp() cp_dict = {} for cp in data.data.cp_data: try: diff --git a/packages/helpermodules/setdata.py b/packages/helpermodules/setdata.py index b7539014cb..6af8cd42ab 100644 --- a/packages/helpermodules/setdata.py +++ b/packages/helpermodules/setdata.py @@ -133,6 +133,15 @@ def _validate_value(self, msg: mqtt.MQTTMessage, data_type, ranges=[], collectio valid = True else: log.error(f"Payload ungültig: Topic {msg.topic}, Payload {value} sollte ein String sein.") + elif isinstance(data_type, Tuple): + if int in data_type: + if self._validate_min_max_value(value, msg, int, ranges): + valid = True + if float in data_type: + if self._validate_min_max_value(value, msg, float, ranges): + valid = True + if None in data_type and value is None: + valid = True elif data_type == int or data_type == float: if self._validate_min_max_value(value, msg, data_type, ranges) or isinstance(value, type(None)): valid = True @@ -521,7 +530,7 @@ def process_chargepoint_topic(self, msg: mqtt.MQTTMessage): self._validate_value(msg, int, [(0, 4)]) elif ("/set/rfid" in msg.topic or "/set/plug_time" in msg.topic): - self._validate_value(msg, str) + self._validate_value(msg, float) elif "/set/log" in msg.topic: self._validate_value(msg, "json") elif "/set/change_ev_permitted" in msg.topic: @@ -541,13 +550,13 @@ def process_chargepoint_topic(self, msg: mqtt.MQTTMessage): self._validate_value(msg, str) elif "/control_parameter/prio" in msg.topic: self._validate_value(msg, bool) - elif ("/control_parameter/timestamp_switch_on_off" in msg.topic or - "/control_parameter/timestamp_auto_phase_switch" in msg.topic or - "/control_parameter/timestamp_perform_phase_switch" in msg.topic or - "/control_parameter/current_plan" in msg.topic): + elif "/control_parameter/current_plan" in msg.topic: self._validate_value(msg, str) elif ("/control_parameter/imported_instant_charging" in msg.topic or - "/control_parameter/imported_at_plan_start" in msg.topic): + "/control_parameter/imported_at_plan_start" in msg.topic or + "/control_parameter/timestamp_switch_on_off" in msg.topic or + "/control_parameter/timestamp_auto_phase_switch" in msg.topic or + "/control_parameter/timestamp_perform_phase_switch" in msg.topic): self._validate_value(msg, float, [(0, float("inf"))]) elif "/control_parameter/state" in msg.topic: self._validate_value(msg, int, [(0, 7)]) diff --git a/packages/helpermodules/timecheck.py b/packages/helpermodules/timecheck.py index 00a5876536..2160403254 100644 --- a/packages/helpermodules/timecheck.py +++ b/packages/helpermodules/timecheck.py @@ -3,7 +3,6 @@ import copy import logging import datetime -from dateutil.relativedelta import relativedelta from typing import Dict, List, Optional, Tuple, TypeVar, Union from helpermodules.abstract_plans import AutolockPlan, ScheduledChargingPlan, TimeChargingPlan @@ -108,13 +107,6 @@ def is_timeframe_valid(now: datetime.datetime, begin: datetime.datetime, end: da return state -def _calc_begin(end: datetime.datetime, hours: int) -> datetime.datetime: - """ berechnet den Zeitpunkt, der die angegebenen Stunden vor dem Endzeitpunkt liegt. - """ - prev = datetime.timedelta(hours) - return end - prev - - def check_duration(plan: ScheduledChargingPlan, duration: float, buffer: int) -> Tuple[Optional[float], bool]: """ prüft, ob der in angegebene Zeitpunkt abzüglich der Dauer jetzt ist. Um etwas Puffer zu haben, werden bei Überschreiten des Zeitpunkts die nachfolgenden 20 Min auch noch als Ladezeit @@ -188,6 +180,7 @@ def _get_remaining_time(now: datetime.datetime, duration: float, end: datetime.d """ delta = datetime.timedelta(hours=int(duration), minutes=((duration % 1) * 60)) start_time = end-delta + log.debug(f"delta {delta} start_time {start_time} end {end} now {now}") return (start_time-now).total_seconds() @@ -219,118 +212,42 @@ def is_list_valid(hour_list: List[int]) -> bool: return False -def check_timestamp(timestamp: str, duration: int) -> bool: +def check_timestamp(timestamp: int, duration: int) -> bool: """ prüft, ob der Zeitstempel innerhalb der angegebenen Zeit liegt - Parameter - --------- - timestamp: str - Zeitstempel, der geprüft werden soll - duration: - Zeitspanne in s, in der der Zeitstempel gültig ist - Return ------ True: Zeit ist noch nicht abgelaufen False: Zeit ist abgelaufen """ - stamp = datetime.datetime.strptime(timestamp, "%m/%d/%Y, %H:%M:%S") - now = datetime.datetime.today() - delta = datetime.timedelta(seconds=duration) - if (now - delta) > stamp: + if (create_timestamp() - duration) > timestamp: return False else: return True -def create_timestamp() -> str: - try: - stamp = datetime.datetime.today().strftime("%m/%d/%Y, %H:%M:%S") - return stamp - except Exception: - raise - - -def create_timestamp_unix() -> int: - """ Unix Zeitstempel - """ - try: - return int(datetime.datetime.today().timestamp()) - except Exception: - raise +def create_timestamp() -> float: + return datetime.datetime.today().timestamp() def create_timestamp_YYYYMM() -> str: - try: - stamp = datetime.datetime.today().strftime("%Y%m") - return stamp - except Exception: - raise + stamp = datetime.datetime.today().strftime("%Y%m") + return stamp def create_timestamp_YYYYMMDD() -> str: - try: - stamp = datetime.datetime.today().strftime("%Y%m%d") - return stamp - except Exception: - raise - - -def create_timestamp_time() -> str: - try: - stamp = datetime.datetime.today().strftime("%H:%M") - return stamp - except Exception: - raise - - -def convert_YYYYMM_to_unix_timestamp(date: str) -> float: - return datetime.datetime.strptime(date, "%Y%m").timestamp() - - -def convert_to_unix_timestamp(timestamp: str) -> float: - return datetime.datetime.strptime(timestamp, "%m/%d/%Y, %H:%M:%S").timestamp() - - -def get_relative_date_string(date_string: str, day_offset: int = 0, month_offset: int = 0, year_offset: int = 0) -> str: - print_format = "%Y%m%d" if len(date_string) > 6 else "%Y%m" - my_date = datetime.datetime.strptime(date_string, print_format) - return (my_date + relativedelta(years=year_offset, months=month_offset, days=day_offset)).strftime(print_format) - - -def get_difference_to_now(timestamp_begin: str) -> Tuple[str, int]: - """ ermittelt den Abstand zwischen zwei Zeitstempeln. - - Parameter - --------- - timestamp_begin: str %m/%d/%Y, %H:%M:%S - Anfangszeitpunkt - - Return - ------ - diff: [str, int] - str: Differenz HH:MM, ggf DD days, HH:MM - int: Differenz in Sekunden - """ - try: - diff = datetime.timedelta( - seconds=get_difference(timestamp_begin, datetime.datetime.today().strftime("%m/%d/%Y, %H:%M:%S"))) - return [convert_timedelta_to_time_string(diff), int(diff.total_seconds())] - except Exception: - log.exception("Fehler im System-Modul") - return ["00:00", 0] + stamp = datetime.datetime.today().strftime("%Y%m%d") + return stamp def get_difference(timestamp_begin: str, timestamp_end: str) -> Optional[int]: """ ermittelt den Abstand zwischen zwei Zeitstempeln in absoluten Sekunden. - Parameter --------- timestamp_begin: str %m/%d/%Y, %H:%M:%S Anfangszeitpunkt timestamp_end: str %m/%d/%Y, %H:%M:%S Endzeitpunkt - Return ------ diff: int @@ -346,48 +263,11 @@ def get_difference(timestamp_begin: str, timestamp_end: str) -> Optional[int]: return None -def duration_sum(first: str, second: str) -> str: - """ addiert zwei Zeitstrings und gibt das Ergebnis als String zurück. - - Parameter - --------- - first, second: str - Zeitstrings HH:MM ggf DD:HH:MM - Return - ------ - sum: str - Summe der Zeitstrings - """ - try: - sum = __get_timedelta_obj(first) + __get_timedelta_obj(second) - return convert_timedelta_to_time_string(sum) - except Exception: - log.exception("Fehler im System-Modul") - return "00:00" - - -def __get_timedelta_obj(time: str) -> datetime.timedelta: - """ erstellt aus einem String ein timedelta-Objekt. - - Parameter - --------- - time: str - Zeitstrings HH:MM ggf DD:HH:MM - """ - time_charged = time.split(":") - if len(time_charged) == 2: - delta = datetime.timedelta(hours=int(time_charged[0]), - minutes=int(time_charged[1])) - elif len(time_charged) == 3: - delta = datetime.timedelta(days=int(time_charged[0]), - hours=int(time_charged[1]), - minutes=int(time_charged[2])) - else: - raise Exception("Unknown charge duration: "+time) - return delta - - def convert_timedelta_to_time_string(timedelta_obj: datetime.timedelta) -> str: diff_hours = int(timedelta_obj.total_seconds() / 3600) diff_minutes = int((timedelta_obj.total_seconds() % 3600) / 60) return f"{diff_hours}:{diff_minutes:02d}" + + +def get_difference_to_now(timestamp_begin: float) -> float: + return create_timestamp() - timestamp_begin diff --git a/packages/helpermodules/timecheck_test.py b/packages/helpermodules/timecheck_test.py index c7d2193bb1..adc556e292 100644 --- a/packages/helpermodules/timecheck_test.py +++ b/packages/helpermodules/timecheck_test.py @@ -20,51 +20,6 @@ def __init__(self, name: str, self.second_time = second_time -# cases_get_difference_to_now = [ -# Params("get_difference_to_now_minutes_before", "02/18/2022, 10:42:23", expected_return="87"), -# Params("get_difference_to_now_minutes_after", "02/18/2022, 10:50:45", expected_return="469"), -# Params("get_difference_to_now_hours", "02/18/2022, 10:42:56", expected_return="8651"), -# Params("get_difference_to_now_days", "02/16/2022, 08:18:45", expected_return="164149"), -# ] -cases_get_difference = [ - Params("get_difference_minutes_before", "02/18/2022, 10:40:56", - second_time="02/18/2022, 10:42:23", expected_return=87), - Params("get_difference_minutes_after", "02/18/2022, 10:42:56", - second_time="02/18/2022, 10:50:45", expected_return=469), - Params("get_difference_hours", "02/18/2022, 08:18:45", second_time="02/18/2022, 10:42:56", expected_return=8651), - Params("get_difference_days", "02/16/2022, 10:42:56", second_time="02/18/2022, 08:18:45", expected_return=164149), -] - -cases_duration_sum = [ - Params("duration_sum_minutes", "00:23", second_time="00:56", expected_return="1:19"), - Params("duration_sum_hours", "08:18", second_time="01:56", expected_return="10:14"), - Params("duration_sum_days", "18:8", second_time="10:24", expected_return="28:32"), -] - -# @pytest.fixture(autouse=True) -# def set_up(monkeypatch): -# mock_today = Mock(name="today", return_value="02/18/2022, 10:42") -# monkeypatch.setattr(datetime, "today", mock_today) - - -@pytest.mark.parametrize("params", cases_get_difference, ids=[c.name for c in cases_get_difference]) -def test_get_difference(params: Params): - # execution - diff = timecheck.get_difference(params.first_time, params.second_time) - - # evaluation - assert params.expected_return == diff - - -@pytest.mark.parametrize("params", cases_duration_sum, ids=[c.name for c in cases_duration_sum]) -def test_duration_sum(params: Params): - # execution - diff = timecheck.duration_sum(params.first_time, params.second_time) - - # evaluation - assert params.expected_return == diff - - @pytest.mark.parametrize("begin_hour, begin_min, end_hour, end_min,expected", [pytest.param(0, 0, 5, 5, 9300, id="too early"), pytest.param(8, 18, 10, 35, -780, id="start"), diff --git a/packages/main.py b/packages/main.py index f74d20b86f..50fba50136 100755 --- a/packages/main.py +++ b/packages/main.py @@ -72,7 +72,7 @@ def handler_with_control_interval(): else: self.interval_counter = self.interval_counter + 1 log.info("# ***Start*** ") - Pub().pub("openWB/set/system/time", timecheck.create_timestamp_unix()) + Pub().pub("openWB/set/system/time", timecheck.create_timestamp()) handler_with_control_interval() except KeyboardInterrupt: log.critical("Ausführung durch exit_after gestoppt: "+traceback.format_exc()) diff --git a/packages/modules/common/component_state.py b/packages/modules/common/component_state.py index 44bb180eb8..cd6ddc5e30 100644 --- a/packages/modules/common/component_state.py +++ b/packages/modules/common/component_state.py @@ -106,11 +106,11 @@ def __init__( @auto_str class CarState: - def __init__(self, soc: float, range: Optional[float] = None, soc_timestamp: Optional[str] = None): + def __init__(self, soc: float, range: Optional[float] = None, soc_timestamp: float = 0): """Args: soc: actual state of charge in percent range: actual range in km - soc_timestamp: timestamp of last request in %m/%d/%Y, %H:%M:%S + soc_timestamp: timestamp of last request as unix timestamp """ self.soc = soc self.range = range diff --git a/packages/modules/configuration_test.py b/packages/modules/configuration_test.py index 9de349ddc6..0de0c77819 100644 --- a/packages/modules/configuration_test.py +++ b/packages/modules/configuration_test.py @@ -3,11 +3,12 @@ from modules.configuration import pub_configurable from modules import configuration +from test_utils.test_environment import running_on_github def test_pub_configurable(monkeypatch): # setup - if str(configuration._get_packages_path()) == "/home/runner/work/core/core/packages": + if running_on_github(): # run test on github mock_packages_path = Mock(name="get packages path", return_value=Path("/home/runner/work/core/core/packages")) monkeypatch.setattr(configuration, "_get_packages_path", mock_packages_path) diff --git a/packages/test_utils/test_environment.py b/packages/test_utils/test_environment.py new file mode 100644 index 0000000000..4d4cda48db --- /dev/null +++ b/packages/test_utils/test_environment.py @@ -0,0 +1,6 @@ + +from pathlib import Path + + +def running_on_github(): + return str(Path(__file__).resolve().parents[2]/"packages") == "/home/runner/work/core/core/packages"