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
171 lines
6.2 KiB
HTML
171 lines
6.2 KiB
HTML
{% extends "base.html" %}
|
||
{% block title %}Monitor serial{% endblock %}
|
||
|
||
{% block content %}
|
||
<section class="page-head">
|
||
<div>
|
||
<h1>Monitor serial</h1>
|
||
<p class="subtitle">Ascultă portul cântarului și află ce format trimite. Nu se scrie nimic către cântar.</p>
|
||
</div>
|
||
</section>
|
||
|
||
<div class="notice">
|
||
<strong>Folosire:</strong> conectează cântarul, pornește o cântărire pe el (sau apasă Print) și rulează
|
||
monitorul. Dacă nu apar bytes, încearcă <em>Scanează vitezele</em> sau altă setare de linie.
|
||
O captură salvată aici este exact ce trebuie ca să adăugăm un protocol nou.
|
||
</div>
|
||
|
||
<section class="card">
|
||
<form method="post" class="filters">
|
||
<div class="field">
|
||
<label for="port">Port</label>
|
||
<input id="port" name="port" type="text" list="port-list" required
|
||
placeholder="/dev/ttyUSB0 sau COM3" value="{{ values.port }}">
|
||
<datalist id="port-list">
|
||
{% for p in ports %}
|
||
<option value="{{ p.device }}">{{ p.description or p.device }}{% if p.chip %} · {{ p.chip }}{% endif %}</option>
|
||
{% endfor %}
|
||
</datalist>
|
||
</div>
|
||
<div class="field">
|
||
<label for="baud">Baud</label>
|
||
<input id="baud" name="baud" type="number" min="50" max="921600" value="{{ values.baud }}">
|
||
</div>
|
||
<div class="field">
|
||
<label for="framing">Framing</label>
|
||
<select id="framing" name="framing">
|
||
{% for f in framings %}
|
||
<option value="{{ f }}" {{ 'selected' if values.framing == f }}>{{ f }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
</div>
|
||
<div class="field">
|
||
<label for="seconds">Secunde</label>
|
||
<input id="seconds" name="seconds" type="number" min="0.5" max="30" step="0.5" value="{{ values.seconds }}">
|
||
</div>
|
||
<div class="field">
|
||
<label for="name">Nume captură</label>
|
||
<input id="name" name="name" type="text" maxlength="60" value="{{ values.name }}">
|
||
</div>
|
||
<div class="field actions-field">
|
||
<button class="btn primary" type="submit">Ascultă</button>
|
||
</div>
|
||
<div class="monitor-options">
|
||
<label class="check"><input type="checkbox" name="scan" value="1" {{ 'checked' if values.scan }}> Scanează vitezele</label>
|
||
<label class="check"><input type="checkbox" name="save" value="1" {{ 'checked' if values.save }}> Salvează captura</label>
|
||
</div>
|
||
</form>
|
||
|
||
{% if ports %}
|
||
<p class="muted small">
|
||
Porturi detectate:
|
||
{% for p in ports %}<code>{{ p.device }}</code>{% if p.chip %} ({{ p.chip }}){% endif %}{% if not loop.last %}, {% endif %}{% endfor %}
|
||
</p>
|
||
{% else %}
|
||
<p class="muted small">Nu a fost detectat niciun port. Verifică adaptorul USB-RJ11 (driver, cablu).</p>
|
||
{% endif %}
|
||
</section>
|
||
|
||
{% if error %}
|
||
<div class="notice warning">{{ error }}</div>
|
||
{% endif %}
|
||
|
||
{% if saved_path %}
|
||
<div class="notice"><strong>Cauptră salvată:</strong> <code>{{ saved_path }}</code></div>
|
||
{% endif %}
|
||
|
||
{% if scan_hits %}
|
||
<section class="card">
|
||
<h2>Viteze cu date</h2>
|
||
<div class="table-wrap">
|
||
<table class="table">
|
||
<thead><tr><th>Baud</th><th>Framing</th><th class="num">Bytes</th><th>Protocoale recunoscute</th></tr></thead>
|
||
<tbody>
|
||
{% for hit in scan_hits %}
|
||
<tr>
|
||
<td>{{ hit.baud }}</td>
|
||
<td>{{ hit.framing }}</td>
|
||
<td class="num">{{ hit.bytes }}</td>
|
||
<td>
|
||
{% if hit.guesses %}
|
||
{% for g in hit.guesses %}<span class="badge ok">{{ g.protocol }}</span> {% endfor %}
|
||
{% else %}<span class="muted">necunoscut</span>{% endif %}
|
||
</td>
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</section>
|
||
{% endif %}
|
||
|
||
{% if result %}
|
||
<section class="card">
|
||
<div class="card-head">
|
||
<h2>Rezultat: {{ result.port }} · {{ result.baud }} {{ result.framing }}</h2>
|
||
<span class="badge {{ 'ok' if result.ok else 'err' }}">{{ result.bytes }} bytes</span>
|
||
</div>
|
||
|
||
{% if result.guesses %}
|
||
<h3>Protocoale recunoscute</h3>
|
||
<div class="table-wrap">
|
||
<table class="table compact">
|
||
<thead><tr><th>ID</th><th>Nume</th><th>Tip</th><th class="num">Valoare</th><th class="num">Cadre</th></tr></thead>
|
||
<tbody>
|
||
{% for g in result.guesses %}
|
||
<tr>
|
||
<td><code>{{ g.protocol }}</code></td>
|
||
<td>{{ g.name }}</td>
|
||
<td>{{ g.kind }}</td>
|
||
<td class="num">{{ g.value }} {{ g.unit }}</td>
|
||
<td class="num">{{ g.count }}</td>
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
{% else %}
|
||
<p class="muted">Niciun protocol cunoscut nu recunoaște datele. Salvează captura și o folosim ca să scriem parserul.</p>
|
||
{% endif %}
|
||
|
||
<h3>Cadre brute ({{ result.frames|length }})</h3>
|
||
{% if result.frames %}
|
||
<div class="table-wrap">
|
||
<table class="table compact">
|
||
<thead><tr><th class="num">Acum</th><th class="num">Bytes</th><th>Hex</th><th>Text</th></tr></thead>
|
||
<tbody>
|
||
{% for f in result.frames %}
|
||
<tr>
|
||
<td class="num">{{ f.age_ms }} ms</td>
|
||
<td class="num">{{ f.size }}</td>
|
||
<td><code class="hex">{{ f.hex }}</code></td>
|
||
<td><code>{{ f.text }}</code></td>
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
{% else %}
|
||
<p class="muted">Niciun byte primit. Cântarul poate fi setat să nu trimită nimic pe această interfață.</p>
|
||
{% endif %}
|
||
</section>
|
||
{% endif %}
|
||
|
||
<section class="card help-card">
|
||
<h2>Setări de încercat</h2>
|
||
<ul class="var-list">
|
||
<li><code>9600 8N1</code> — cel mai comun pentru cântare de magazin.</li>
|
||
<li><code>9600 7E1</code> / <code>4800 7E1</code> — frecvent la indicatoarele vechi.</li>
|
||
<li><code>9600 7O1</code> — dacă textul apare cu bitul 8 schimbat.</li>
|
||
<li>Unele cântare trimit doar la apăsarea <em>Print</em>: ține monitorul pornit și apasă.</li>
|
||
</ul>
|
||
<h2>Cablaj modular (RJ11 / 10P4C)</h2>
|
||
<p class="muted small">
|
||
Un adaptor USB–RJ11 funcționează doar dacă cei patru ași ai prizei cântarului sunt
|
||
<strong>TX, RX, GND</strong> la nivel RS-232 și adaptorul are aceeași ordine. Verifică pinoutul în manualul
|
||
BC800 înainte de a conecta; unele prize modulare de cântar sunt TTL sau current-loop și nu se leagă
|
||
direct la un adaptor RS-232.
|
||
</p>
|
||
</section>
|
||
{% endblock %}
|