Files
maziggy 4fb4e5faac Fix SpoolBuddy scale calibration lost after reboot
_get_mac_id() used Path.iterdir() to find a network interface for the
  device ID, but iteration order is non-deterministic. On different boots
  it could pick eth0 (MAC …3100) or wlan0 (MAC …3102), producing a
  different device_id each time. Since calibration is stored per device ID
  in the backend DB, a new ID meant registering as an uncalibrated device.

  Sort interfaces alphabetically so the same one is always selected.
2026-03-01 13:27:04 +01:00

84 lines
2.6 KiB
Python

"""Configuration loader for SpoolBuddy daemon.
All configuration is via environment variables. The systemd service file
or a shell wrapper sets these before launching the daemon.
Required:
SPOOLBUDDY_BACKEND_URL — Bambuddy server URL (e.g. http://192.168.1.100:5000)
SPOOLBUDDY_API_KEY — API key created in Bambuddy Settings → API Keys
Optional:
SPOOLBUDDY_DEVICE_ID — Unique device identifier (default: derived from MAC)
SPOOLBUDDY_HOSTNAME — Display name (default: system hostname)
"""
import os
import socket
from dataclasses import dataclass
from pathlib import Path
@dataclass
class Config:
backend_url: str = ""
api_key: str = ""
device_id: str = ""
hostname: str = ""
nfc_poll_interval: float = 0.3
scale_read_interval: float = 0.1
scale_report_interval: float = 1.0
heartbeat_interval: float = 10.0
stability_threshold: float = 2.0
stability_window: float = 1.0
tare_offset: int = 0
calibration_factor: float = 1.0
@classmethod
def load(cls) -> "Config":
cfg = cls()
cfg.backend_url = os.environ.get("SPOOLBUDDY_BACKEND_URL", "")
cfg.api_key = os.environ.get("SPOOLBUDDY_API_KEY", "")
cfg.device_id = os.environ.get("SPOOLBUDDY_DEVICE_ID", "")
cfg.hostname = os.environ.get("SPOOLBUDDY_HOSTNAME", "")
if not cfg.backend_url:
raise RuntimeError("SPOOLBUDDY_BACKEND_URL is required (e.g. http://192.168.1.100:5000)")
if not cfg.api_key:
raise RuntimeError("SPOOLBUDDY_API_KEY is required (create one in Bambuddy Settings → API Keys)")
# Default device_id from MAC address
if not cfg.device_id:
cfg.device_id = _get_mac_id()
# Default hostname from system
if not cfg.hostname:
cfg.hostname = socket.gethostname()
return cfg
def _get_mac_id() -> str:
"""Generate a stable device ID from the primary network interface MAC address.
Interfaces are sorted by name so the same interface is always picked
regardless of filesystem iteration order (eth0 before wlan0, etc.).
"""
try:
ifaces = sorted(Path("/sys/class/net").iterdir(), key=lambda p: p.name)
for iface in ifaces:
if iface.name == "lo":
continue
addr_file = iface / "address"
if addr_file.exists():
mac = addr_file.read_text().strip().replace(":", "")
if mac and mac != "000000000000":
return f"sb-{mac}"
except Exception:
pass
import uuid
return f"sb-{uuid.uuid4().hex[:12]}"