Add data_logging/src/data_logging/main.py
This commit is contained in:
parent
51149591eb
commit
4f7dc84912
1 changed files with 96 additions and 0 deletions
96
data_logging/src/data_logging/main.py
Normal file
96
data_logging/src/data_logging/main.py
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
import argparse
|
||||
import json
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict
|
||||
import os
|
||||
|
||||
|
||||
class LogEntry:
|
||||
"""Repräsentiert einen einzelnen Telemetrie-Logeintrag."""
|
||||
|
||||
def __init__(self, timestamp: datetime, temperature: float, wind_speed: float, error_rate: float) -> None:
|
||||
if not isinstance(timestamp, datetime):
|
||||
raise TypeError("timestamp muss datetime sein")
|
||||
if not all(isinstance(v, (float, int)) for v in [temperature, wind_speed, error_rate]):
|
||||
raise TypeError("temperature, wind_speed und error_rate müssen numerisch sein")
|
||||
self.timestamp = timestamp
|
||||
self.temperature = float(temperature)
|
||||
self.wind_speed = float(wind_speed)
|
||||
self.error_rate = float(error_rate)
|
||||
|
||||
def to_json(self) -> Dict[str, Any]:
|
||||
"""Gibt die Struktur als JSON-kompatibles Dict zurück."""
|
||||
return {
|
||||
"timestamp": self.timestamp.isoformat(),
|
||||
"temperature": self.temperature,
|
||||
"wind_speed": self.wind_speed,
|
||||
"error_rate": self.error_rate,
|
||||
}
|
||||
|
||||
|
||||
def log_data(data: Dict[str, Any]) -> bool:
|
||||
"""Protokolliert übergebene Sensordatenobjekte in eine Logdatei."""
|
||||
if not isinstance(data, dict):
|
||||
raise TypeError("data muss ein dict sein")
|
||||
required = {"timestamp", "temperature", "wind_speed", "error_rate"}
|
||||
if not required.issubset(data):
|
||||
raise ValueError(f"Fehlende Felder: {required - set(data.keys())}")
|
||||
|
||||
entry = LogEntry(
|
||||
timestamp=datetime.fromisoformat(data["timestamp"]),
|
||||
temperature=float(data["temperature"]),
|
||||
wind_speed=float(data["wind_speed"]),
|
||||
error_rate=float(data["error_rate"]),
|
||||
)
|
||||
|
||||
output_path = data.get("_output_path")
|
||||
if not output_path:
|
||||
raise ValueError("_output_path muss angegeben werden")
|
||||
output = Path(output_path)
|
||||
output.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
try:
|
||||
if output.exists():
|
||||
with output.open("r", encoding="utf-8") as f:
|
||||
logs = json.load(f)
|
||||
if not isinstance(logs, list):
|
||||
logs = []
|
||||
else:
|
||||
logs = []
|
||||
logs.append(entry.to_json())
|
||||
with output.open("w", encoding="utf-8") as f:
|
||||
json.dump(logs, f, indent=2, ensure_ascii=False)
|
||||
return True
|
||||
except (OSError, json.JSONDecodeError) as e:
|
||||
print(f"Fehler beim Schreiben der Logdatei: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def _main() -> None:
|
||||
parser = argparse.ArgumentParser(description="Robot Night Telemetry Logger")
|
||||
parser.add_argument("--input", required=True, help="Pfad zur Eingabe-JSON-Datei mit Sensordaten.")
|
||||
parser.add_argument("--output", required=True, help="Zielpfad für die Protokollausgabe.")
|
||||
args = parser.parse_args()
|
||||
|
||||
input_path = Path(args.input)
|
||||
if not input_path.exists():
|
||||
raise FileNotFoundError(f"Eingabedatei nicht gefunden: {input_path}")
|
||||
|
||||
with input_path.open("r", encoding="utf-8") as f:
|
||||
try:
|
||||
telemetry_data = json.load(f)
|
||||
except json.JSONDecodeError as e:
|
||||
raise ValueError(f"Ungültige Eingabedatei: {e}")
|
||||
|
||||
if isinstance(telemetry_data, dict):
|
||||
telemetry_data = [telemetry_data]
|
||||
|
||||
for record in telemetry_data:
|
||||
if isinstance(record, dict):
|
||||
record["_output_path"] = args.output
|
||||
log_data(record)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
_main()
|
||||
Loading…
Reference in a new issue