Files
cantarire-etichetare/vendor/syncpulse-scale-bridge/tests/test_labels.py
T
ske087 bff6d70b17 Initial commit: aplicatie de cantarire si etichetare
Aplicatie Flask + SQLite pentru productie alimentara: cantarirea
componentelor unui produs finit si tiparirea etichetei prin QZ Tray.

- produse finite (retete) formate din componente cantarite
- designer vizual de etichete (mm/px, zona sigura, campuri variabile,
  cod QR cu continut din mai multe bucati)
- legare produs finit -> sablon de eticheta
- navigare pe doua taburi: Cantarire / Setari
- administrare: componente, produse finite, sabloane, campuri, istoric
- backup, resetare baza de date, checklist de pregatire, /healthz
- CLI de administrare si serviciu systemd pentru productie
- vendor/syncpulse-scale-bridge (GPL-3.0-or-later) pentru citirea cantarului
2026-10-18 23:38:45 +03:00

138 lines
5.7 KiB
Python

# SPDX-License-Identifier: GPL-3.0-or-later
"""Indicators that print labels: the PTC400 capture, other label languages, the label log."""
import json
import os
import time
import pytest
from scale_bridge import profiles
from scale_bridge.detect import Detector, Timings
from scale_bridge.labels import LabelLog
from scale_bridge.protocols import PROTOCOLS
from scale_bridge.simulator import SimulatorBank
HERE = os.path.dirname(os.path.abspath(__file__))
FAST = Timings(passive_s=0.4, probe_s=0.1, confirm_s=0.3, drain_s=0.02)
def capture() -> list[bytes]:
with open(os.path.join(HERE, "captures", "ptc400_tspl_labels.hex"), encoding="ascii") as f:
return [bytes.fromhex(line) for line in f if line.strip()]
def test_ptc400_capture_all_labels():
# Recorded from a PTC400 indicator (TSPL to a TSC label printer), a 1.4 kg
# test weight moved around the platform after three other weighings.
readings = PROTOCOLS["label_print"].readings(b"".join(capture()))
assert [r.value for r in readings] == [102.3, 141.8, 141.2, 1.4, 1.4, 1.35, 1.3, 1.25, 0.95,
1.2, 1.25, 1.15]
first = readings[0]
assert first.unit == "kg" and first.stable is True
assert first.fields["Order.Co"] == "222" and first.fields["SHIFT"] == "2"
assert first.fields["date"] == "1405/07/19" and first.fields["time"] == "16:39"
assert first.fields["Thickness"] == "0.0" and first.fields["No"] == "6"
assert readings[2].fields["Thickness"] == "3.3"
def test_label_split_over_two_chunks_is_read_once():
label = capture()[0]
chunks = [(1000, label[:200]), (1020, label[200:])]
timed = profiles.timed_readings("label_print", None, chunks)
assert len(timed) == 1 and timed[0].t_ms == 1020 and timed[0].reading.value == 102.3
@pytest.mark.parametrize("label,value,unit", [
(b'^XA^FO50,50^A0N,40,40^FDNet: 12.34 kg^FS^FO50,120^FDLOT 7^FS^XZ', 12.34, "kg"),
(b'N\r\nA50,0,0,4,1,1,N,"Weight"\r\nA50,40,0,4,1,1,N,"2.500"\r\nA200,40,0,4,1,1,N,"kg"\r\nP1\r\n',
2.5, "kg"),
(b'CLS\r\nTEXT 10,10,"3",0,1,1,"GROSS 15.6 kg"\r\nPRINT 1,1\r\n', 15.6, "kg"),
])
def test_other_label_languages(label, value, unit):
r = PROTOCOLS["label_print"].readings(label)[-1]
assert (r.value, r.unit) == (value, unit)
def test_label_without_weight_is_ignored():
assert PROTOCOLS["label_print"].readings(b'CLS\r\nTEXT 1,1,"3",0,1,1,"Hello"\r\nPRINT 1\r\n') == []
@pytest.mark.parametrize("spec,baud,parity,wrong", [
("label_print", 9600, "N", 0), ("label_print:4800", 4800, "N", 2), ("label_print:9600:7E1", 9600, "E", 0),
])
def test_wait_for_print_detection(spec, baud, parity, wrong):
bank = SimulatorBank(spec)
events = []
detector = Detector(bank.opener(), log=lambda code, **kw: events.append(code), timings=FAST,
print_wait_s=5, listen_only=True)
result = detector.run_port("COM90")
assert result["found"] and result["protocol"] == "label_print" and result["mode"] == "print"
assert result["serial"]["baudrate"] == baud and result["serial"]["parity"] == parity
assert result["reading"]["fields"]["Order.Co"] == "222"
assert events.count("print_wrong_speed") == wrong
assert "ask" not in events # listen only: nothing was sent
def test_listen_only_sends_nothing():
written = []
class Quiet:
in_waiting = 0
def __init__(self, s):
pass
def read(self, n=1):
time.sleep(0.01)
return b""
def write(self, data):
written.append(data)
return len(data)
def close(self):
pass
result = Detector(lambda s: Quiet(s), timings=FAST, print_wait_s=0.3, listen_only=True).run_port("COM5")
assert result["found"] is False and written == []
def test_label_log_feeds_pieces_and_writes_files(tmp_path):
log = LabelLog(str(tmp_path))
profile = profiles.validate({"name": "label-1", "port": "COM8", "protocol": "label_print",
"serial": {"baudrate": 9600}})
a, b = capture()[3], capture()[4]
assert log.feed(profile, a[:100]) == []
got = log.feed(profile, a[100:] + b)
assert [r["value"] for r in got] == [1.4, 1.4] and [r["seq"] for r in got] == [1, 2]
assert [r["seq"] for r in log.list("label-1", after=1)] == [2]
files = list(tmp_path.iterdir())
assert len(files) == 1 and files[0].name.startswith("label-1-")
lines = files[0].read_text(encoding="utf-8").splitlines()
assert json.loads(lines[0])["fields"]["Order.Co"] == "222"
def test_bridge_keeps_print_scale_open_and_logs_labels(tmp_path):
from scale_bridge.config import Config
from scale_bridge.server import Bridge
config = Config(str(tmp_path / "bridge.json"))
bridge = Bridge(config, simulate="label_print")
try:
config.save_profile({"name": "label-1", "port": "COM90", "protocol": "label_print",
"serial": {"baudrate": 9600}})
bridge.keeper.tick()
deadline = time.time() + 12
while time.time() < deadline and not bridge.labels.list("label-1"):
time.sleep(0.3)
listed = bridge.label_list({"profile": "label-1"})
assert listed["labels"] and listed["listening"] == ["label-1"]
assert listed["labels"][-1]["fields"]["SHIFT"] == "2"
started = time.monotonic()
answer = bridge.weight(config.profile("label-1"), max_age_ms=60000, wait_ms=2500)
assert time.monotonic() - started < 1.5 # a print scale never holds the caller
assert answer["ok"] and answer["on_print"] and answer["stable"] and answer["unit"] == "kg"
assert (tmp_path / "labels").is_dir()
finally:
bridge.keeper.stop()
bridge.registry.stop_all()