webserial-scale
v1.1.0
Published
TypeScript library to read weighing scales (Toledo, Filizola, Elgin, Magna) through the Web Serial API.
Maintainers
Readme
webserial-scale
TypeScript library to read weighing scales (balanças) from the browser through the
Web Serial API. Works in Chromium-based browsers
(Chrome, Edge) over HTTPS or localhost.
Supported scales
| Protocol | Frame / request | Source studied |
| ----------- | ------------------------------------------------------------ | ----------------------------------- |
| toledo | STX 01234 ETX (kg × 1000), live STX 00.250 CR, request 0x05 | OpenAC.Net.Balanca, PesoLib, balance-app |
| filizola | STX 01234 ETX, request 0x05 | OpenAC.Net.Balanca, PesoLib |
| elgin | STX IIIIII ETX (status), STX [ -]00.250 ETX (weight), request 0x05 | PesoLib |
| magna | PESO 1,328 kg\r\n, request P | PesoLib |
| urano | ESC T1/ESC T2 frames (46, 69 and POP 56 bytes), request 0x04 | PesoLib |
Default serial settings for all protocols: 9600 baud, 8 data bits, no parity, 1 stop bit, no flow control.
Not implemented yet: Alfa 3101C. The PesoLib implementation has a buffer copy bug, so it needs a fresh review against the manual in docs/.
Usage
import { WebSerialScale } from "webserial-scale";
const scale = new WebSerialScale({ protocol: "toledo" });
scale.on("reading", (reading) => {
if (reading.status === "stable") {
console.log(`Stable: ${reading.weight} kg`);
} else {
console.log(`Scale status: ${reading.status}`);
}
});
scale.on("error", (error) => console.error(error));
scale.on("disconnect", () => console.log("Scale disconnected"));
// Must run inside a user gesture (e.g. a click handler): shows the browser port picker.
button.addEventListener("click", () => scale.connect());Connect to a port you already have (e.g. one returned by a previous requestPort()):
const port = await WebSerialScale.requestPort();
await scale.connect(port);Options
new WebSerialScale({
protocol: "filizola", // built-in name or a custom ScaleProtocol
serial: { baudRate: 4800 }, // override any serial setting
autoRequest: 250, // ms between weight requests; false = listen only
});autoRequestdefaults to 250 ms for request-driven protocols and is ignored for streaming-only ones. Usefalsefor scales that stream continuously.requestWeight()sends the request once, on demand.
Readings
Each reading has:
status:"stable" | "unstable" | "negative" | "overload"weight: kilograms, ornullwhen the scale sent no value (unstable, negative, overload)unit: always"kg"protocol,raw(the frame bytes),timestamp
Finding scales automatically
findCompatibleScales() probes the ports the user already authorized and returns the ones where a supported scale answered. The UI can list them and let the user pick one:
import { WebSerialScale } from "webserial-scale";
// 1. The user authorizes a port (once per port).
await WebSerialScale.requestPort();
// 2. Probe all authorized ports (takes a few seconds per port).
const found = await WebSerialScale.findCompatible();
// found: [{ port, protocol, serial, readings, sample, usb }, ...]
// 3. Connect to the one the user picked, with the serial settings that worked.
const item = found[0];
const scale = new WebSerialScale({ protocol: item.protocol, serial: item.serial });
await scale.connect(item.port);Each port is opened with every serial configuration of the built-in protocols (for example 9600 8N1 and 9600 8N2), and the weight requests are sent while listening. Only authorized ports are probed, but the probe writes request bytes to them.
Decoding without a browser
FrameDecoder works on any byte stream (for example, data coming from Node's serialport package):
import { FrameDecoder, toledo } from "webserial-scale";
const decoder = new FrameDecoder(toledo);
for (const reading of decoder.push(chunk)) {
console.log(reading.weight);
}Protocol reference
See docs/PROTOCOLS.md for the frames of each scale, which ones send automatically, which need a request, and which need the operator to press a key.
Custom protocols
A protocol is an object with name, serialOptions, an optional requestCommand and a
parseFrame(buffer) function that returns ok (with the frame length), incomplete or invalid.
See src/protocols/ for examples.
Development
npm install
npm run typecheck
npm test
npm run buildTests use the built-in node:test runner and need no browser or hardware.
Testing with a real scale still requires a serial port or a virtual COM pair (e.g. com0com on Windows).
Credits
Protocol behaviour was derived from studying these projects:
Toledo Prix 3 Fit
Prix3Fit is the class for the Toledo Prix 3 Fit: reading in the four weight modes, price per kg, tare and pre-packing.
See docs/PRIX3_FIT.md.
import { Prix3Fit } from "webserial-scale";
const fit = new Prix3Fit({ mode: "prt5" }); // same mode and baud rate as the scale's C14 and C16
await fit.connect(); // inside a user gesture
await fit.setPricePerKg(16.58);
await fit.setTare(360);
const reading = await fit.readWeight();
console.log(reading.weight, reading.status);License
MIT. See LICENSE.
