The bridge becomes pure transport: it opens the port, writes a poll
string it is given at runtime, and streams raw lines. Protocol
definitions live in Django and parsing happens in the browser, so a new
scale type never means a new binary on the station PCs. The poll loop
stays in the bridge because a browser cannot be the heartbeat - hidden
tabs get throttled and a closed tab would stop the scale.
Every payload now carries a hex field. Toledo Continuous sends STX and
bit-packed status, which UTF-8 decoding silently corrupts. Fixed-column
protocols need the opposite care: a space can mean balanced, so the
trailing whitespace must survive.
Parsers for the simulator, fixed-column, Toledo Continuous and SICS
return an explicit error rather than a guess on a frame that does not
match, since a silently wrong weight on a weighbridge is worse than no
weight. Toledo and SICS are written from documented structure and have
not been validated against real hardware.
The admin monitor shows the raw stream as text and hex, sends one-off
probe commands, and builds fixed-column protocols against captured
lines. Spaces render as middots because in some protocols a space is
the stability flag.
The test writer now simulates a weighing cycle - idle, ramp, balanced,
drop - alternating empty and loaded trucks, quantised to the 20kg and
50kg divisions real truck scales use.
Bridge logging rotates and per-reading lines drop to DEBUG; the old
config had grown two log files totalling 368MB.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Shows previously-used combinations of lookup nomenclature values above
the Additional Data fields in both the new-vehicle and edit forms.
Clicking a row merges the combination into the current values, so
free-text fields the operator already typed are preserved.
NomenclatureContext now fans extra_combination events out to
subscribers; without that they hit the unknown-object warning and were
dropped, so deletes would not have reached other open tabs.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Four related backend features. They are committed together because they
interleave in api/views.py and api/serializers.py - one hunk holds the
combinations ViewSet, the licensing helpers and LicenseView - and
splitting by hunk would produce commits that do not import.
ExtraCombination records previously-used combinations of lookup
nomenclature values so an operator can refill the Additional Data fields
in one click. Deduplicated by a canonical order-independent hash, since
JSONField equality compares serialized text on SQLite and so depends on
key order.
Weighing replaces set_tare/set_gross with a single measure action that
assigns by weight - lighter becomes tare, heavier gross - because trucks
arrive both loaded and empty. A second, lighter reading moves the first
to gross carrying its own timestamp, user and manual fields, so
provenance follows the value rather than the slot. Manual entries record
who, when and why, gated on the previously unenforced can_measure and
can_manually_measure flags.
ScaleProtocol stores how to read each indicator, so a new scale type is
a configuration change rather than a new binary on every station PC.
Licensing is offline and node-locked: the server verifies an Ed25519
signature against a fingerprint of four hardware components, tolerating
one change, and counts concurrently connected stations. Sites are
air-gapped, so there is no activation server. A 14-day grace period
keeps an unlicensed or newly-invalid install working, because a licence
check must never stop a weighbridge without warning.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Nomenclatures can be reordered by dragging in the left-hand list, which
PATCHes sort_order on the rows that moved. PATCH rather than PUT, since a
full update recreates the nested fields collection.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Backend now runs on 8002 and the frontend dev server on 5172, with the
proxy, CORS origins and the run_*.bat launchers updated to match. The
launchers also activate the venv so they work from a clean shell.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>