Skip to content

Commit

Permalink
fix
Browse files Browse the repository at this point in the history
  • Loading branch information
LKuemmel committed Dec 5, 2023
1 parent 2b079fd commit 1d1c7f2
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 127 deletions.
234 changes: 117 additions & 117 deletions packages/control/chargelog/chargelog.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
from enum import Enum
import json
import logging
import math
import pathlib
from typing import Dict, List, Union
from typing import Dict, List

from control import data
from dataclass_utils import asdict
Expand Down Expand Up @@ -51,6 +50,9 @@ def collect_data(chargepoint):
log_data.chargemode_log_entry = "time_charging"
else:
log_data.chargemode_log_entry = chargepoint.data.control_parameter.chargemode.value
log_data.ev = chargepoint.data.set.charging_ev_data.num
log_data.prio = chargepoint.data.control_parameter.prio
log_data.rfid = chargepoint.data.set.rfid
log_data.imported_since_mode_switch = chargepoint.data.get.imported - log_data.imported_at_mode_switch
log.debug(f"imported_since_mode_switch {log_data.imported_since_mode_switch} "
f"counter {chargepoint.data.get.imported}")
Expand All @@ -62,9 +64,27 @@ def collect_data(chargepoint):
log.exception("Fehler im Ladelog-Modul")


def save_data(chargepoint, charging_ev, immediately: bool = True, reset: bool = False):
""" json-Objekt für den Log-Eintrag erstellen, an die Datei anhängen und die Daten, die sich auf den Ladevorgang
beziehen, löschen.
def save_interim_data(chargepoint, charging_ev, immediately: bool = True):
try:
log_data = chargepoint.data.set.log
# Es wurde noch nie ein Auto zugeordnet
if charging_ev == -1:
return
if log_data.timestamp_start_charging is None:
# Die Daten wurden schon erfasst.
return
if not immediately:
if chargepoint.data.get.power != 0:
# Das Fahrzeug hat die Ladung noch nicht beendet. Der Logeintrag wird später erstellt.
return
save_data(chargepoint, charging_ev, immediately)
chargepoint.reset_log_data_chargemode_switch()
except Exception:
log.exception("Fehler im Ladelog-Modul")


def save_and_reset_data(chargepoint, charging_ev, immediately: bool = True):
"""nach dem Abstecken Log-Eintrag erstellen und alle Log-Daten zurücksetzen.
Parameter
---------
Expand All @@ -73,84 +93,106 @@ def save_data(chargepoint, charging_ev, immediately: bool = True, reset: bool =
charging_ev: class
EV, das an diesem Ladepunkt lädt. (Wird extra übergeben, da es u.U. noch nicht zugewiesen ist und nur die
Nummer aus dem Broker in der LP-Klasse hinterlegt ist.)
reset: bool
Wenn die Daten komplett zurückgesetzt werden, wird nicht der Zwischenzählerstand für
imported_at_mode_switch notiert. Sonst schon, damit zwischen save_data und dem nächsten collect_data keine
Daten verloren gehen.
immediately: bool
Soll sofort ein Eintrag erstellt werden oder gewartet werden, bis die Ladung beendet ist.
"""
try:
log_data = chargepoint.data.set.log
# Es wurde noch nie ein Auto zugeordnet
if charging_ev == -1:
return
if log_data.timestamp_start_charging is None:
# Die Daten wurden schon erfasst.
# Es wurde noch nie ein Auto zugeordnet.
return
if not immediately:
if chargepoint.data.get.power != 0:
# Das Fahrzeug hat die Ladung noch nicht beendet. Der Logeintrag wird später erstellt.
return
# Daten vor dem Speichern nochmal aktualisieren, auch wenn nicht mehr geladen wird.
log_data.imported_since_plugged = chargepoint.data.get.imported - log_data.imported_at_plugtime
log_data.imported_since_mode_switch = chargepoint.data.get.imported - log_data.imported_at_mode_switch
log_data.range_charged = log_data.imported_since_mode_switch / charging_ev.ev_template.data.average_consump*100
log_data.time_charged, duration = timecheck.get_difference_to_now(log_data.timestamp_start_charging)
power = 0
if duration > 0:
power = log_data.imported_since_mode_switch / duration
calculate_charge_cost(chargepoint, True)
costs = log_data.costs
new_entry = {
"chargepoint":
{
"id": chargepoint.num,
"name": chargepoint.data.config.name,
},
"vehicle":
{
"id": charging_ev.num,
"name": charging_ev.data.name,
"chargemode": log_data.chargemode_log_entry,
"prio": chargepoint.data.control_parameter.prio,
"rfid": chargepoint.data.set.rfid
},
"time":
{
"begin": log_data.timestamp_start_charging,
"end": timecheck.create_timestamp(),
"time_charged": log_data.time_charged
},
"data":
{
"range_charged": truncate(log_data.range_charged, 2),
"imported_since_mode_switch": truncate(log_data.imported_since_mode_switch, 2),
"imported_since_plugged": truncate(log_data.imported_since_plugged, 2),
"power": truncate(power, 2),
"costs": truncate(costs, 2)
}
if chargepoint.data.set.log.timestamp_start_charging:
# Die Daten wurden noch nicht erfasst.
save_data(chargepoint, charging_ev, immediately)
chargepoint.reset_log_data()
except Exception:
log.exception("Fehler im Ladelog-Modul")


def save_data(chargepoint, charging_ev, immediately: bool = True):
""" json-Objekt für den Log-Eintrag erstellen, an die Datei anhängen und die Daten, die sich auf den Ladevorgang
beziehen, löschen.
Parameter
---------
chargepoint: class
Ladepunkt
charging_ev: class
EV, das an diesem Ladepunkt lädt. (Wird extra übergeben, da es u.U. noch nicht zugewiesen ist und nur die
Nummer aus dem Broker in der LP-Klasse hinterlegt ist.)
reset: bool
Wenn die Daten komplett zurückgesetzt werden, wird nicht der Zwischenzählerstand für
imported_at_mode_switch notiert. Sonst schon, damit zwischen save_data und dem nächsten collect_data keine
Daten verloren gehen.
"""
log_data = chargepoint.data.set.log
# Daten vor dem Speichern nochmal aktualisieren, auch wenn nicht mehr geladen wird.
log_data.imported_since_plugged = chargepoint.data.get.imported - log_data.imported_at_plugtime
log_data.imported_since_mode_switch = chargepoint.data.get.imported - log_data.imported_at_mode_switch
log_data.range_charged = log_data.imported_since_mode_switch / charging_ev.ev_template.data.average_consump*100
log_data.time_charged, duration = timecheck.get_difference_to_now(log_data.timestamp_start_charging)
power = 0
if duration > 0:
power = log_data.imported_since_mode_switch / duration
calculate_charge_cost(chargepoint, True)
costs = log_data.costs
new_entry = {
"chargepoint":
{
"id": chargepoint.num,
"name": chargepoint.data.config.name,
},
"vehicle":
{
"id": log_data.ev,
"name": _get_ev_name(log_data.ev),
"chargemode": log_data.chargemode_log_entry,
"prio": log_data.prio,
"rfid": log_data.rfid
},
"time":
{
"begin": log_data.timestamp_start_charging,
"end": timecheck.create_timestamp(),
"time_charged": log_data.time_charged
},
"data":
{
"range_charged": round(log_data.range_charged, 2),
"imported_since_mode_switch": round(log_data.imported_since_mode_switch, 2),
"imported_since_plugged": round(log_data.imported_since_plugged, 2),
"power": round(power, 2),
"costs": round(costs, 2)
}
}

# json-Objekt in Datei einfügen
(_get_parent_file() / "data"/"charge_log").mkdir(mode=0o755, parents=True, exist_ok=True)
filepath = str(_get_parent_file() / "data" / "charge_log" /
(timecheck.create_timestamp_YYYYMM() + ".json"))
try:
with open(filepath, "r", encoding="utf-8") as json_file:
content = json.load(json_file)
except FileNotFoundError:
# with open(filepath, "w", encoding="utf-8") as jsonFile:
# json.dump([], jsonFile)
# with open(filepath, "r", encoding="utf-8") as jsonFile:
# content = json.load(jsonFile)
content = []
content.append(new_entry)
with open(filepath, "w", encoding="utf-8") as json_file:
json.dump(content, json_file)
log.debug(f"Neuer Ladelog-Eintrag: {new_entry}")

chargepoint.reset_log_data_regarding_chargemode(reset)
Pub().pub(f"openWB/set/chargepoint/{chargepoint.num}/set/log", asdict(chargepoint.data.set.log))
# json-Objekt in Datei einfügen
(_get_parent_file() / "data"/"charge_log").mkdir(mode=0o755, parents=True, exist_ok=True)
filepath = str(_get_parent_file() / "data" / "charge_log" /
(timecheck.create_timestamp_YYYYMM() + ".json"))
try:
with open(filepath, "r", encoding="utf-8") as json_file:
content = json.load(json_file)
except FileNotFoundError:
# with open(filepath, "w", encoding="utf-8") as jsonFile:
# json.dump([], jsonFile)
# with open(filepath, "r", encoding="utf-8") as jsonFile:
# content = json.load(jsonFile)
content = []
content.append(new_entry)
with open(filepath, "w", encoding="utf-8") as json_file:
json.dump(content, json_file)
log.debug(f"Neuer Ladelog-Eintrag: {new_entry}")


def _get_ev_name(ev: int) -> str:
try:
return data.data.ev_data[f"ev{ev}"].data.name
except Exception:
log.exception("Fehler im Ladelog-Modul")
return ""


def get_log_data(request: Dict):
Expand Down Expand Up @@ -255,53 +297,10 @@ def get_log_data(request: Dict):
return log_data


def reset_data(chargepoint, charging_ev, immediately: bool = True):
"""nach dem Abstecken Log-Eintrag erstellen und alle Log-Daten zurücksetzen.
Parameter
---------
chargepoint: class
Ladepunkt
charging_ev: class
EV, das an diesem Ladepunkt lädt. (Wird extra übergeben, da es u.U. noch nicht zugewiesen ist und nur die
Nummer aus dem Broker in der LP-Klasse hinterlegt ist.)
immediately: bool
Soll sofort ein Eintrag erstellt werden oder gewartet werden, bis die Ladung beendet ist.
"""
try:
if charging_ev == -1:
# Es wurde noch nie ein Auto zugeordnet.
return
if not immediately:
if chargepoint.data.get.power != 0:
return
save_data(chargepoint, charging_ev, immediately, reset=True)
except Exception:
log.exception("Fehler im Ladelog-Modul")


def truncate(number: Union[int, float], decimals: int = 0):
"""
Returns a value truncated to a specific number of decimal places.
"""
try:
if not isinstance(decimals, int):
raise TypeError("decimal places must be an integer.")
elif decimals < 0:
raise ValueError("decimal places has to be 0 or more.")
elif decimals == 0:
return math.trunc(number)

factor = 10.0 ** decimals
return math.trunc(number * factor) / factor
except Exception:
log.exception("Fehler im Ladelog-Modul")


def calculate_charge_cost(cp, create_log_entry: bool = False):
content = get_todays_daily_log()
try:
if cp.data.set.log.imported_since_plugged != 0:
if cp.data.set.log.imported_since_plugged != 0 and cp.data.set.log.imported_since_mode_switch != 0:
reference = _get_reference_position(cp, create_log_entry)
reference_time = get_reference_time(cp, reference)
reference_entry = _get_reference_entry(content["entries"], reference_time)
Expand All @@ -328,6 +327,7 @@ def calculate_charge_cost(cp, create_log_entry: bool = False):
cp.data.set.log.costs += _calc(power_source_entry["power_source"],
charged_energy,
(data.data.optional_data.et_module is not None))
Pub().pub(f"openWB/set/chargepoint/{cp.num}/set/log", asdict(cp.data.set.log))
except Exception:
log.exception(f"Fehler beim Berechnen der Ladekosten für Ladepunkt {cp.num}")

Expand Down
1 change: 1 addition & 0 deletions packages/control/chargelog/chargelog_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ def test_calculate_charge_cost(monkeypatch):
# setup
data.data.cp_data["cp3"].data.set.log.timestamp_start_charging = "11/01/2023, 08:12:40"
data.data.cp_data["cp3"].data.set.log.imported_since_plugged = 1000
data.data.cp_data["cp3"].data.set.log.imported_since_mode_switch = 1000
# Mock today() to values in log-file
datetime_mock = MagicMock(wraps=datetime.datetime)
# Thu Nov 02 2023 07:00:51
Expand Down
23 changes: 15 additions & 8 deletions packages/control/chargepoint/chargepoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ class Log:
range_charged: float = 0
time_charged: str = "00:00"
timestamp_start_charging: Optional[str] = None
ev: int = -1
prio: bool = False
rfid: Optional[str] = None


def connected_vehicle_factory() -> ConnectedVehicle:
Expand Down Expand Up @@ -420,7 +423,7 @@ def _process_charge_stop(self) -> None:
self.data.set.manual_lock = True
Pub().pub("openWB/set/chargepoint/"+str(self.num)+"/set/manual_lock", True)
# Ev wurde noch nicht aktualisiert.
chargelog.reset_data(self, data.data.ev_data["ev"+str(self.data.set.charging_ev_prev)])
chargelog.save_and_reset_data(self, data.data.ev_data["ev"+str(self.data.set.charging_ev_prev)])
self.data.set.charging_ev_prev = -1
Pub().pub("openWB/set/chargepoint/"+str(self.num)+"/set/charging_ev_prev",
self.data.set.charging_ev_prev)
Expand Down Expand Up @@ -484,14 +487,18 @@ def remember_previous_values(self):
self.data.set.plug_state_prev = self.data.get.plug_state
Pub().pub("openWB/set/chargepoint/"+str(self.num)+"/set/plug_state_prev", self.data.set.plug_state_prev)

def reset_log_data_regarding_chargemode(self, reset: bool = False) -> None:
def reset_log_data_chargemode_switch(self) -> None:
reset_log = Log()
if reset is False:
# Wenn ein Zwischeneintrag, zB bei Wechsel des Lademodus, erstellt wird, Zählerstände nicht verwerfen.
reset_log.imported_at_mode_switch = self.data.get.imported
reset_log.imported_at_plugtime = self.data.set.log.imported_at_plugtime
reset_log.imported_since_plugged = self.data.set.log.imported_since_plugged
# Wenn ein Zwischeneintrag, zB bei Wechsel des Lademodus, erstellt wird, Zählerstände nicht verwerfen.
reset_log.imported_at_mode_switch = self.data.get.imported
reset_log.imported_at_plugtime = self.data.set.log.imported_at_plugtime
reset_log.imported_since_plugged = self.data.set.log.imported_since_plugged
self.data.set.log = reset_log
Pub().pub(f"openWB/set/chargepoint/{self.num}/set/log", asdict(self.data.set.log))

def reset_log_data(self) -> None:
self.data.set.log = Log()
Pub().pub(f"openWB/set/chargepoint/{self.num}/set/log", asdict(self.data.set.log))

def prepare_cp(self) -> Tuple[int, Optional[str]]:
try:
Expand Down Expand Up @@ -902,7 +909,7 @@ def update(self, ev_list: Dict[str, Ev]) -> None:
# Ein Eintrag muss nur erstellt werden, wenn vorher schon geladen wurde und auch danach noch
# geladen werden soll.
if charging_ev.chargemode_changed and self.data.get.charge_state and state:
chargelog.save_data(self, charging_ev)
chargelog.save_interim_data(self, charging_ev)

# Wenn die Nachrichten gesendet wurden, EV wieder löschen, wenn das EV im Algorithmus nicht
# berücksichtigt werden soll.
Expand Down
2 changes: 1 addition & 1 deletion packages/control/process.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def process_algorithm_results(self) -> None:
else:
# LP, an denen nicht geladen werden darf
if cp.data.set.charging_ev_prev != -1:
chargelog.save_data(
chargelog.save_interim_data(
cp, data.data.ev_data
["ev" + str(cp.data.set.charging_ev_prev)],
immediately=False)
Expand Down
4 changes: 3 additions & 1 deletion packages/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,9 @@ def schedule_jobs():
[schedule.every().minute.at(f":{i:02d}").do(smarthome_handler).tag("algorithm") for i in range(0, 60, 5)]
[schedule.every().hour.at(f":{i:02d}").do(handler.handler5Min) for i in range(0, 60, 5)]
[schedule.every().hour.at(f":{i:02d}").do(handler.handler5MinAlgorithm).tag("algorithm") for i in range(0, 60, 5)]
schedule.every().hour.do(handler.handler_hour).tag("algorithm")
[schedule.every().day.at(f"{i:02d}:00").do(handler.handler_hour).tag("algorithm") for i in range(0, 24, 1)]
# every().hour ruft nicht jede Stunde den Handler auf.
# schedule.every().hour.do(handler.handler_hour).tag("algorithm")
schedule.every().day.at("00:00:00").do(handler.handler_midnight).tag("algorithm")
schedule.every().day.at(f"0{randrange(0, 5)}:{randrange(0, 59):02d}:{randrange(0, 59):02d}").do(
handler.handler_random_nightly)
Expand Down

0 comments on commit 1d1c7f2

Please sign in to comment.