{"_id":"@danidoble/webserial-jofemar","name":"@danidoble/webserial-jofemar","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@danidoble/webserial-jofemar","type":"module","version":"1.0.0","description":"A strongly-typed, event-driven USB jofemar 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-jofemar#readme","repository":{"type":"git","url":"git+https://github.com/danidoble/webserial-jofemar.git"},"bugs":{"url":"https://github.com/danidoble/webserial-jofemar/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-jofemar@1.0.0","_integrity":"sha512-ZI2tRylimZ0qIlVDG80gIO6JfFiasIm/JzINPP16A1tQ1+thUMcw4figsyqEHbWFY4q9sGatIlVQHDtaYwHyDQ==","_resolved":"/tmp/ef9f9fd15cbac5ec0012a0f09ecc4bee/danidoble-webserial-jofemar-1.0.0.tgz","_from":"file:danidoble-webserial-jofemar-1.0.0.tgz","_nodeVersion":"24.12.0","_npmVersion":"11.13.0","dist":{"integrity":"sha512-ZI2tRylimZ0qIlVDG80gIO6JfFiasIm/JzINPP16A1tQ1+thUMcw4figsyqEHbWFY4q9sGatIlVQHDtaYwHyDQ==","shasum":"264b580979303a10faa4e5756b998692b11461c5","tarball":"https://registry.npmjs.org/@danidoble/webserial-jofemar/-/webserial-jofemar-1.0.0.tgz","fileCount":7,"unpackedSize":171621,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDt25uB9mSBvTfPCKhQ4dbdkhtinrIbIj9evnZjX43OGwIgG3dPWHMgssf/EWZ2eqnxJv8WK3S5r8yQ7yccyYQyix4="}]},"_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-jofemar_1.0.0_1777227091015_0.3838504098757545"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-26T18:11:30.884Z","1.0.0":"2026-04-26T18:11:31.144Z","modified":"2026-04-26T18:11:31.385Z"},"maintainers":[{"name":"danidoble","email":"ddanidoble@gmail.com"}],"description":"A strongly-typed, event-driven USB jofemar driver for the Web Serial API, built on top of webserial-core.","homepage":"https://github.com/danidoble/webserial-jofemar#readme","repository":{"type":"git","url":"git+https://github.com/danidoble/webserial-jofemar.git"},"author":{"name":"Danidoble","email":"ddanidoble@gmail.com"},"bugs":{"url":"https://github.com/danidoble/webserial-jofemar/issues"},"license":"GPL-3.0-only","readme":"# @danidoble/webserial-jofemar\n\nA strongly-typed, event-driven driver for **Jofemar vending machines** (ES-Plus / Ice-Plus) built on top of [`webserial-core`](https://www.npmjs.com/package/webserial-core).\n\nHandles the serial connection, binary handshake, auto-reconnect, and message routing — so you only deal with clean, typed events.\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-jofemar)](https://www.npmjs.com/package/@danidoble/webserial-jofemar)\n[![license](https://img.shields.io/npm/l/@danidoble/webserial-jofemar)](./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-jofemar webserial-core\n\n# pnpm\npnpm add @danidoble/webserial-jofemar webserial-core\n\n# yarn\nyarn add @danidoble/webserial-jofemar webserial-core\n\n# bun\nbun add @danidoble/webserial-jofemar 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 { Jofemar } from '@danidoble/webserial-jofemar';\nimport type { SerialPortFilter } from '@danidoble/webserial-jofemar';\n\nconst filters: SerialPortFilter[] = [{ usbVendorId: 0x0403 }]; // FTDI chip\nconst machine = new Jofemar({ channel: 1, type: 'esplus', filters });\n\nmachine.on('serial:connecting',   () => console.log('Opening port…'));\nmachine.on('serial:connected',    () => console.log('Port open'));\nmachine.on('serial:disconnected', () => console.log('Disconnected'));\n\nmachine.on('jofemar:connected',      ({ channel }) => console.log(`Jofemar on channel ${channel} ready`));\nmachine.on('jofemar:machine-status', (msg)         => console.log(`[${msg.no_code}] ${msg.name}`));\nmachine.on('jofemar:warning',        ({ type })     => console.warn('Warning:', type));\nmachine.on('jofemar:error',          ({ type })     => console.error('Error:', type));\nmachine.on('jofemar:message',        (msg)          => console.log(`[${msg.no_code}] ${msg.name}`));\n\n// Opens a port picker dialog (requires a user gesture)\nawait machine.connect();\n\n// Dispense selection 5 (returns DispenseResult)\nconst result = await machine.sendDispense({ selection: 5 });\nconsole.log(result.status);  // true | false\nconsole.log(result.error);   // null | 'not-dispensed' | 'elevator-locked' | 'no-response' | 'send-failed'\n\n// Check machine status\nawait machine.sendStatus();\n\n// Collect the dispensed product\nawait machine.sendCollect();\n\n// Reset errors\nawait machine.sendResetAll();\n\n// Scan channels 1–80 for presence\nmachine.startChannelVerification = 1;\nmachine.endChannelVerification   = 80;\nconst channels = await machine.sendAssignChannels();\nconsole.log(channels); // [{ selection: 1, active: true }, ...]\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            | 9600                     |\n| Data bits            | 8                        |\n| Stop bits            | 1                        |\n| Parity               | none                     |\n| Flow control         | none                     |\n| Buffer size          | 255 B                    |\n| Parser               | interByteTimeout (40 ms) |\n| Command timeout      | 4 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 { Jofemar } from '@danidoble/webserial-jofemar';\n\nconst machine = new Jofemar({ filters: [{ usbVendorId: 0x0403 }] });\nawait machine.connect();\n```\n\n### WebUSB (`WebUsbProvider`)\n\n```ts\nimport { Jofemar, WebUsbProvider } from '@danidoble/webserial-jofemar';\n\nconst machine = new Jofemar({\n  filters: [{ usbVendorId: 0x0403 }],\n  provider: new WebUsbProvider(),\n});\nawait machine.connect();\n```\n\n### Web Bluetooth (`createBluetoothProvider`)\n\n```ts\nimport { Jofemar, createBluetoothProvider } from '@danidoble/webserial-jofemar';\n\nconst machine = new Jofemar({ provider: createBluetoothProvider() });\nawait machine.connect();\n```\n\n### WebSocket (`createWebSocketProvider`)\n\n```ts\nimport { Jofemar, createWebSocketProvider } from '@danidoble/webserial-jofemar';\n\nconst machine = new Jofemar({\n  filters: [{ usbVendorId: 0x0403 }],\n  provider: createWebSocketProvider('ws://localhost:8080'),\n});\nawait machine.connect();\n```\n\n### Global provider (`AbstractSerialDevice.setProvider`)\n\n```ts\nimport { AbstractSerialDevice, WebUsbProvider } from 'webserial-core';\nimport { Jofemar } from '@danidoble/webserial-jofemar';\n\nAbstractSerialDevice.setProvider(new WebUsbProvider());\nconst machine = new Jofemar({ filters: [{ usbVendorId: 0x0403 }] });\nawait machine.connect();\n```\n\n### Custom provider\n\n```ts\nimport type { SerialProvider, SerialPortFilter } from '@danidoble/webserial-jofemar';\nimport { Jofemar } from '@danidoble/webserial-jofemar';\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 machine = new Jofemar({ filters: [{ usbVendorId: 0x0403 }], provider: myProvider });\n```\n\n---\n\n## API\n\n### `new Jofemar(options?)`\n\n| Option            | Type                  | Default     | Description                                                        |\n| ----------------- | --------------------- | ----------- | ------------------------------------------------------------------ |\n| `channel`         | `number`              | `1`         | Machine address used in the handshake and all outbound commands.   |\n| `type`            | `DeviceType`          | `'esplus'`  | Machine model. Affects temperature limits and reset duration.      |\n| `supportCart`     | `boolean`             | `true`      | Whether the machine has a cart (affects dispense command byte).    |\n| `filters`         | `SerialPortFilter[]`  | `[]`        | USB vendor/product filters for port matching.                      |\n| `provider`        | `SerialProvider`      | —           | Per-instance provider. Overrides the global static provider.       |\n| `polyfillOptions` | `SerialDeviceOptions` | —           | Extra options forwarded to the underlying core device.             |\n\n### Getters and setters\n\n| Name                        | Type                   | R/W | Notes                                     |\n| --------------------------- | ---------------------- | --- | ----------------------------------------- |\n| `isDispensing`              | `boolean`              | R   | `true` while a dispense is in flight.     |\n| `isDoorOpen`                | `boolean`              | R   | Updated from door-event frames.           |\n| `deviceType`                | `DeviceType`           | R/W | `'esplus'` \\| `'iceplus'`                 |\n| `supportCart`               | `boolean`              | R/W | —                                         |\n| `listenOnChannel`           | `number`               | R/W | Valid range: 1–31. Throws on invalid.     |\n| `startChannelVerification`  | `number \\| string`     | W   | Valid range: 1–126. Throws on invalid.    |\n| `endChannelVerification`    | `number \\| string`     | W   | Valid range: 1–126. Throws on invalid.    |\n\n---\n\n### Connection\n\n#### `jofemar.connect()`\n\nOpens the serial port and performs the handshake. Shows a browser port-picker dialog on first use.\n\n#### `jofemar.disconnect()`\n\nGracefully closes the port and stops auto-reconnect.\n\n---\n\n### Dispense\n\n#### `jofemar.sendDispense(options?)`\n\nDispenses the product at the given selection. Automatically retries on `elevator-locked` or `no-response`.\n\n| Option      | Type               | Default | Description                                              |\n| ----------- | ------------------ | ------- | -------------------------------------------------------- |\n| `selection` | `number \\| string` | `1`     | Channel selection (1–130).                               |\n| `cart`      | `boolean`          | `false` | Use the cart-dispense command byte instead of standard.  |\n\nReturns `Promise<DispenseResult>`.\n\n```ts\nconst result = await machine.sendDispense({ selection: 3, cart: false });\n// { status: true, error: null }\n// { status: false, error: 'not-dispensed' | 'elevator-locked' | 'no-response' | 'send-failed' }\n```\n\n#### `jofemar.sendProductRemoved()`\n\nSignals that the product from the elevator has been physically removed, immediately ending the withdrawal wait.\n\n---\n\n### Status and collect\n\n| Method                | Returns        | Description                                        |\n| --------------------- | -------------- | -------------------------------------------------- |\n| `sendStatus()`        | `Promise<void>` | Request machine status. Triggers `jofemar:machine-status`. |\n| `sendCollect()`       | `Promise<void>` | Signal that the dispensed product has been collected. |\n| `sendEndDispense()`   | `Promise<void>` | End a cart-mode dispense cycle.                    |\n\n---\n\n### Reset\n\n| Method                          | Returns        | Description                                                          |\n| ------------------------------- | -------------- | -------------------------------------------------------------------- |\n| `sendResetSoldOut()`            | `Promise<void>` | Reset sold-out errors.                                               |\n| `sendResetWaitingProduct()`     | `Promise<void>` | Reset waiting-product errors.                                        |\n| `sendResetMachine()`            | `Promise<void>` | Full machine reset. Emits `jofemar:reset-errors`. 25 s (ES-Plus) / 40 s (Ice-Plus). |\n| `sendResetAll()`                | `Promise<void>` | Runs `sendResetWaitingProduct` → `sendResetSoldOut` → `sendResetMachine` in sequence. |\n\n---\n\n### Lights\n\n| Method              | Returns        | Description          |\n| ------------------- | -------------- | -------------------- |\n| `sendLightsOn()`    | `Promise<void>` | Turn interior lights on.  |\n| `sendLightsOff()`   | `Promise<void>` | Turn interior lights off. |\n\n---\n\n### Program (write settings)\n\n| Method                                                   | Parameters                                    | Description                              |\n| -------------------------------------------------------- | --------------------------------------------- | ---------------------------------------- |\n| `sendProgram(param1, param2)`                            | `param1: number`, `param2: number`            | Send a raw program command.              |\n| `sendProgramDisplayLanguage({ language? })`              | `'spanish' \\| 'english' \\| 'french'`          | Set display language.                    |\n| `sendProgramBeeper({ enable? })`                         | `enable: boolean` (default `true`)            | Enable/disable beeper.                   |\n| `sendProgramDisableWorkingTemperature()`                 | —                                             | Disable working temperature control (ES-Plus only). |\n| `sendProgramDisableThermometer()`                        | —                                             | Alias for disable working temperature.   |\n| `sendProgramWorkingTemperature({ degrees? })`            | `degrees: number` (multiple of 0.5)           | Set working temperature.                 |\n| `sendProgramIsolationTray({ tray? })`                    | `tray: number` (0–12)                         | Set isolation tray number (0 = none).    |\n| `sendProgramStandbyAfterCollect({ seconds? })`           | `seconds: number` (15–120)                    | Time to standby after product collection. |\n| `sendProgramStandbyWithoutCollect({ minutes? })`         | `minutes: number`                             | Time to standby when product is not collected. |\n| `sendProgramElevatorSpeed({ speed? })`                   | `'high' \\| 'low'`                             | Set elevator speed.                      |\n| `sendProgramTemperatureExpiration({ enable? })`          | `enable: boolean` (default `false`)           | Enable/disable temperature expiration.   |\n| `sendProgramEnableTemperatureExpiration()`               | —                                             | Enable temperature expiration.           |\n| `sendProgramDisableTemperatureExpiration()`              | —                                             | Disable temperature expiration.          |\n| `sendProgramMachineAddress({ address? })`                | `address: number` (default `1`)               | Assign machine channel address.          |\n| `sendProgramTemperatureBeforeExpiration({ degrees? })`   | `degrees: number`                             | Set temperature threshold before expiration. |\n| `sendProgramTimeBeforeExpiration({ minutes? })`          | `minutes: number` (default `1`)               | Time before expiration by temperature.   |\n| `sendProgramTemperatureScale({ scale? })`                | `'celsius' \\| 'fahrenheit'`                   | Set temperature display scale.           |\n| `sendProgramVoltageEngine({ selection?, voltage? })`     | `selection: number`, `voltage: number`        | Set engine voltage for a channel.        |\n| `sendProgramPushOverProducts({ selection?, enable? })`   | `selection: number`, `enable: boolean`        | Enable/disable push-over for a channel.  |\n| `sendProgramChannelRunningAfterDispense({ selection?, seconds? })` | `selection: number`, `seconds: number` | Set channel run time after dispense. |\n| `sendProgramClock({ date? })`                            | `date: Date` (default `new Date()`)           | Synchronise the machine clock.           |\n\n---\n\n### Get / Check (read settings)\n\nAll methods return `Promise<void>` and deliver their response via the corresponding `jofemar:check-*` event.\n\n| Method                                        | Response event                             |\n| --------------------------------------------- | ------------------------------------------ |\n| `sendCheckData(type, aux?)`                   | depends on `type`                          |\n| `sendGetDisplayLanguage()`                    | `jofemar:check-language`                   |\n| `sendGetBeeper()`                             | `jofemar:check-beeper`                     |\n| `sendGetWorkingTemperature()`                 | `jofemar:temperature-working`              |\n| `sendGetIsolationTray()`                      | `jofemar:check-isolation-tray`             |\n| `sendGetProgramVersion()`                     | `jofemar:program-version`                  |\n| `sendGetFaults()`                             | `jofemar:machine-faults`                   |\n| `sendGetMachineId()`                          | `jofemar:check-machine-id`                 |\n| `sendGetCurrentTemperature()`                 | `jofemar:temperature-current`              |\n| `sendGetStandbyAfterCollect()`                | `jofemar:check-standby-after-collect`      |\n| `sendGetStandbyWithoutCollect()`              | `jofemar:check-standby-without-collect`    |\n| `sendGetElevatorSpeed()`                      | `jofemar:check-elevator-speed`             |\n| `sendGetTemperatureExpiration()`              | `jofemar:check-expiration-by-temperature`  |\n| `sendGetTemperatureBeforeExpiration()`        | `jofemar:check-temperature-before-expiration` |\n| `sendGetTimeBeforeExpiration()`               | `jofemar:check-expiration-after`           |\n| `sendGetTemperatureScale()`                   | `jofemar:check-temperature-scale`          |\n| `sendGetClockRegisters()`                     | `jofemar:clock-registers`                  |\n| `sendGetMachineActivity()`                    | `jofemar:machine-activity`                 |\n| `sendGetVoltageEngine({ selection? })`        | `jofemar:check-engine-voltage`             |\n| `sendGetChannelPresence({ selection? })`      | `jofemar:channel-status`                   |\n| `sendGetPushOverProducts({ selection? })`     | `jofemar:check-push-over`                  |\n| `sendGetChannelRunningAfterDispense({ selection? })` | `jofemar:check-extractor-after-dispense` |\n\n---\n\n### Display\n\n| Method                                                    | Parameters                                         | Description                                 |\n| --------------------------------------------------------- | -------------------------------------------------- | ------------------------------------------- |\n| `sendSetDisplayStandbyMessage({ message? })`              | `message: string` (max 32 chars)                   | Set the idle/standby screen message.        |\n| `sendSetDisplayMessageTemporarily({ message?, seconds? })` | `message: string`, `seconds: number` (default `1`) | Show a message for the given number of seconds. |\n| `sendSetDisplayMessageUnlimited({ message? })`            | `message: string` (max 32 chars)                   | Show a message indefinitely.                |\n\n---\n\n### Events config\n\n| Method                                          | Parameters                                              | Description                     |\n| ----------------------------------------------- | ------------------------------------------------------- | ------------------------------- |\n| `sendEventsConfig({ event?, enable? })`         | `event: number \\| string \\| null`, `enable: boolean`    | Configure an automatic event.   |\n| `sendEventEnable({ event? })`                   | `event: number \\| string \\| null`                       | Enable an automatic event.      |\n| `sendEventDisable({ event? })`                  | `event: number \\| string \\| null`                       | Disable an automatic event.     |\n\n---\n\n### Custom code\n\n```ts\nawait machine.sendCustomCode({ code: [0x02, 0x30, 0x30, 0x81, 0x53, 0xff, 0xff] });\n```\n\n---\n\n### Channel verification\n\nScans a range of selections for product presence. Configure the range with the `startChannelVerification` and `endChannelVerification` setters before calling.\n\n```ts\nmachine.startChannelVerification = 1;\nmachine.endChannelVerification   = 80;\n\nmachine.on('jofemar:channels-progress', ({ percentage }) => console.log(`${percentage}%`));\nmachine.on('jofemar:channels',          ({ channels })   => console.log(channels));\n\nconst channels = await machine.sendAssignChannels();\n// [{ selection: 1, active: true }, { selection: 2, active: false }, ...]\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 binary 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### Jofemar events\n\n| Event                                    | Payload                              | Description                                             |\n| ---------------------------------------- | ------------------------------------ | ------------------------------------------------------- |\n| `jofemar:connected`                      | `{ channel: number }`                | Handshake succeeded; machine is ready.                  |\n| `jofemar:message`                        | `MessageSerial`                      | Every parsed frame emits this.                          |\n| `jofemar:machine-status`                 | `MessageSerial`                      | Status response (no_code 8–37).                         |\n| `jofemar:command-executed`               | `MessageSerial`                      | The last sent command was acknowledged by the machine.  |\n| `jofemar:warning`                        | `JofemarWarningPayload`              | Non-fatal condition (empty channel, thermometer, etc.). |\n| `jofemar:error`                          | `JofemarErrorPayload`                | Hardware error (jam, malfunction, EEPROM, etc.).        |\n| `jofemar:door-event`                     | `JofemarDoorEventPayload`            | Door opened or closed.                                  |\n| `jofemar:keyboard-pressed`               | `MessageSerialAdditional`            | A key was pressed on the machine's keypad.              |\n| `jofemar:channel-status`                 | `JofemarChannelStatusPayload`        | Single-channel presence/availability response.          |\n| `jofemar:program-version`                | `MessageSerialAdditional`            | Response to `sendGetProgramVersion()`.                  |\n| `jofemar:machine-faults`                 | `MessageSerialAdditional`            | Response to `sendGetFaults()`.                          |\n| `jofemar:clock-registers`                | `MessageSerialAdditional`            | Response to `sendGetClockRegisters()`.                  |\n| `jofemar:machine-activity`               | `MessageSerialAdditional`            | Response to `sendGetMachineActivity()`.                 |\n| `jofemar:temperature-working`            | `MessageSerialAdditional`            | Response to `sendGetWorkingTemperature()`.              |\n| `jofemar:temperature-current`            | `MessageSerialAdditional`            | Response to `sendGetCurrentTemperature()`.              |\n| `jofemar:check-language`                 | `MessageSerialAdditional`            | Response to `sendGetDisplayLanguage()`.                 |\n| `jofemar:check-beeper`                   | `MessageSerialAdditional`            | Response to `sendGetBeeper()`.                          |\n| `jofemar:check-isolation-tray`           | `MessageSerialAdditional`            | Response to `sendGetIsolationTray()`.                   |\n| `jofemar:check-engine-voltage`           | `MessageSerialAdditional`            | Response to `sendGetVoltageEngine()`.                   |\n| `jofemar:check-push-over`                | `MessageSerialAdditional`            | Response to `sendGetPushOverProducts()`.                |\n| `jofemar:check-extractor-after-dispense` | `MessageSerialAdditional`            | Response to `sendGetChannelRunningAfterDispense()`.     |\n| `jofemar:check-standby-after-collect`    | `MessageSerialAdditional`            | Response to `sendGetStandbyAfterCollect()`.             |\n| `jofemar:check-standby-without-collect`  | `MessageSerialAdditional`            | Response to `sendGetStandbyWithoutCollect()`.           |\n| `jofemar:check-elevator-speed`           | `MessageSerialAdditional`            | Response to `sendGetElevatorSpeed()`.                   |\n| `jofemar:check-expiration-by-temperature`| `MessageSerialAdditional`            | Response to `sendGetTemperatureExpiration()`.           |\n| `jofemar:check-temperature-before-expiration` | `MessageSerialAdditional`       | Response to `sendGetTemperatureBeforeExpiration()`.     |\n| `jofemar:check-expiration-after`         | `MessageSerialAdditional`            | Response to `sendGetTimeBeforeExpiration()`.            |\n| `jofemar:check-temperature-scale`        | `MessageSerialAdditional`            | Response to `sendGetTemperatureScale()`.                |\n| `jofemar:check-machine-id`               | `MessageSerialAdditional`            | Response to `sendGetMachineId()`.                       |\n| `jofemar:reset-errors`                   | `JofemarResetErrorsPayload`          | Emitted immediately when `sendResetMachine()` is called. |\n| `jofemar:channels`                       | `JofemarChannelsPayload`             | Final result of `sendAssignChannels()`.                 |\n| `jofemar:channels-progress`              | `JofemarChannelsProgressPayload`     | Progress updates during `sendAssignChannels()`.         |\n| `jofemar:dispensing-withdrawal`          | `JofemarDispensingWithdrawalPayload` | Emitted every second while waiting for elevator clearance. |\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 needed.\n\nProviders and commonly used types are re-exported so you rarely need to import directly from `webserial-core`:\n\n```ts\nimport { Jofemar, WebUsbProvider, createBluetoothProvider, createWebSocketProvider } from '@danidoble/webserial-jofemar';\n\nimport type {\n  DeviceType,\n  JofemarOptions,\n  DispenseOptions,\n  DispenseResult,\n  MessageSerial,\n  MessageSerialAdditional,\n  JofemarConnectedPayload,\n  JofemarWarningPayload,\n  JofemarErrorPayload,\n  JofemarDoorEventPayload,\n  JofemarChannelStatusPayload,\n  JofemarChannelsPayload,\n  JofemarChannelsProgressPayload,\n  JofemarDispensingWithdrawalPayload,\n  JofemarResetErrorsPayload,\n  SerialPortFilter,\n  SerialDeviceOptions,\n  SerialProvider,\n} from '@danidoble/webserial-jofemar';\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-88b145bedbadb2e75d3a30a0a0403bc0"}