109 lines
4.0 KiB
Python
109 lines
4.0 KiB
Python
import os, sys, time, csv, statistics, threading, queue
|
|
import numpy as np
|
|
|
|
scriptDir = os.path.dirname(os.path.realpath(__file__))
|
|
DEFAULT_OUTDIR = os.path.join(scriptDir, "logs")
|
|
|
|
class DeviceWorker:
|
|
"""
|
|
Arbeitet genau wie dein Single-Gerät-Logger:
|
|
- filter_window_size Rohsamples pro Loop
|
|
- ~10 Hz Loop (interval=0.1)
|
|
- 1 Hz Logging (eine CSV-Zeile pro Sekunde)
|
|
Wichtig: kontrolliert NICHT die Session!
|
|
"""
|
|
def __init__(self, dev, outdir=DEFAULT_OUTDIR, filter_window_size=10, interval=0.1):
|
|
self.dev = dev
|
|
self.serial = getattr(dev, "serial", "UNKNOWN")
|
|
self.outdir = outdir
|
|
self._log_path = None
|
|
self.filter_window_size = filter_window_size
|
|
self.interval = interval
|
|
|
|
self._running = False
|
|
self._stop_evt = threading.Event()
|
|
self._cmdq = queue.Queue()
|
|
self._writer_q = queue.Queue(maxsize=50)
|
|
|
|
self._reader_t = threading.Thread(target=self._reader_loop, daemon=True)
|
|
self._writer_t = threading.Thread(target=self._writer_loop, daemon=True)
|
|
|
|
# ---- API ----
|
|
def start(self):
|
|
print(f"[{self.serial}] Worker.start()")
|
|
if not self._reader_t.is_alive(): self._reader_t.start()
|
|
if not self._writer_t.is_alive(): self._writer_t.start()
|
|
self._cmdq.put(("start", None))
|
|
|
|
def stop(self):
|
|
print(f"[{self.serial}] Worker.stop()")
|
|
self._cmdq.put(("stop", None))
|
|
|
|
def shutdown(self):
|
|
self.stop()
|
|
self._stop_evt.set()
|
|
|
|
def set_mode(self, ch, mode):
|
|
key = {0: "A", 1: "B"}.get(ch, str(ch).upper())
|
|
self.dev.channels[key].mode = mode
|
|
|
|
def _reader_loop(self):
|
|
print(f"[{self.serial}] Reader gestartet (interval={self.interval}, n={self.filter_window_size})")
|
|
filter_window_size = 10
|
|
interval = self.interval
|
|
last_log = -999.0
|
|
current_direction = 1 # falls du das brauchst wie im Single-Logger
|
|
|
|
while not self._stop_evt.is_set():
|
|
if not self._running:
|
|
time.sleep(0.05); continue
|
|
try:
|
|
# exakt wie im Single-Logger:
|
|
samples = self.dev.read(filter_window_size, 500, True)
|
|
|
|
if not samples:
|
|
time.sleep(interval)
|
|
continue
|
|
|
|
# WICHTIG: gleiche Indizes wie in deinem Logger!
|
|
vb = float(np.mean([s[1][0] for s in samples])) # Spannung B
|
|
ia = float(np.mean([s[0][1] for s in samples]))
|
|
|
|
print(f"[{self.serial}] got {len(samples)} samples; vb={vb:.3f}, ia={ia:.3f}")
|
|
|
|
now = time.time()
|
|
if now - last_log >= 1.0: # 1 Hz loggen
|
|
self._writer_q.put((now, vb, ia))
|
|
last_log = now
|
|
|
|
except Exception as e:
|
|
print(f"[{self.serial}] Read-Fehler: {e}")
|
|
time.sleep(0.05)
|
|
|
|
time.sleep(max(0.05, interval))
|
|
|
|
def _writer_loop(self):
|
|
try:
|
|
os.makedirs(self.outdir, exist_ok=True)
|
|
except Exception as e:
|
|
print(f"[{self.serial}] os.makedirs-Fehler für '{self.outdir}': {e}")
|
|
return
|
|
|
|
self._log_path = os.path.join(self.outdir, f"{time.strftime('%Y%m%d_%H%M%S')}_{self.serial}.csv")
|
|
print(f"[{self.serial}] Writer startet → {self._log_path}")
|
|
|
|
written = 0
|
|
with open(self._log_path, "w", newline="") as f:
|
|
w = csv.writer(f)
|
|
w.writerow(["timestamp", "VB", "IA"]) # Datei JETZT sichtbar
|
|
while not (self._stop_evt.is_set() and self._writer_q.empty()):
|
|
try:
|
|
ts, vb, ia = self._writer_q.get(timeout=0.5)
|
|
except queue.Empty:
|
|
continue
|
|
w.writerow([ts, vb, ia])
|
|
written += 1
|
|
if written % 5 == 0:
|
|
f.flush()
|
|
print(f"[{self.serial}] rows written: {written}")
|
|
print(f"[{self.serial}] Writer beendet: {self._log_path}") |