{"_id":"@danidoble/webserial-boardroid","name":"@danidoble/webserial-boardroid","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@danidoble/webserial-boardroid","type":"module","version":"1.0.0","description":"A strongly-typed, event-driven USB boardroid driver for the Web Serial API, built on top of webserial-core.","author":{"name":"Danidoble","email":"ddanidoble@gmail.com"},"license":"GPL-3.0-only","homepage":"https://github.com/danidoble/webserial-boardroid#readme","repository":{"type":"git","url":"git+https://github.com/danidoble/webserial-boardroid.git"},"bugs":{"url":"https://github.com/danidoble/webserial-boardroid/issues"},"exports":{".":{"import":"./dist/index.mjs","require":"./dist/index.cjs"},"./package.json":"./package.json"},"devDependencies":{"@eslint/js":"^10.0.1","@typescript/native-preview":"7.0.0-dev.20260328.1","bumpp":"^11.0.1","eslint":"^10.2.1","globals":"^17.5.0","prettier":"3.8.3","tsdown":"^0.21.10","typescript":"^6.0.3","typescript-eslint":"^8.59.0","vitest":"^4.1.5","webserial-core":"^2.1.0"},"peerDependencies":{"webserial-core":"^2.1.0"},"main":"./dist/index.cjs","module":"./dist/index.mjs","types":"./dist/index.d.cts","scripts":{"build":"tsdown","dev":"prettier --write ./src/**/*.ts && tsdown --watch","test":"vitest","typecheck":"tsc --noEmit","release":"bumpp","lint":"eslint ./src/**/*.ts ./tests/**/*.ts","format":"prettier --write ./src/ ./tests/ ./README.md ./package.json"},"_id":"@danidoble/webserial-boardroid@1.0.0","_integrity":"sha512-naQRWJoc3UEZBYWX2Y6xvVP+sJnEDbLFTf8kWTwtyk4+omTaNTCmLpxED9LJCQfB5cSsB59Wk22PYmhrMwoKzQ==","_resolved":"/tmp/b94606320783e611b0c4b26343cd5dcf/danidoble-webserial-boardroid-1.0.0.tgz","_from":"file:danidoble-webserial-boardroid-1.0.0.tgz","_nodeVersion":"24.12.0","_npmVersion":"11.13.0","dist":{"integrity":"sha512-naQRWJoc3UEZBYWX2Y6xvVP+sJnEDbLFTf8kWTwtyk4+omTaNTCmLpxED9LJCQfB5cSsB59Wk22PYmhrMwoKzQ==","shasum":"d9720f9e172416485418ba308ca1b0e15366269e","tarball":"https://registry.npmjs.org/@danidoble/webserial-boardroid/-/webserial-boardroid-1.0.0.tgz","fileCount":7,"unpackedSize":131123,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCRrEgljzXX3IC0W+N1G3lXre3mpN/v5AtE9B1ObcCTRAIgNXzb9wzAFCjNmLJ33mgK0NFQ4OtI3KBtoKTP64qHc5c="}]},"_npmUser":{"name":"danidoble","email":"ddanidoble@gmail.com"},"directories":{},"maintainers":[{"name":"danidoble","email":"ddanidoble@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/webserial-boardroid_1.0.0_1777219748436_0.45810903186842933"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-26T16:09:08.373Z","1.0.0":"2026-04-26T16:09:08.654Z","modified":"2026-04-26T16:09:08.807Z"},"maintainers":[{"name":"danidoble","email":"ddanidoble@gmail.com"}],"description":"A strongly-typed, event-driven USB boardroid driver for the Web Serial API, built on top of webserial-core.","homepage":"https://github.com/danidoble/webserial-boardroid#readme","repository":{"type":"git","url":"git+https://github.com/danidoble/webserial-boardroid.git"},"author":{"name":"Danidoble","email":"ddanidoble@gmail.com"},"bugs":{"url":"https://github.com/danidoble/webserial-boardroid/issues"},"license":"GPL-3.0-only","readme":"# @danidoble/webserial-boardroid\n\nA strongly-typed, event-driven vending machine controller driver built on top of [`webserial-core`](https://github.com/danidoble/webserial-core).\n\nManages the serial connection, binary handshake, auto-reconnect, and message routing for a full vending machine main board: coin purse (MDB), banknote purse (recycler / ICT), card reader, cooling relay, temperature sensor, door monitor, and product dispensing.\n\nNot tied to a single transport: swap in the **WebUSB**, **Web Bluetooth**, or **WebSocket** provider from `webserial-core`, or implement your own `SerialProvider` for any platform.\n\n[![npm version](https://img.shields.io/npm/v/@danidoble/webserial-boardroid)](https://www.npmjs.com/package/@danidoble/webserial-boardroid)\n[![license](https://img.shields.io/npm/l/@danidoble/webserial-boardroid)](./LICENSE.md)\n\n---\n\n## Requirements\n\n- [`webserial-core`](https://www.npmjs.com/package/webserial-core) `^2.1.0` (peer dependency)\n- A compatible transport (see [Providers](#providers)):\n  - **Web Serial API** — Chrome / Edge 89+ (default, no extra setup)\n  - **WebUSB** — Chrome / Edge (via `WebUsbProvider`)\n  - **Web Bluetooth** — Chrome / Edge (via `createBluetoothProvider`, Nordic UART Service)\n  - **WebSocket** — any environment (via `createWebSocketProvider` + a bridge server)\n  - **Custom** — any platform via your own `SerialProvider` implementation\n\n---\n\n## Installation\n\n```bash\n# npm\nnpm install @danidoble/webserial-boardroid webserial-core\n\n# pnpm\npnpm add @danidoble/webserial-boardroid webserial-core\n\n# yarn\nyarn add @danidoble/webserial-boardroid webserial-core\n\n# bun\nbun add @danidoble/webserial-boardroid webserial-core\n```\n\n> `webserial-core` is a **peer dependency** — it must be installed alongside this package.\n\n---\n\n## Quick start\n\n```ts\nimport { Boardroid } from '@danidoble/webserial-boardroid';\n\nconst boardroid = new Boardroid({ channel: 1, filters: [{ usbVendorId: 0x2341 }] });\n\n// Serial lifecycle\nboardroid.on('serial:connecting',   () => console.log('Opening port…'));\nboardroid.on('serial:connected',    () => console.log('Port open'));\nboardroid.on('serial:disconnected', () => console.log('Disconnected'));\n\n// Boardroid ready\nboardroid.on('boardroid:connected', ({ channel }) => console.log(`Boardroid on channel ${channel} ready`));\n\n// Every device message\nboardroid.on('boardroid:message', (msg) => console.log(`[${msg.no_code}] ${msg.name}`));\n\n// Payment events\nboardroid.on('money:inserted',    ({ type, money }) => console.log(`${type}: ${money.name}`));\nboardroid.on('session:money-request', () => console.log('Money session updated'));\n\n// Product dispense result\nboardroid.on('dispensed', () => console.log('Dispense cycle finished'));\n\n// Door / temperature / relay monitoring\nboardroid.on('event:door',        ({ open }) => console.log('Door', open ? 'open' : 'closed'));\nboardroid.on('status:temperature',({ temperature }) => console.log('Temp:', temperature));\nboardroid.on('status:relay',      ({ enabled }) => console.log('Relay', enabled ? 'on' : 'off'));\n\n// Opens a port picker dialog (requires a user gesture)\nawait boardroid.connect();\n\n// Enable payment purses (coin + banknote)\nawait boardroid.sendPaymentPursesEnable({ coin: true, banknote: true });\n\n// Dispense product on selection 5\nawait boardroid.sendDispense({ selection: 5 });\n\n// Disable payment purses at end of sale\nawait boardroid.sendPaymentPursesDisable();\n\n// Dispense change\nawait boardroid.sendCoinPurseDispense({ $5: 1, $1: 2 });\n\n// Read temperature\nawait boardroid.sendReadTemperature();\n\n// Test all 80 motors sequentially\nconst results = await boardroid.sendTestEngines({ limit: 80 });\nconsole.log(results.filter(r => r.dispensed).length, 'motors OK');\n```\n\n---\n\n## Serial settings\n\nThe constructor pre-configures the following defaults — no extra setup needed:\n\n| Setting            | Value                    |\n| ------------------ | ------------------------ |\n| Baud rate          | 115 200                  |\n| Data bits          | 8                        |\n| Stop bits          | 1                        |\n| Parity             | none                     |\n| Flow control       | none                     |\n| Buffer size        | 255 B                    |\n| Parser             | fixedLength (14 bytes)   |\n| Command timeout    | 5 000 ms                 |\n| Auto-reconnect     | ✓                        |\n| Reconnect interval | 1 500 ms                 |\n| Handshake timeout  | 3 000 ms                 |\n\n---\n\n## Providers\n\nBy default the library uses the browser's native **Web Serial API** (`navigator.serial`). You can replace this with any of the built-in providers from `webserial-core`, or write your own.\n\n### Web Serial API (default)\n\nNo setup required — works out of the box in Chrome / Edge 89+.\n\n```ts\nimport { Boardroid } from '@danidoble/webserial-boardroid';\n\nconst boardroid = new Boardroid({ filters: [{ usbVendorId: 0x2341 }] });\nawait boardroid.connect();\n```\n\n### WebUSB (`WebUsbProvider`)\n\n```ts\nimport { Boardroid, WebUsbProvider } from '@danidoble/webserial-boardroid';\n\nconst boardroid = new Boardroid({\n  filters: [{ usbVendorId: 0x2341 }],\n  provider: new WebUsbProvider()\n});\n\nawait boardroid.connect();\n```\n\n### Web Bluetooth (`createBluetoothProvider`)\n\n```ts\nimport { Boardroid, createBluetoothProvider } from '@danidoble/webserial-boardroid';\n\nconst boardroid = new Boardroid({ provider: createBluetoothProvider() });\nawait boardroid.connect();\n```\n\n### WebSocket (`createWebSocketProvider`)\n\n```ts\nimport { Boardroid, createWebSocketProvider } from '@danidoble/webserial-boardroid';\n\nconst boardroid = new Boardroid({\n  filters: [{ usbVendorId: 0x2341 }],\n  provider: createWebSocketProvider('ws://localhost:8080')\n});\n\nawait boardroid.connect();\n```\n\n### Global provider (`AbstractSerialDevice.setProvider`)\n\n```ts\nimport { AbstractSerialDevice, WebUsbProvider } from 'webserial-core';\nimport { Boardroid } from '@danidoble/webserial-boardroid';\n\nAbstractSerialDevice.setProvider(new WebUsbProvider());\nconst boardroid = new Boardroid({ filters: [{ usbVendorId: 0x2341 }] });\nawait boardroid.connect();\n```\n\n### Custom provider\n\n```ts\nimport type { SerialProvider, SerialPortFilter } from '@danidoble/webserial-boardroid';\nimport { Boardroid } from '@danidoble/webserial-boardroid';\n\nconst myProvider: SerialProvider = {\n  async requestPort(options?: { filters?: SerialPortFilter[] }): Promise<SerialPort> {\n    // return a SerialPort-compatible object\n  },\n  async getPorts(): Promise<SerialPort[]> {\n    // return previously authorised ports\n  }\n};\n\nconst boardroid = new Boardroid({ provider: myProvider });\n```\n\n---\n\n## API\n\n### `new Boardroid(options?)`\n\n| Option            | Type                          | Default | Description                                                  |\n| ----------------- | ----------------------------- | ------- | ------------------------------------------------------------ |\n| `channel`         | `number`                      | `1`     | Channel used in the binary handshake.                        |\n| `filters`         | `SerialPortFilter[]`          | `[]`    | USB vendor/product filters for port matching.                |\n| `provider`        | `SerialProvider`              | —       | Per-instance transport provider.                             |\n| `polyfillOptions` | `SerialDeviceOptions<Uint8Array>` | —    | Extra options forwarded to the underlying device.            |\n\n---\n\n### Connection\n\n#### `boardroid.connect()`\n\nOpens the serial port and performs the binary handshake. Shows a browser port-picker on first connection; subsequent calls reuse the last authorised port.\n\n```ts\nawait boardroid.connect();\n```\n\n#### `boardroid.disconnect()`\n\nGracefully closes the port and stops auto-reconnect.\n\n```ts\nawait boardroid.disconnect();\n```\n\n#### `boardroid.isConnected()`\n\nReturns `true` when the port is open and the handshake has completed.\n\n#### `boardroid.softReload()`\n\nResets the in-memory sale session (price, change, inserted/retired counters) without touching the physical device.\n\n```ts\nboardroid.softReload();\n```\n\n---\n\n### Properties\n\n| Property                 | Type      | R/W | Description                                                                 |\n| ------------------------ | --------- | --- | --------------------------------------------------------------------------- |\n| `totalInTubes`           | `number`  | R   | Total monetary value (in currency units) currently in the coin tubes.       |\n| `totalInRecycler`        | `number`  | R   | Total monetary value currently in the banknote recycler.                    |\n| `hasRecycler`            | `boolean` | R/W | Whether the banknote purse has a recycler unit.                             |\n| `hasICT`                 | `boolean` | R/W | Whether the recycler uses ICT (Innovative Technology) hardware.             |\n| `banknoteICT`            | `number`  | R/W | Active ICT banknote denomination (`20 \\| 50 \\| 100 \\| 200 \\| 500`).         |\n| `hasCoinPurse`           | `boolean` | R/W | Whether a coin purse is physically connected.                               |\n| `price`                  | `number`  | R/W | Current sale price. Negative or NaN values are normalised to `0`.          |\n| `change`                 | `number`  | R   | Calculated change due (`inserted − price`). Returns `0` if no debt.        |\n| `coins`                  | `CoinsInfo` | R | Live snapshot of all coin counters (tubes, box, totals).                   |\n| `banknotes`              | `BanknotesInfo` | R | Live snapshot of all banknote counters (stacker, recycler, out, totals). |\n| `cardReaderAvailable`    | `boolean` | R/W | Whether a card reader is physically connected.                              |\n| `cardReaderMaxPreCredit` | `number`  | R/W | Maximum pre-credit amount allowed for the card reader.                      |\n\n---\n\n### Coin purse\n\n#### `boardroid.sendCoinPurseConfigure(options?)`\n\nSends a full configuration frame to the coin purse.\n\n| Option   | Type      | Default  | Description                    |\n| -------- | --------- | -------- | ------------------------------ |\n| `enable` | `boolean` | `false`  | Enable (`true`) or disable.    |\n| `high`   | `number`  | `0xff`   | High-byte tube limit.          |\n| `low`    | `number`  | `0xff`   | Low-byte tube limit.           |\n\n#### `boardroid.sendCoinPurseEnable()`\n\nShorthand for `sendCoinPurseConfigure({ enable: true })`.\n\n#### `boardroid.sendCoinPurseDisable()`\n\nShorthand for `sendCoinPurseConfigure({ enable: false })`.\n\n#### `boardroid.sendCoinPurseReadTubes()`\n\nRequests the current coin count in each tube. Triggers a `coin-purse:tubes` event.\n\n#### `boardroid.sendCoinPurseDispense(options?)`\n\nDispenses coins from the coin purse.\n\n| Option  | Type     | Default | Description                    |\n| ------- | -------- | ------- | ------------------------------ |\n| `$50c`  | `number` | `0`     | Number of 50-centavo coins.    |\n| `$1`    | `number` | `0`     | Number of $1 coins.            |\n| `$2`    | `number` | `0`     | Number of $2 coins.            |\n| `$5`    | `number` | `0`     | Number of $5 coins.            |\n| `$10`   | `number` | `0`     | Number of $10 coins.           |\n\n```ts\nawait boardroid.sendCoinPurseDispense({ $5: 1, $1: 2 }); // dispense $7 in coins\n```\n\n---\n\n### Banknote purse\n\n#### `boardroid.sendBanknotePurseConfigure(options?)`\n\nSends a configuration frame to the banknote purse. Automatically selects ICT or standard protocol based on `hasICT`.\n\n| Option   | Type      | Default | Description                               |\n| -------- | --------- | ------- | ----------------------------------------- |\n| `enable` | `boolean` | `false` | Enable (`true`) or disable.               |\n| `scrow`  | `boolean` | `false` | Enable scrow mode (manual accept/reject). |\n\n#### `boardroid.sendBanknotePurseEnable(options?)`\n\nShorthand for `sendBanknotePurseConfigure({ enable: true, ... })`.\n\n| Option  | Type      | Default | Description          |\n| ------- | --------- | ------- | -------------------- |\n| `scrow` | `boolean` | `false` | Enable scrow mode.   |\n\n#### `boardroid.sendBanknotePurseDisable()`\n\nShorthand for `sendBanknotePurseConfigure({ enable: false })`.\n\n#### `boardroid.sendBanknotePurseDispense(options?)`\n\nDispenses banknotes from the recycler. Requires `hasRecycler = true`.\n\n| Option   | Type     | Default | Description                  |\n| -------- | -------- | ------- | ---------------------------- |\n| `$20`    | `number` | `0`     | Number of $20 banknotes.     |\n| `$50`    | `number` | `0`     | Number of $50 banknotes.     |\n| `$100`   | `number` | `0`     | Number of $100 banknotes.    |\n| `$200`   | `number` | `0`     | Number of $200 banknotes.    |\n| `$500`   | `number` | `0`     | Number of $500 banknotes.    |\n| `$1000`  | `number` | `0`     | Number of $1000 banknotes.   |\n\n#### `boardroid.sendBanknotePurseAcceptInScrow()`\n\nAccepts (stacks/recycles) a banknote currently held in scrow.\n\n#### `boardroid.sendBanknotePurseRejectInScrow()`\n\nRejects and ejects a banknote currently held in scrow.\n\n#### `boardroid.sendBanknotePurseReadRecycler()`\n\nRequests the current banknote count in the recycler. Triggers a `banknote-purse:recycler` event.\n\n#### `boardroid.sendBanknotePurseSaveMemory(options)`\n\nSaves denomination counts to the banknote purse NVRAM. All fields are required.\n\n| Option    | Type     | Description                   |\n| --------- | -------- | ----------------------------- |\n| `channel` | `number` | Channel number.               |\n| `$20`     | `number` | $20 count to save.            |\n| `$50`     | `number` | $50 count to save.            |\n| `$100`    | `number` | $100 count to save.           |\n| `$200`    | `number` | $200 count to save.           |\n| `$500`    | `number` | $500 count to save.           |\n| `$1000`   | `number` | $1000 count to save.          |\n\n---\n\n### Payment purses (combined)\n\n#### `boardroid.sendPaymentPursesEnable(options?)`\n\nEnables the specified payment peripherals simultaneously.\n\n| Option          | Type      | Default | Description                              |\n| --------------- | --------- | ------- | ---------------------------------------- |\n| `coin`          | `boolean` | `true`  | Enable coin purse.                       |\n| `banknote`      | `boolean` | `true`  | Enable banknote purse.                   |\n| `scrowBanknote` | `boolean` | `false` | Enable scrow mode on the banknote purse. |\n\n#### `boardroid.sendPaymentPursesDisable(options?)`\n\nDisables the specified payment peripherals simultaneously.\n\n| Option       | Type      | Default | Description                   |\n| ------------ | --------- | ------- | ----------------------------- |\n| `coin`       | `boolean` | `true`  | Disable coin purse.           |\n| `banknote`   | `boolean` | `true`  | Disable banknote purse.       |\n| `cardReader` | `boolean` | `false` | Disable card reader.          |\n\n---\n\n### Card reader\n\n#### `boardroid.sendCardReaderDispense(options?)`\n\nInitiates a card reader transaction and dispenses the selected product.\n\n| Option             | Type               | Default | Description                                          |\n| ------------------ | ------------------ | ------- | ---------------------------------------------------- |\n| `selection`        | `number`           | `1`     | Primary product selection (1-based).                 |\n| `second_selection` | `number \\| null`   | `null`  | Secondary selection for combo dispensing.            |\n| `sensor`           | `boolean`          | `true`  | Use optical sensor to detect delivery.               |\n| `seconds`          | `number \\| null`   | `null`  | Motor run time in seconds (0.1–40.0) if no sensor.   |\n| `price`            | `number`           | `0`     | Transaction amount. Must be `> 0`.                   |\n\n#### `boardroid.sendCardReaderDisable()`\n\nDisables the card reader.\n\n---\n\n### Dispense\n\n#### `boardroid.sendDispense(options?)`\n\nTriggers the vending motor for the given product selection.\n\n| Option             | Type             | Default | Description                                          |\n| ------------------ | ---------------- | ------- | ---------------------------------------------------- |\n| `selection`        | `number`         | `1`     | Product selection (1–80).                            |\n| `second_selection` | `number \\| null` | `null`  | Secondary selection (1–80, must differ from first).  |\n| `sensor`           | `boolean`        | `true`  | Use optical sensor to confirm delivery.              |\n| `seconds`          | `number \\| null` | `null`  | Motor run time in seconds (0.1–40.0) if no sensor.   |\n\n```ts\nawait boardroid.sendDispense({ selection: 5 });\n// without sensor — run motor for 2 s\nawait boardroid.sendDispense({ selection: 5, sensor: false, seconds: 2 });\n```\n\n#### `boardroid.sendTestEngines(options?)`\n\nSequentially fires every motor from 1 to `limit`, collects the response for each, and returns an array of `DispenserDispenseResponse`. Emits `percentage:test` after each motor.\n\n| Option  | Type     | Default | Description                           |\n| ------- | -------- | ------- | ------------------------------------- |\n| `limit` | `number` | `80`    | Last motor to test (1-based).         |\n\n```ts\nboardroid.on('percentage:test', ({ percentage }) => console.log(`${percentage}%`));\nconst results = await boardroid.sendTestEngines({ limit: 80 });\n```\n\n---\n\n### Cooling relay\n\n#### `boardroid.sendCoolingRelayConfigure(options?)`\n\n| Option   | Type      | Default | Description          |\n| -------- | --------- | ------- | -------------------- |\n| `enable` | `boolean` | `false` | Turn relay on/off.   |\n\n#### `boardroid.sendCoolingRelayEnable()`\n\nShorthand for `sendCoolingRelayConfigure({ enable: true })`.\n\n#### `boardroid.sendCoolingRelayDisable()`\n\nShorthand for `sendCoolingRelayConfigure({ enable: false })`.\n\n---\n\n### Temperature\n\n#### `boardroid.sendReadTemperature()`\n\nRequests the current cabinet temperature. Triggers a `status:temperature` event.\n\n---\n\n### Custom frame\n\n#### `boardroid.sendCustomCode(options)`\n\nSends a raw byte array directly to the device.\n\n| Option | Type       | Description                    |\n| ------ | ---------- | ------------------------------ |\n| `code` | `number[]` | Raw bytes to send (12 bytes).  |\n\n```ts\nawait boardroid.sendCustomCode({ code: [0xf1, 0xcb, 0, 0, 0, 0, 0, 0, 0, 0, 0xf2, 0x00] });\n```\n\n---\n\n## Events\n\n### Core events (from `webserial-core`)\n\n| Event                    | Payload                           | Description                                       |\n| ------------------------ | --------------------------------- | ------------------------------------------------- |\n| `serial:connecting`      | `instance`                        | Port is being opened.                             |\n| `serial:connected`       | `instance`                        | Port opened successfully.                         |\n| `serial:disconnected`    | `instance`                        | Port closed or device unplugged.                  |\n| `serial:reconnecting`    | `instance`                        | Auto-reconnect attempt in progress.               |\n| `serial:data`            | `data: Uint8Array`, `instance`    | Raw 14-byte frame received from the device.       |\n| `serial:sent`            | `data: Uint8Array`, `instance`    | Raw bytes written to the port.                    |\n| `serial:error`           | `error: Error`, `instance`        | An error occurred during communication.           |\n| `serial:need-permission` | `instance`                        | No authorised port found; user must grant access. |\n| `serial:timeout`         | `command: Uint8Array`, `instance` | A queued command timed out.                       |\n\n### Boardroid events\n\n| Event                              | Payload                                                                                          | Description                                               |\n| ---------------------------------- | ------------------------------------------------------------------------------------------------ | --------------------------------------------------------- |\n| `boardroid:connected`              | `{ channel: number }`                                                                            | Handshake succeeded; device is ready.                     |\n| `boardroid:message`                | `BoardroidMessage`                                                                               | Fired for every recognised device response.               |\n| `boardroid:unknown`                | `BoardroidMessage`                                                                               | Fired for unrecognised response bytes.                    |\n| `run:default-load`                 | `{}`                                                                                             | Fires right after `boardroid:connected`. Load defaults here. |\n| `money:inserted`                   | `{ type: 'coin' \\| 'banknote'; money: MoneyInfo; where: string }`                               | A coin or banknote was inserted.                          |\n| `session:money-request`            | `{}`                                                                                             | Money session totals changed.                             |\n| `session:money-dispensed`          | `{ type_money: string \\| null; retired: number \\| null; finish: boolean; type: string; data?: BoardroidMessage }` | Change or banknote was dispensed. |\n| `dispensed`                        | `{}`                                                                                             | Product dispense cycle completed.                         |\n| `coin-purse:config`                | `{ enabled: boolean }`                                                                           | Coin purse enable/disable confirmed.                      |\n| `coin-purse:tubes`                 | `CoinTubes`                                                                                      | Current coin count per tube denomination.                 |\n| `coin-purse:coin-event`            | `CoinsInfo`                                                                                      | Full coin counter snapshot.                               |\n| `coin-purse:reject-lever`          | `{}`                                                                                             | Reject lever was pressed.                                 |\n| `coin-purse:reset`                 | `{}`                                                                                             | Coin purse was reset.                                     |\n| `banknote-purse:config`            | `{ enabled: boolean; scrow: boolean }`                                                           | Banknote purse enable/scrow confirmed.                    |\n| `banknote-purse:event-banknote`    | `BanknotesInfo`                                                                                  | Full banknote counter snapshot.                           |\n| `banknote-purse:recycler`          | `BanknoteStacker`                                                                                | Current count per recycler denomination.                  |\n| `banknote-purse:banknote-scrow-status` | `{ status: boolean }`                                                                        | Scrow accept/reject result.                               |\n| `banknote-purse:save-memory`       | `{ message: BoardroidMessage }`                                                                  | NVRAM save operation result.                              |\n| `banknote-purse:read-memory`       | `{ message: BoardroidMessage }`                                                                  | NVRAM read operation result.                              |\n| `card-reader:event`                | `BoardroidMessage`                                                                               | Card reader state change (disable, pre-auth, sell, etc.). |\n| `event:door`                       | `{ open: boolean }`                                                                              | Cabinet door opened or closed.                            |\n| `door:event`                       | `{ open: boolean }`                                                                              | Alias for `event:door`.                                   |\n| `status:temperature`               | `{ high: number; low: number; temperature: number }`                                             | Current cabinet temperature (°C).                         |\n| `status:relay`                     | `{ enabled: boolean }`                                                                           | Cooling relay state.                                      |\n| `percentage:test`                  | `{ percentage: number; dispensed: DispenserDispenseResponse[] \\| null }`                        | Progress during `sendTestEngines()`.                      |\n\n#### `BoardroidMessage` — selected `no_code` values\n\n| `no_code`    | Meaning                                               |\n| ------------ | ----------------------------------------------------- |\n| `1`          | Connection handshake completed.                       |\n| `3`          | Coin purse enabled.                                   |\n| `4`          | Coin purse disabled.                                  |\n| `5`          | Banknote purse configured.                            |\n| `6`          | Coin tubes read.                                      |\n| `7`          | Banknote recycler read.                               |\n| `8`          | Banknote scrow status.                                |\n| `9`          | Banknotes dispensed.                                  |\n| `10`         | Coins dispensed.                                      |\n| `11`         | Product not delivered.                                |\n| `12`         | Product delivered.                                    |\n| `13`         | Door closed.                                          |\n| `14`         | Door open.                                            |\n| `15`         | Temperature status.                                   |\n| `16`         | Relay on.                                             |\n| `17`         | Relay off.                                            |\n| `18`         | Banknote NVRAM saved.                                 |\n| `19`         | Banknote NVRAM read.                                  |\n| `20–31`      | Card reader events (code `20 + event_byte`).          |\n| `100`        | Coin reject lever pressed.                            |\n| `101`        | Coin purse reset.                                     |\n| `200`        | Banknote dispensed by ICT recycler.                   |\n| `400`        | Response received but not recognised.                 |\n\n---\n\n## TypeScript\n\nAll events and method signatures are fully typed. The package ships with `.d.mts` / `.d.cts` declaration files — no extra `@types` package required.\n\nCommonly used types and all built-in providers are re-exported so you do not need to import directly from `webserial-core`:\n\n```ts\nimport {\n  Boardroid,\n  WebUsbProvider,\n  createBluetoothProvider,\n  createWebSocketProvider\n} from '@danidoble/webserial-boardroid';\n\nimport type {\n  BoardroidOptions,\n  BoardroidMessage,\n  DispenserDispenseResponse,\n  CommandOptions,\n  CoinPurseConfigureOptions,\n  CoinPurseDispenseOptions,\n  BanknotePurseConfigureOptions,\n  BanknotePurseEnableOptions,\n  BanknotePurseDispenseOptions,\n  BanknotePurseICTConfigureOptions,\n  BanknotePurseICTDispenseOptions,\n  BanknotePurseOtherConfigureOptions,\n  BanknotePurseOtherDispenseOptions,\n  BanknotePurseSaveMemoryOptions,\n  CardReaderDispenseOptions,\n  BoardroidDispenseOptions,\n  CoolingRelayConfigureOptions,\n  PaymentPursesOptions,\n  PaymentPursesEnableOptions,\n  SendCustomCodeOptions,\n  MoneyInfo,\n  CoinTubes,\n  CoinsInfo,\n  BanknoteStacker,\n  BanknotesInfo,\n  DenominationBanknote,\n  SerialPortFilter,\n  SerialDeviceOptions,\n  SerialEventMap,\n  SerialParser,\n  SerialProvider,\n  SerialPolyfillOptions\n} from '@danidoble/webserial-boardroid';\n```\n\n---\n\n## License\n\n[GPL-3.0-only](./LICENSE.md) © [Danidoble](https://github.com/danidoble)\n","readmeFilename":"README.md","_rev":"1-f009e6b347de74529a8dcd14f9ca65a8"}