fix: replace Unicode chars in log messages, fix DeviceInfo.serial, UTF-8 file log

- Replace all Unicode arrows/checkmarks (->  [OK]  [FAIL]) in ach_server.py
  and client.py log calls — Windows cp1252 console can't encode them
- Fix DeviceInfo attribute: serial_number -> serial
- Fix _device_info_to_dict key: serial_number -> serial
- Demote count_events 1E/1F per-key log lines from WARNING to DEBUG
  (they were flooding the console on devices with many stored events)
- FileHandler now opens with encoding='utf-8' so session log files
  can hold any characters without codec errors

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-10 01:06:27 -04:00
committed by serversdown
parent 574d40027f
commit 1bfc6e4258
2 changed files with 13 additions and 13 deletions
+1 -1
View File
@@ -136,7 +136,7 @@ class AchSession:
raw_path = session_dir / f"raw_rx_{ts}.bin" raw_path = session_dir / f"raw_rx_{ts}.bin"
# Wire up a file handler so every protocol log line goes to the session log # Wire up a file handler so every protocol log line goes to the session log
fh = logging.FileHandler(log_path) fh = logging.FileHandler(log_path, encoding="utf-8")
fh.setFormatter(logging.Formatter("%(asctime)s %(levelname)-7s %(name)s %(message)s")) fh.setFormatter(logging.Formatter("%(asctime)s %(levelname)-7s %(name)s %(message)s"))
root_logger = logging.getLogger() root_logger = logging.getLogger()
root_logger.addHandler(fh) root_logger.addHandler(fh)
+12 -12
View File
@@ -216,8 +216,8 @@ class MiniMateClient:
log.warning("count_events: 1E failed: %s — returning 0", exc) log.warning("count_events: 1E failed: %s — returning 0", exc)
return 0 return 0
log.warning( log.debug(
"count_events: 1E key=%s data8=%s trailing=%s", "count_events: 1E -> key=%s data8=%s trailing=%s",
key4.hex(), data8.hex(), data8[4:8].hex(), key4.hex(), data8.hex(), data8[4:8].hex(),
) )
@@ -241,8 +241,8 @@ class MiniMateClient:
break break
try: try:
key4, data8 = proto.advance_event(browse=True) key4, data8 = proto.advance_event(browse=True)
log.warning( log.debug(
"count_events: 1F [iter %d] key=%s data8=%s trailing=%s", "count_events: 1F [iter %d] -> key=%s data8=%s trailing=%s",
count, key4.hex(), data8.hex(), data8[4:8].hex(), count, key4.hex(), data8.hex(), data8[4:8].hex(),
) )
except ProtocolError as exc: except ProtocolError as exc:
@@ -426,7 +426,7 @@ class MiniMateClient:
try: try:
key4, data8 = proto.advance_event(browse=True) key4, data8 = proto.advance_event(browse=True)
log.info( log.info(
"get_events: 1F(browse) key=%s trailing=%s", "get_events: 1F(browse) -> key=%s trailing=%s",
key4.hex(), data8[4:8].hex(), key4.hex(), data8[4:8].hex(),
) )
except ProtocolError as exc: except ProtocolError as exc:
@@ -481,7 +481,7 @@ class MiniMateClient:
try: try:
key4, data8 = proto.advance_event(browse=True) key4, data8 = proto.advance_event(browse=True)
log.info( log.info(
"get_events: 1F key=%s trailing=%s", "get_events: 1F -> key=%s trailing=%s",
key4.hex(), data8[4:8].hex(), key4.hex(), data8[4:8].hex(),
) )
except ProtocolError as exc: except ProtocolError as exc:
@@ -1499,14 +1499,14 @@ def _encode_compliance_config(
log.warning("_encode_compliance_config: anchor not found — cannot write sample_rate") log.warning("_encode_compliance_config: anchor not found — cannot write sample_rate")
else: else:
struct.pack_into(">H", buf, _anc - 6, sample_rate) struct.pack_into(">H", buf, _anc - 6, sample_rate)
log.debug("_encode_compliance_config: sample_rate=%d offset %d", sample_rate, _anc - 6) log.debug("_encode_compliance_config: sample_rate=%d -> offset %d", sample_rate, _anc - 6)
if record_time is not None: if record_time is not None:
if _anc < 0 or _anc + 10 > len(buf): if _anc < 0 or _anc + 10 > len(buf):
log.warning("_encode_compliance_config: anchor not found — cannot write record_time") log.warning("_encode_compliance_config: anchor not found — cannot write record_time")
else: else:
struct.pack_into(">f", buf, _anc + 6, record_time) struct.pack_into(">f", buf, _anc + 6, record_time)
log.debug("_encode_compliance_config: record_time=%.3f offset %d", record_time, _anc + 6) log.debug("_encode_compliance_config: record_time=%.3f -> offset %d", record_time, _anc + 6)
# ── Numeric: channel block (Tran label + unit-string guard) ─────────────── # ── Numeric: channel block (Tran label + unit-string guard) ───────────────
_needs_channel = any( _needs_channel = any(
@@ -1529,13 +1529,13 @@ def _encode_compliance_config(
else: else:
if max_range_geo is not None: if max_range_geo is not None:
struct.pack_into(">f", buf, _tran + 28, max_range_geo) struct.pack_into(">f", buf, _tran + 28, max_range_geo)
log.debug("_encode_compliance_config: max_range_geo=%.4f offset %d", max_range_geo, _tran + 28) log.debug("_encode_compliance_config: max_range_geo=%.4f -> offset %d", max_range_geo, _tran + 28)
if trigger_level_geo is not None: if trigger_level_geo is not None:
struct.pack_into(">f", buf, _tran + 34, trigger_level_geo) struct.pack_into(">f", buf, _tran + 34, trigger_level_geo)
log.debug("_encode_compliance_config: trigger_level_geo=%.4f offset %d", trigger_level_geo, _tran + 34) log.debug("_encode_compliance_config: trigger_level_geo=%.4f -> offset %d", trigger_level_geo, _tran + 34)
if alarm_level_geo is not None: if alarm_level_geo is not None:
struct.pack_into(">f", buf, _tran + 42, alarm_level_geo) struct.pack_into(">f", buf, _tran + 42, alarm_level_geo)
log.debug("_encode_compliance_config: alarm_level_geo=%.4f offset %d", alarm_level_geo, _tran + 42) log.debug("_encode_compliance_config: alarm_level_geo=%.4f -> offset %d", alarm_level_geo, _tran + 42)
# ── ASCII strings (64-byte slot, value at label_pos+22) ─────────────────── # ── ASCII strings (64-byte slot, value at label_pos+22) ───────────────────
def _set_string(label: bytes, value: Optional[str]) -> None: def _set_string(label: bytes, value: Optional[str]) -> None:
@@ -1548,7 +1548,7 @@ def _encode_compliance_config(
val_bytes = value.encode("ascii", errors="replace")[:_COMPLIANCE_VALUE_MAX - 1] val_bytes = value.encode("ascii", errors="replace")[:_COMPLIANCE_VALUE_MAX - 1]
padded = val_bytes + b"\x00" * (_COMPLIANCE_VALUE_MAX - len(val_bytes)) padded = val_bytes + b"\x00" * (_COMPLIANCE_VALUE_MAX - len(val_bytes))
buf[idx + _COMPLIANCE_VALUE_OFFSET : idx + _COMPLIANCE_SLOT_SIZE] = padded buf[idx + _COMPLIANCE_VALUE_OFFSET : idx + _COMPLIANCE_SLOT_SIZE] = padded
log.debug("_encode_compliance_config: %r %r", label, value) log.debug("_encode_compliance_config: %r -> %r", label, value)
_set_string(b"Project:", project) _set_string(b"Project:", project)
_set_string(b"Client:", client_name) _set_string(b"Client:", client_name)