"""CSV export/import of the device list, including AES keys.""" from __future__ import annotations import csv import time from typing import Dict, Iterable, List from .models import Device FIELDNAMES = [ "id", "manufacturer", "manufacturer_name", "media", "driver", "version", "first_seen", "last_seen", "count", "rssi", "interval_s", "interval_samples", "encryption", "security_mode", "status", "aes_key", ] def _fmt_time(ts: float) -> str: if not ts: return "" return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(ts)) def export_devices(path: str, devices: Iterable[Device]) -> int: n = 0 with open(path, "w", newline="") as f: writer = csv.DictWriter(f, fieldnames=FIELDNAMES) writer.writeheader() for d in devices: writer.writerow( { "id": d.id, "manufacturer": d.manufacturer, "manufacturer_name": d.manufacturer_name, "media": d.media, "driver": d.driver, "version": d.version, "first_seen": _fmt_time(d.first_seen), "last_seen": _fmt_time(d.last_seen), "count": d.count, "rssi": "" if d.rssi is None else d.rssi, "interval_s": ( "" if d.interval_estimate is None else round(d.interval_estimate, 1) ), "interval_samples": d.interval_samples, "encryption": d.encryption, "security_mode": d.sec_mode or "", "status": d.status, "aes_key": d.key or "", } ) n += 1 return n def import_rows(path: str) -> List[Dict[str, str]]: """Read a previously exported CSV. Returns a list of row dicts. Only ``id`` is required; ``aes_key`` and the metadata columns are optional, so hand-written key files with just ``id,aes_key`` import fine too. """ rows: List[Dict[str, str]] = [] with open(path, newline="") as f: reader = csv.DictReader(f) for row in reader: device_id = (row.get("id") or "").strip() if not device_id: continue rows.append({k: (v or "").strip() for k, v in row.items()}) return rows