add daemon mode

This commit is contained in:
osiu97
2026-01-02 10:58:02 +01:00
parent 10d00c8fbb
commit 814c41098f
4 changed files with 100 additions and 103 deletions
+60 -1
View File
@@ -1,11 +1,45 @@
import csv
import json
import os
import math
import struct
from typing import Iterable, List
from typing import List, Optional
from .models import PowerMeterReadings
class ReadingsCsvLogger:
def __init__(self, file_path: str, fieldnames: List[str]):
self._file_path = file_path
self._fieldnames = fieldnames
self._fp = None
self._writer: Optional[csv.DictWriter] = None
def __enter__(self) -> "ReadingsCsvLogger":
is_new_file = (not os.path.exists(self._file_path)) or os.path.getsize(self._file_path) == 0
self._fp = open(self._file_path, "a", newline="", encoding="utf-8")
self._writer = csv.DictWriter(self._fp, fieldnames=self._fieldnames)
if is_new_file:
self._writer.writeheader()
self._fp.flush()
return self
def __exit__(self, exc_type, exc, tb) -> None:
if self._fp is not None:
try:
self._fp.flush()
finally:
self._fp.close()
self._fp = None
self._writer = None
def log(self, row: dict) -> None:
if self._writer is None or self._fp is None:
raise RuntimeError("CSV logger is not open")
self._writer.writerow(row)
self._fp.flush()
class PowerMeterDataHandler:
"""Parses Modbus RTU responses and computes derived power metrics."""
@@ -90,6 +124,31 @@ class PowerMeterDataHandler:
def print_readings_json(self, readings: PowerMeterReadings) -> None:
print(self.readings_to_json(readings, ensure_ascii=False))
def open_csv_logger(self, file_path: str) -> ReadingsCsvLogger:
fieldnames = ["timestamp"] + self._flat_readings_keys()
return ReadingsCsvLogger(file_path=file_path, fieldnames=fieldnames)
@staticmethod
def _flat_readings_keys() -> List[str]:
# Keep order stable for CSV columns.
return [
"active_power_w",
"rms_current_a",
"voltage_v",
"frequency_hz",
"power_factor",
"annual_power_consumption_kwh",
"active_consumption_kwh",
"reactive_consumption_kwh",
"load_time_hours",
"work_hours_per_day",
"device_address",
"apparent_power_vi_va",
"apparent_power_pf_va",
"reactive_power_var",
"apparent_consumption_kvah",
]
@staticmethod
def _bytes_to_registers_be(data: bytes) -> List[int]:
registers: List[int] = []