bff6d70b17
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
86 lines
3.0 KiB
Python
86 lines
3.0 KiB
Python
"""Monitor de port serial: identifica formatul unui cantar necunoscut."""
|
|
from __future__ import annotations
|
|
|
|
import math
|
|
|
|
from flask import Blueprint, current_app, flash, redirect, render_template, request, url_for
|
|
|
|
from ..probe import BAUD_RATES, FRAMINGS, ProbeError, list_ports, save_capture, sweep
|
|
from ..scale import get_scale
|
|
|
|
bp = Blueprint("monitor", __name__, url_prefix="/monitor")
|
|
|
|
|
|
def _form_values() -> dict:
|
|
def number(name: str, default: float) -> float:
|
|
raw = (request.form.get(name) or "").strip().replace(",", ".")
|
|
try:
|
|
value = float(raw)
|
|
except ValueError:
|
|
return default
|
|
return value if math.isfinite(value) else default
|
|
|
|
return {
|
|
"port": (request.form.get("port") or "").strip(),
|
|
"baud": int(number("baud", 9600)),
|
|
"framing": (request.form.get("framing") or "8N1").strip().upper(),
|
|
"seconds": min(max(number("seconds", 5), 0.5), 30),
|
|
"save": bool(request.form.get("save")),
|
|
"name": (request.form.get("name") or "capture").strip()[:60],
|
|
"scan": bool(request.form.get("scan")),
|
|
}
|
|
|
|
|
|
@bp.route("", methods=["GET", "POST"])
|
|
def index():
|
|
scale = get_scale(current_app)
|
|
values = _form_values() if request.method == "POST" else {
|
|
"port": "", "baud": 9600, "framing": "8N1", "seconds": 5.0,
|
|
"save": False, "name": "capture", "scan": False,
|
|
}
|
|
|
|
result = None
|
|
scan_hits = None
|
|
saved_path = None
|
|
error = None
|
|
|
|
if request.method == "POST":
|
|
if not values["port"]:
|
|
error = "Alege portul serial."
|
|
elif values["scan"]:
|
|
try:
|
|
rows = sweep(values["port"], seconds=min(values["seconds"], 2.0),
|
|
framings=(values["framing"],), bauds=BAUD_RATES)
|
|
scan_hits = [r for r in rows if r.get("bytes")]
|
|
if not scan_hits:
|
|
error = "Niciun byte primit la vitezele incercate. Verifica cablul si setarile cantarului."
|
|
except ProbeError as exc:
|
|
error = str(exc)
|
|
else:
|
|
result = scale.probe(values["port"], values["baud"], values["framing"], values["seconds"])
|
|
if not result.get("ok"):
|
|
error = result.get("error") or "Portul nu a putut fi deschis."
|
|
elif values["save"] and result.get("frames"):
|
|
try:
|
|
saved_path = save_capture(
|
|
current_app.config["INSTANCE_DIR"] / "captures",
|
|
values["name"],
|
|
result["frames"],
|
|
)
|
|
flash(f"Captura a fost salvata in {saved_path}.", "success")
|
|
except OSError as exc:
|
|
error = f"Captura nu a putut fi scrisa: {exc}"
|
|
|
|
return render_template(
|
|
"monitor.html",
|
|
values=values,
|
|
ports=list_ports(),
|
|
profiles=scale.profiles(),
|
|
result=result,
|
|
scan_hits=scan_hits,
|
|
saved_path=saved_path,
|
|
error=error,
|
|
baud_rates=BAUD_RATES,
|
|
framings=FRAMINGS,
|
|
)
|