UNPKG

@danidoble/webserial

Version:
1,377 lines 88.6 kB
import { v as O } from "./webserial-core-Bn6Ker2l.js"; import { D as N } from "./devices-CzEcntFZ.js"; class T { /** * Byte order configuration * - true: Big Endian (high byte first) - Current JSD firmware * - false: Little Endian (low byte first) */ static USE_BIG_ENDIAN = !0; /** * CRC algorithm type * - false: Non-reflected/MSB-first with polynomial 0x8005 - Current JSD firmware * - true: Reflected/LSB-first with polynomial 0xA001 (reflected 0x8005) */ static USE_REFLECTED = !1; /** * Calculate CRC-16 based on configuration flags. * @param bytes - Array of bytes to calculate CRC for. * @returns [firstByte, secondByte] - Order depends on USE_BIG_ENDIAN setting. */ static calculate(e) { let t; if (this.USE_REFLECTED) { t = 0; for (const s of e) { t ^= s & 255; for (let n = 0; n < 8; n++) t & 1 ? t = t >> 1 ^ 40961 : t >>= 1; } } else { t = 0; for (const s of e) { t ^= s << 8; for (let n = 0; n < 8; n++) t & 32768 ? t = (t << 1 ^ 32773) & 65535 : t = t << 1 & 65535; } } return this.USE_BIG_ENDIAN ? [t >> 8 & 255, t & 255] : [t & 255, t >> 8 & 255]; } /** * Get current configuration info (for debugging). * @returns Object containing configuration flags. */ static getConfig() { return { bigEndian: this.USE_BIG_ENDIAN, reflected: this.USE_REFLECTED }; } } class b { /** * Application ID for Vision Machines (Snacks, PPEs, Supplies, Medicines, etc.) * Each Jofemar application has its specific protocol and application number * APP_ID = 402 → Vision * APP_ID = 601 → Manifest & Log of events * @see APP_NO */ _name = "tcpip"; get name() { return this._name; } get packetId() { return 0; } _overridePacketId(e) { console.warn(`TCP/IP transport does not use packet IDs. Ignoring override to ${e}.`); } /** * Convert number to 2 bytes Little Endian. * Example: 10000 → 0x2710 → [0x10, 0x27]. * @param val - Number to convert. * @returns Tuple of two numbers [lowByte, highByte]. */ toLittleEndian(e) { return [e & 255, e >> 8 & 255]; } /** * Build a packet for TCP/IP transport. * @param opcode - Operation code. * @param args - Arguments string. * @param APP_ID - Application ID. * @returns Array of numbers representing the packet. */ buildPacket(e, t, s) { const n = t ? t.split("").map((h) => h.charCodeAt(0)) : [], a = 6 + n.length, i = this.toLittleEndian(a), c = this.toLittleEndian(s), o = this.toLittleEndian(e); return { bytes: [ ...i, // NumBytes (total chain length) ...c, // App ID (402 for Vision) ...o, // Opcode (e.g., 100 for machine status) ...n // Data associated (ASCII args) ], packetId: 0 // TCP/IP doesn't use packet IDs, but we include it for consistency }; } /** * Transparency (Byte Stuffing): 0xC0 -> 0xDB, 0xDC | 0xDB -> 0xDB, 0xDD. * @param bytes - Array of bytes to escape. * @returns Array of escaped bytes. */ escapeBytes(e) { const t = []; for (const s of e) s === 192 ? t.push(219, 220) : s === 219 ? t.push(219, 221) : t.push(s); return t; } /** * Build an Acknowledge (ACK) packet. * @param packetId - Packet ID to acknowledge. * @returns Array of numbers representing the ACK packet. */ buildAckPacket(e) { const n = [192, 2, e], [a, i] = T.calculate(n), c = [2, e, a, i]; return [192, ...this.escapeBytes(c), 192]; } } class k extends b { packetIdCounter = 1; _name = "rs232"; get packetId() { return this.packetIdCounter; } _overridePacketId(e) { this.packetIdCounter = e & 255; } getNextPacketId() { const e = this.packetIdCounter; return this.packetIdCounter = this.packetIdCounter + 1 & 255, this.packetIdCounter === 0 && (this.packetIdCounter = 1), e; } /** * Build a packet for RS232 transport. * @param opcode - Operation code. * @param args - Arguments string. * @param APP_ID - Application ID. * @returns Array of numbers representing the packet. */ buildPacket(e, t, s) { const i = this.getNextPacketId(), { bytes: c } = super.buildPacket(e, t, s), o = [192, 1, i, ...c], [h, d] = T.calculate(o), l = [1, i, ...c, h, d]; return { bytes: [192, ...this.escapeBytes(l), 192], packetId: i }; } } const r = { requestMachineStatus: 100, requestStatusChannel: 101, requestStatusSelection: 102, configureSelectionDispense: 103, addChannelToSelection: 104, requestMachineIdentification: 105, programWorkingTemperature: 106, programWaitingTimings: 107, resetSoldOutChannels: 108, programTimeWaitingAfterPickup: 109, requestJSDVersion: 110, requestFaultMachine: 111, manageJSDDispensingQueue: 112, defineSpecialCharacteristicsSelection: 113, configurePerishableProducts: 114, requestActiveFaults: 115, configureExtendedDispenseStatusData: 116, requestStatusTrayPositioningPhototransistors: 117, dispenseFromChannel: 150, dispenseFromSelection: 151, controlLights: 152, resetFaultsAndSelfTest: 153, performCollectCycle: 154, dispenseFromChannelExtended: 155, restartingTheJSDKnowingThatItIsDangerous: 156, responseFormatCmdWrong: 200, responseMachineStatus: 201, responseStatusChannel: 202, responseStatusSelection: 203, responseDispenseStatus: 204, responseConfigurationSelectionDispense: 205, responseConfigurationChannelsLinkedToSelection: 206, responseMachineIdentification: 207, responseCurrentTemperature: 208, responseReportEventsAlarmsAndFaults: 209, responseNewTimingWaitingForProductCollection: 210, responsePerformingProductCollectionCycle: 211, responseResetMachineSoldOutChannels: 212, responseNewTimingWaitingAfterProductCollection: 213, responseJSDVersion: 214, responseActiveFaults: 215, responseJSDDispensingQueue: 216, responseSpecialCharacteristicsSelection: 217, responsePerishableProducts: 218, responseActiveFaultsList: 219, responseJSDResetStatus: 220, responseExtendedDispenseStatusData: 221, responseTraysPositioningPhototransistorsStatus: 222, jsdErrorLicenseTemporarilyBlocked: 300, jsdErrorLicenseNotActive: 301, jsdErrorCommandNotExecutable: 302 }, C = (p) => Object.keys(r).find((t) => r[t] === p) || "Unknown", f = { VISION: 402, LICENSING: 600, MANIFESTS_AND_LOGS: 601, SIMULATOR_VISION: 1e4 }, L = (p) => [f.VISION, f.SIMULATOR_VISION].includes(p), F = (p) => [f.LICENSING].includes(p), w = (p) => [f.MANIFESTS_AND_LOGS].includes(p); class u { transport; static APP_ID = f.VISION; // Manifest & Logs Application ID constructor(e) { this.transport = e; } /** * Alias to Opcode 100: Connection command (no data). * @param options Object containing the machine index and transport protocol. * @param options.machine Machine index (0-3). * @param options.transport Transport protocol instance to use. * @returns The generated packet as a number array. */ static connection({ transport: e, packetId: t }) { return e._overridePacketId(t || 255), new u(e).requestJSDVersion(); } /** * Opcode 100: Request machine status. * @param options Object containing the machine index. * @param options.machine Machine index (0-3). * @returns The generated packet as a number array. */ requestMachineStatus({ machine: e }) { const t = `${e}`; return this.transport.buildPacket(r.requestMachineStatus, t, u.APP_ID); } /** * Opcode 101: Request status of a specific channel. * @param options Object containing the options. * @param options.machine Machine index (0-3). * @param options.tray Tray number (11-18). * @param options.channel Channel number (0-9). * @returns The generated packet as a number array. */ requestStatusChannel({ machine: e, tray: t, channel: s }) { const n = `${e},${t},${s}`; return this.transport.buildPacket(r.requestStatusChannel, n, u.APP_ID); } /** * Opcode 102: Request status of a specific selection. * @param options Object containing the options. * @param options.selection Selection number (1-240). * @returns The generated packet as a number array. */ requestStatusSelection({ selection: e }) { const t = `${e}`; return this.transport.buildPacket(r.requestStatusSelection, t, u.APP_ID); } /** * Configure dispense parameters for a selection. * @param options Object containing the options. * @param options.selection Selection number (1-240). * @param options.speed Speed of the dispense engine (0-21). * @param options.timePostRun Time post run (0-255). * @returns The generated packet as a number array. */ configureSelectionDispense({ selection: e, speed: t, timePostRun: s }) { const n = `${e},${t},${s}`; return this.transport.buildPacket(r.configureSelectionDispense, n, u.APP_ID); } /** * Get current dispense configuration for a selection. * @param options Object containing the options. * @param options.machine Machine index (0-3). * @returns The generated packet as a number array. */ getSelectionDispenseConfig({ machine: e }) { const t = `${e}`; return this.transport.buildPacket(r.configureSelectionDispense, t, u.APP_ID); } /** * Request to add a channel to a selection. * @param options Object containing the options. * @param options.selection Selection number (1-240). * @param options.machine Machine index (0-3). * @param options.tray Tray number (11-18). * @param options.channel Channel number (0-9). * @returns The generated packet as a number array. */ addChannelToSelection({ selection: e, machine: t, tray: s, channel: n }) { const a = `${e},${t},${s},${n}`; return this.transport.buildPacket(r.addChannelToSelection, a, u.APP_ID); } /** * Get channels linked to a selection. * @param options Object containing the options. * @param options.selection Selection number (1-240). * @returns The generated packet as a number array. */ getChannelsLinkedToSelection({ selection: e }) { const t = `${e}`; return this.transport.buildPacket(r.addChannelToSelection, t, u.APP_ID); } /** * Request machine identification. * @param options Object containing the options. * @param options.machine Machine index (0-3). * @returns The generated packet as a number array. */ requestMachineIdentification({ machine: e }) { const t = `${e}`; return this.transport.buildPacket(r.requestMachineIdentification, t, u.APP_ID); } /** * Format temperature to +05.0 or -03.5 * @param temperature The temperature value to format. * @returns The formatted date string (5 characters). */ formatTemperature(e) { const t = e >= 0 ? "+" : "-", s = Math.abs(e).toFixed(1).padStart(4, "0"); return `${t}${s}`; } /** * Program working temperature. * @param options Object containing the options. * @param options.machine Machine index (0-3). * @param options.temperature The target temperature. * @param options.enable Boolean indicating if the temperature control should be enabled (true) or disabled (false). * @returns The generated packet as a number array. */ programWorkingTemperature({ machine: e, temperature: t, enable: s }) { const n = this.formatTemperature(t), i = `${e},${n},${s ? 1 : 0}`; return this.transport.buildPacket(r.programWorkingTemperature, i, u.APP_ID); } /** * Get working temperature. * @param options Object containing the options. * @param options.machine Machine index (0-3). * @returns The generated packet as a number array. */ getWorkingTemperature({ machine: e }) { const t = `${e}`; return this.transport.buildPacket(r.programWorkingTemperature, t, u.APP_ID); } /** * Program waiting timings. * @param options Object containing the options. * @param options.collectPosition Time for collect position (1-10). * @param options.dispenseManoeuvres Time for dispense manoeuvres (0-65). * @param options.afterPickup Time waiting after pickup (1-255). * @returns The generated packet as a number array. */ programWaitingTimings({ collectPosition: e, dispenseManoeuvres: t, afterPickup: s }) { const n = `${e},${t},${s}`; return this.transport.buildPacket(r.programWaitingTimings, n, u.APP_ID); } /** * Get waiting timings. * @returns The generated packet as a number array. */ getWaitingTimings() { return this.transport.buildPacket(r.programWaitingTimings, "", u.APP_ID); } /** * Reset sold-out status for all channels in a machine. * @param options Object containing the options. * @param options.machine Machine index (0-3). * @returns The generated packet as a number array. */ resetSoldOutChannels({ machine: e }) { const t = `${e}`; return this.transport.buildPacket(r.resetSoldOutChannels, t, u.APP_ID); } /** * Program time waiting after pickup. * @param options Object containing the options. * @param options.time Time in seconds (15-120). * @returns The generated packet as a number array. */ programTimeWaitingAfterPickup({ time: e }) { const t = `${e}`; return this.transport.buildPacket(r.programTimeWaitingAfterPickup, t, u.APP_ID); } /** * Get time waiting after pickup. * @returns The generated packet as a number array. */ getTimeWaitingAfterPickup() { return this.transport.buildPacket(r.programTimeWaitingAfterPickup, "", u.APP_ID); } /** * Opcode 110: Request JSD firmware version. * Data: None. * @returns The generated packet as a number array. */ requestJSDVersion() { return this.transport.buildPacket(r.requestJSDVersion, "", u.APP_ID); } /** * Opcode 111: Request or clear machine faults. * @param options Object containing the options. * @param options.machine Machine index (0-3). * @param options.type Type of operation: 'report-active', 'report-inactive', or 'clear-inactive'. * @returns The generated packet as a number array. */ requestFaultMachine({ machine: e, type: t }) { const n = `${e},${{ "report-active": 0, "report-inactive": 1, "clear-inactive": 2 }[t]}`; return this.transport.buildPacket(r.requestFaultMachine, n, u.APP_ID); } /** * Request report of active faults. * @param machine Machine index (0-3). * @returns The generated packet as a number array. */ requestReportActiveFaults(e) { return this.requestFaultMachine({ machine: e, type: "report-active" }); } /** * Request report of inactive faults. * @param machine Machine index (0-3). * @returns The generated packet as a number array. */ requestReportInactiveFaults(e) { return this.requestFaultMachine({ machine: e, type: "report-inactive" }); } /** * Request to clear inactive faults. * @param machine Machine index (0-3). * @returns The generated packet as a number array. */ requestClearInactiveFaults(e) { return this.requestFaultMachine({ machine: e, type: "clear-inactive" }); } /** * Manage JSD dispensations requested list (product petitions queue). * @param options Object containing the options. * @param options.type Type of operation (0 = Request status, 1 = Clear queue). * @returns The generated packet as a number array. */ manageJSDDispensingQueue({ type: e }) { const t = `${e}`; return this.transport.buildPacket(r.manageJSDDispensingQueue, t, u.APP_ID); } /** * Request JSD dispensing queue status. * @returns The generated packet as a number array. */ requestJSDDispensingQueueStatus() { return this.manageJSDDispensingQueue({ type: 0 }); } /** * Clear JSD dispensing queue. * @returns The generated packet as a number array. */ clearJSDDispensingQueue() { return this.manageJSDDispensingQueue({ type: 1 }); } /** * Define special characteristics for a selection. * @param options Object containing the options. * @param options.selection Selection number (1-240). * @param options.perishable Boolean indicating if the product is perishable. * @param options.fragileOrHeavy Boolean [false=standard, true=fragile/heavy] (if fragileOrHeavy is true, multidispense is disabled). * @param options.typeAdjustElevator Type of elevator adjustment ('lower' | 'upper'). * @param options.timeAdjustElevator Time for elevator adjustment (in ms). * @returns The generated packet as a number array. */ defineSpecialCharacteristicsSelection({ selection: e, perishable: t, fragileOrHeavy: s, typeAdjustElevator: n, timeAdjustElevator: a }) { const d = `${e},${t ? 1 : 0},${s ? 1 : 0},${n === "lower" ? 0 : 1},${a}`; return this.transport.buildPacket(r.defineSpecialCharacteristicsSelection, d, u.APP_ID); } /** * Get special characteristics for a selection. * @param options Object containing the options. * @param options.selection Selection number (1-240). * @returns The generated packet as a number array. */ getSpecialCharacteristicsSelection({ selection: e }) { const t = `${e}`; return this.transport.buildPacket(r.defineSpecialCharacteristicsSelection, t, u.APP_ID); } /** * Configure perishable products settings for a machine. * @param options Object containing the options. * @param options.machine Machine index (0-3). * @param options.enable Boolean indicating whether to enable perishable product settings. * @param options.temperatureLimit Temperature limit. * @param options.minutesToExpiry Minutes to expiry. * @returns The generated packet as a number array. */ configurePerishableProducts({ machine: e, enable: t, temperatureLimit: s, minutesToExpiry: n }) { const a = t ? 1 : 0, i = this.formatTemperature(s), c = `${e},${a},${i},${n}`; return this.transport.buildPacket(r.configurePerishableProducts, c, u.APP_ID); } /** * Request active faults for a machine. * @param options Object containing the options. * @param options.machine Machine index (0-3). * @returns The generated packet as a number array. */ requestActiveFaults({ machine: e }) { const t = `${e}`; return this.transport.buildPacket(r.requestActiveFaults, t, u.APP_ID); } /** * Configure extended dispense status data. * @param options Object containing the options. * @param options.enable Boolean indicating whether to enable extended dispense status data. * @returns The generated packet as a number array. */ configureExtendedDispenseStatusData({ enable: e }) { const s = `${e ? 1 : 0}`; return this.transport.buildPacket(r.configureExtendedDispenseStatusData, s, u.APP_ID); } /** * Get extended dispense status data configuration. * @returns The generated packet as a number array. */ getExtendedDispenseStatusDataConfig() { return this.transport.buildPacket(r.configureExtendedDispenseStatusData, "", u.APP_ID); } /** * Request the status of the tray positioning phototransistors. * @param options Object containing the options. * @param options.machine Machine index (0-3). * @returns The generated packet as a number array. */ requestStatusTrayPositioningPhototransistors({ machine: e }) { const t = `${e}`; return this.transport.buildPacket( r.requestStatusTrayPositioningPhototransistors, t, u.APP_ID ); } /** * Request dispense from channel. * @param options Object containing the options. * @param options.token Token for tracking the request. * @param options.machine Machine index (0-3). * @param options.tray Tray number (11-18). * @param options.channel Channel number (0-9). * @param options.speed Speed of the dispense engine (0-21). * @param options.timePostRun Time post run (0-255). * @returns The generated packet as a number array. */ dispenseFromChannel({ token: e, machine: t, tray: s, channel: n, speed: a, timePostRun: i }) { const c = `${e},${t},${s},${n},${a},${i}`; return this.transport.buildPacket(r.dispenseFromChannel, c, u.APP_ID); } /** * Get dispense status from channel thought token. * @param options Object containing the options. * @param options.token Token for tracking the request. * @returns The generated packet as a number array. */ getDispenseStatusFromChannel({ token: e }) { const t = `${e}`; return this.transport.buildPacket(r.dispenseFromChannel, t, u.APP_ID); } /** * Request dispense from selection. * @param options Object containing the options. * @param options.token Token for tracking the request. * @param options.selection Selection number (1-240). * @returns The generated packet as a number array. */ dispenseFromSelection({ token: e, selection: t }) { const s = `${e},${t}`; return this.transport.buildPacket(r.dispenseFromSelection, s, u.APP_ID); } /** * Get dispense status from selection thought token. * @param options Object containing the options. * @param options.token Token for tracking the request. * @returns The generated packet as a number array. */ getDispenseStatusFromSelection({ token: e }) { const t = `${e}`; return this.transport.buildPacket(r.dispenseFromSelection, t, u.APP_ID); } /** /** * Change lighting status. * @param options Object containing the options. * @param options.machine Machine index (0-3). * @param options.turnOn Boolean indicating whether to turn the lights on (true) or off (false). * @returns The generated packet as a number array. */ controlLights({ machine: e, turnOn: t }) { const n = `${e},${t ? 1 : 0}`; return this.transport.buildPacket(r.controlLights, n, u.APP_ID); } /** /** * Reset faults and perform self-test. * @param options Object containing the options. * @param options.machine Machine index (0-3). * @returns The generated packet as a number array. */ resetFaultsAndSelfTest({ machine: e }) { const t = `${e}`; return this.transport.buildPacket(r.resetFaultsAndSelfTest, t, u.APP_ID); } /** /** * Perform collect cycle. * @param options Object containing the options. * @param options.machine Machine index (0-3). * @returns The generated packet as a number array. */ performCollectCycle({ machine: e }) { const t = `${e}`; return this.transport.buildPacket(r.performCollectCycle, t, u.APP_ID); } /** /** * Request dispense from channel with extended options. * @param options Object containing the extended dispense options. * @param options.token Token for tracking the request. * @param options.machine Machine index (0-3). * @param options.tray Tray number (11-18). * @param options.channel Channel number (0-9). * @param options.speed Speed of the dispense engine (0-21). * @param options.timePostRun Time post run (0-255). * @param options.fragileOrHeavy Boolean indicating if the product is fragile or heavy. * @param options.typeAdjustElevator Type of elevator adjustment ('lower' | 'upper'). * @param options.timeAdjustElevator Time for elevator adjustment (in ms). * @returns The generated packet as a number array. */ dispenseFromChannelExtended({ token: e, machine: t, tray: s, channel: n, speed: a, timePostRun: i, fragileOrHeavy: c, typeAdjustElevator: o, timeAdjustElevator: h }) { const I = `${e},${t},${s},${n},${a},${i},${c ? 1 : 0},${o === "lower" ? 0 : 1},${h}`; return this.transport.buildPacket(r.dispenseFromChannelExtended, I, u.APP_ID); } /** /** * Get dispense status from channel with extended options using a token. * @param options Object containing the options. * @param options.token Token for tracking the request. * @returns The generated packet as a number array. */ getDispenseStatusFromChannelExtended({ token: e }) { const t = `${e}`; return this.transport.buildPacket(r.dispenseFromChannelExtended, t, u.APP_ID); } /** * Request for a complete JSD reset. * VERY IMPORTANT: the JSD will respond with Opcode 220. Once received by the JSD, it will perform a total * reset without taking care of the machine's current situation (manoeuvres, dispenses, etc.). * This must not be used for solving anything and must be used thinking about the possible consequences. * @returns The generated packet as a number array. */ restartingTheJSDKnowingThatItIsDangerous() { return this.transport.buildPacket(r.restartingTheJSDKnowingThatItIsDangerous, "", u.APP_ID); } } function q(p) { if (p.length > 5) throw new Error(`Token must be max 5 characters, got ${p.length}`); return p; } function _() { let p; do { const e = new Uint8Array(2); p = parseInt(crypto.getRandomValues(e).toString().replaceAll(",", "")).toString(36); } while (p.length > 5); return q(p); } const E = { status: "NO-CONNECTED", machineInService: !1, doorOpen: !1, availabilityToDispense: "NOT-AVAILABLE-TO-DISPENSE", hasLightsOn: !1, temperature: "" }; class M { _commands; jsd; APP_ID = f.VISION; _machineStatus = [ { ...E }, { ...E }, { ...E }, { ...E } ]; constructor(e, t) { this._commands = new u(t), this.jsd = e; } _performingChannelAssignment = { enabled: !1, selections: [], currentSelection: 1 }; _dispensingTokens = {}; async send(e, t) { return this.jsd._lastApplicationCode = this.APP_ID, this.jsd._toQueue(e, { alias: t.alias, waitResponse: t.waitResponse || !1, timeout: t.timeout || 500 }); } get cmd() { return this._commands; } _getMachineIndex(e) { return e - 1; } /** * Check if a machine is available to dispense based on its status. * @param options.machine Machine index to check availability for. * @returns True if the machine is available to dispense, false otherwise. */ isAvailableToDispense({ machine: e = 1 } = {}) { const t = this._getMachineIndex(e); return ["ELEVATOR-COLLECTION-POSITION", "AVAILABLE-TO-DISPENSE"].includes( this._machineStatus[t]?.availabilityToDispense || "" ) && this._machineStatus[t]?.machineInService === !0 && this._machineStatus[t]?.doorOpen === !1 && this._machineStatus[t]?.status === "CONNECTED"; } /** * Request machine status. * @param options Object containing the machine index. * @param options.machine Machine index (defaults to 1). * @returns Promise resolving when the command is sent. */ async requestMachineStatus({ machine: e = 1 } = {}) { const t = this._getMachineIndex(e), s = this.cmd.requestMachineStatus({ machine: t }); return await this.send(s, { alias: "requestMachineStatus" }); } _getTrayChannelFromSelection(e) { const t = Math.floor((e - 1) / 10) + 11, s = (e - 1) % 10; return { tray: t, channel: s }; } _getSelectionFromTrayChannel(e, t) { return (e - 11) * 10 + t + 1; } /** * Request status of a specific channel. * @param options Object containing machine and selection. * @param options.machine Machine index. * @param options.selection Selection number (1-81) to derive tray and channel. * @returns Promise resolving when the command is sent. */ async requestStatusChannel({ machine: e, selection: t }) { const s = this._getMachineIndex(e), { tray: n, channel: a } = this._getTrayChannelFromSelection(t), i = this.cmd.requestStatusChannel({ machine: s, tray: n, channel: a }); return await this.send(i, { alias: "requestStatusChannel" }); } /** * Get status of all channels in a machine. * WARNING: This method triggers a sequence of requests for all 80 selections. * @param options Object containing the machine index. * @param options.machine Machine index. * @returns Promise resolving to an array of SelectionStatus objects. */ async assignChannels({ machine: e }) { if (this._performingChannelAssignment.enabled) throw new Error("Channel assignment already in progress"); this._performingChannelAssignment.enabled = !0; for (let t = 1; t <= 80; t++) await this.requestStatusChannel({ machine: e, selection: t }); return new Promise((t) => { const s = setInterval(() => { if (this._performingChannelAssignment.enabled) return; clearInterval(s); const n = this._performingChannelAssignment.selections; this._performingChannelAssignment.selections = [], t(n); }, 200); }); } /** * Request status of a specific selection. * @param options Object containing the selection number. * @param options.selection Selection number (1-240). * @returns Promise resolving when the command is sent. */ async requestStatusSelection({ selection: e }) { const t = this.cmd.requestStatusSelection({ selection: e }); return await this.send(t, { alias: "requestStatusSelection" }); } /** * Configure dispense parameters for a selection. * @param options Object containing selection, speed, and timePostRun. * @param options.selection Selection number. * @param options.speed Dispense speed. * @param options.timePostRun Time post run. * @returns Promise resolving when the command is sent. */ async configureSelectionDispense({ selection: e, speed: t, timePostRun: s }) { const n = this.cmd.configureSelectionDispense({ selection: e, speed: t, timePostRun: s }); return await this.send(n, { alias: "configureSelectionDispense" }); } /** * Get current dispense configuration for a selection. * @param options Object containing the machine index. * @param options.machine Machine index. * @returns Promise resolving when the command is sent. */ async requestSelectionDispenseConfig({ machine: e }) { const t = this._getMachineIndex(e), s = this.cmd.getSelectionDispenseConfig({ machine: t }); return await this.send(s, { alias: "getSelectionDispenseConfig" }); } /** * Add a channel to a selection. * @param options Object containing details for adding a channel. * @param options.selection Selection number. * @param options.machine Machine index. * @param options.tray Tray number. * @param options.channel Channel number. * @returns Promise resolving when the command is sent. */ async configureAddChannelToSelection({ selection: e, machine: t, tray: s, channel: n }) { const a = this._getMachineIndex(t), i = this.cmd.addChannelToSelection({ selection: e, machine: a, tray: s, channel: n }); return await this.send(i, { alias: "addChannelToSelection" }); } /** * Get channels linked to a selection. * @param options Object containing the selection number. * @param options.selection Selection number. * @returns Promise resolving when the command is sent. */ async requestChannelsLinkedToSelection({ selection: e }) { const t = this.cmd.getChannelsLinkedToSelection({ selection: e }); return await this.send(t, { alias: "getChannelsLinkedToSelection" }); } /** * Request machine identification. * @param options Object containing the machine index. * @param options.machine Machine index. * @returns Promise resolving when the command is sent. */ async requestMachineIdentification({ machine: e }) { const t = this._getMachineIndex(e), s = this.cmd.requestMachineIdentification({ machine: t }); return await this.send(s, { alias: "requestMachineIdentification" }); } /** * Program working temperature. * @param options Object containing temperature settings. * @param options.machine Machine index. * @param options.temperature Target temperature. * @param options.enable Enable or disable temperature control. * @returns Promise resolving when the command is sent. */ async configureWorkingTemperature({ machine: e, temperature: t, enable: s }) { const n = this._getMachineIndex(e), a = this.cmd.programWorkingTemperature({ machine: n, temperature: t, enable: s }); return await this.send(a, { alias: "programWorkingTemperature" }); } /** * Get working temperature. * @param options Object containing the machine index. * @param options.machine Machine index. * @returns Promise resolving when the command is sent. */ async requestWorkingTemperature({ machine: e }) { const t = this._getMachineIndex(e), s = this.cmd.getWorkingTemperature({ machine: t }); return await this.send(s, { alias: "getWorkingTemperature" }); } /** * Program waiting timings. * @param options Object containing timing settings. * @param options.collectPosition Time for collect position. * @param options.dispenseManoeuvres Time for dispense manoeuvres. * @param options.afterPickup Time waiting after pickup. * @returns Promise resolving when the command is sent. */ async configureWaitingTimings({ collectPosition: e, dispenseManoeuvres: t, afterPickup: s }) { const n = this.cmd.programWaitingTimings({ collectPosition: e, dispenseManoeuvres: t, afterPickup: s }); return await this.send(n, { alias: "programWaitingTimings" }); } /** * Get waiting timings. * @returns Promise resolving when the command is sent. */ async requestWaitingTimings() { const e = this.cmd.getWaitingTimings(); return await this.send(e, { alias: "getWaitingTimings" }); } /** * Reset sold-out status for all channels in a machine. * @param options Object containing the machine index. * @param options.machine Machine index. * @returns Promise resolving when the command is sent. */ async resetSoldOutChannels({ machine: e }) { const t = this._getMachineIndex(e), s = this.cmd.resetSoldOutChannels({ machine: t }); return await this.send(s, { alias: "resetSoldOutChannels" }); } /** * Reset faults and perform self-test for a machine. * @param options Object containing the machine index. * @param options.machine Machine index. * @returns Promise resolving when the command is sent. */ async resetAllErrors({ machine: e }) { return await Promise.all([ this.clearInactiveFaults({ machine: e }), this.resetSoldOutChannels({ machine: e }), this.resetFaultsAndSelfTest({ machine: e }) ]); } /** * Program time waiting after pickup. * @param options Object containing time setting. * @param options.time Time in seconds. * @returns Promise resolving when the command is sent. */ async configureTimeWaitingAfterPickup({ time: e }) { const t = this.cmd.programTimeWaitingAfterPickup({ time: e }); return await this.send(t, { alias: "programTimeWaitingAfterPickup" }); } /** * Get time waiting after pickup. * @returns Promise resolving when the command is sent. */ async requestTimeWaitingAfterPickup() { const e = this.cmd.getTimeWaitingAfterPickup(); return await this.send(e, { alias: "getTimeWaitingAfterPickup" }); } /** * Request JSD firmware version. * @returns Promise resolving when the command is sent. */ async requestJSDVersion() { const e = this.cmd.requestJSDVersion(); return await this.send(e, { alias: "requestJSDVersion" }); } /** * Request report of active faults. * @param machine Machine index. * @returns Promise resolving when the command is sent. */ async requestReportActiveFaults({ machine: e }) { const t = this._getMachineIndex(e), s = this.cmd.requestReportActiveFaults(t); return await this.send(s, { alias: "requestReportActiveFaults" }); } /** * Request report of inactive faults. * @param machine Machine index. * @returns Promise resolving when the command is sent. */ async requestReportInactiveFaults({ machine: e }) { const t = this._getMachineIndex(e), s = this.cmd.requestReportInactiveFaults(t); return await this.send(s, { alias: "requestReportInactiveFaults" }); } /** * Request to clear inactive faults. * @param machine Machine index. * @returns Promise resolving when the command is sent. */ async clearInactiveFaults({ machine: e }) { const t = this._getMachineIndex(e), s = this.cmd.requestClearInactiveFaults(t); return await this.send(s, { alias: "requestClearInactiveFaults" }); } /** * Request JSD dispensing queue status. * @returns Promise resolving when the command is sent. */ async requestJSDDispensingQueueStatus() { const e = this.cmd.requestJSDDispensingQueueStatus(); return await this.send(e, { alias: "requestJSDDispensingQueueStatus" }); } /** * Clear JSD dispensing queue. * @returns Promise resolving when the command is sent. */ async clearJSDDispensingQueue() { const e = this.cmd.clearJSDDispensingQueue(); return await this.send(e, { alias: "clearJSDDispensingQueue" }); } /** * Define special characteristics for a selection. * @param options Object containing special characteristics. * @param options.selection Selection number. * @param options.perishable Perishable flag. * @param options.fragileOrHeavy Fragile or heavy flag. * @param options.typeAdjustElevator Elevator adjustment type. * @param options.timeAdjustElevator Elevator adjustment time. * @returns Promise resolving when the command is sent. */ async configureSpecialCharacteristicsSelection({ selection: e, perishable: t, fragileOrHeavy: s, typeAdjustElevator: n, timeAdjustElevator: a }) { const i = this.cmd.defineSpecialCharacteristicsSelection({ selection: e, perishable: t, fragileOrHeavy: s, typeAdjustElevator: n, timeAdjustElevator: a }); return await this.send(i, { alias: "defineSpecialCharacteristicsSelection" }); } /** * Get special characteristics for a selection. * @param options Object containing the selection number. * @param options.selection Selection number. * @returns Promise resolving when the command is sent. */ requestSpecialCharacteristicsSelection({ selection: e }) { const t = this.cmd.getSpecialCharacteristicsSelection({ selection: e }); return this.send(t, { alias: "getSpecialCharacteristicsSelection" }); } /** * Configure perishable products settings. * @param options Object containing perishable product settings. * @param options.machine Machine index. * @param options.enable Enable or disable. * @param options.temperatureLimit Temperature limit. * @param options.minutesToExpiry Minutes to expiry. * @returns Promise resolving when the command is sent. */ configurePerishableProducts({ machine: e, enable: t, temperatureLimit: s, minutesToExpiry: n }) { const a = this._getMachineIndex(e), i = this.cmd.configurePerishableProducts({ machine: a, enable: t, temperatureLimit: s, minutesToExpiry: n }); return this.send(i, { alias: "configurePerishableProducts" }); } /** * Request active faults. * @param options Object containing the machine index. * @param options.machine Machine index. * @returns Promise resolving when the command is sent. */ async requestActiveFaults({ machine: e }) { const t = this._getMachineIndex(e), s = this.cmd.requestActiveFaults({ machine: t }); return await this.send(s, { alias: "requestActiveFaults" }); } /** * Configure extended dispense status data. * @param options Object containing enable flag. * @param options.enable Enable extended data. * @returns Promise resolving when the command is sent. */ async configureExtendedDispenseStatusData({ enable: e }) { const t = this.cmd.configureExtendedDispenseStatusData({ enable: e }); return await this.send(t, { alias: "configureExtendedDispenseStatusData" }); } /** * Get extended dispense status data configuration. * @returns Promise resolving when the command is sent. */ async requestExtendedDispenseStatusDataConfig() { const e = this.cmd.getExtendedDispenseStatusDataConfig(); return await this.send(e, { alias: "getExtendedDispenseStatusDataConfig" }); } /** * Request status of tray positioning phototransistors. * @param options Object containing the machine index. * @param options.machine Machine index. * @returns Promise resolving when the command is sent. */ async requestStatusTrayPositioningPhototransistors({ machine: e }) { const t = this._getMachineIndex(e), s = this.cmd.requestStatusTrayPositioningPhototransistors({ machine: t }); return await this.send(s, { alias: "requestStatusTrayPositioningPhototransistors" }); } /** * Dispense from a specific channel. * @param options Object containing dispense details. * @param options.machine Machine index. * @param options.tray Tray number. * @param options.channel Channel number. * @param options.speed Dispense speed. * @param options.timePostRun Time post run. * @param options.cart Cart flag (optional, defaults to false). * @returns Promise resolving when the command is sent. */ async dispenseFromChannel({ machine: e, tray: t, channel: s, speed: n, timePostRun: a, cart: i = !1 }) { if (!this.isAvailableToDispense({ machine: e })) throw new Error(`Machine ${e} is not available to dispense`); const c = this._getMachineIndex(e), o = _(), h = this.cmd.dispenseFromChannel({ token: o, machine: c, tray: t, channel: s, speed: n, timePostRun: a }); return await this.send(h, { alias: "dispenseFromChannel" }), this._dispensingTokens[o] = { cart: !!i, resolve: () => { delete this._dispensingTokens[o]; }, reject: () => { } }, new Promise((d, l) => { this._dispensingTokens[o].resolve = d, this._dispensingTokens[o].reject = l; }); } /** * Dispense from a selection using the channel assignment logic. * @param options Object containing dispense details. * @param options.machine Machine index. * @param options.selection Selection number (1-81). * @param options.speed Dispense speed. * @param options.timePostRun Time post run. * @param options.cart Cart flag (optional, defaults to false). * @returns Promise resolving when the command is sent. */ async dispense({ machine: e, selection: t, speed: s, timePostRun: n, cart: a = !1 }) { const { tray: i, channel: c } = this._getTrayChannelFromSelection(t); return this.dispenseFromChannel({ machine: e, tray: i, channel: c, speed: s || 5, timePostRun: n || 0, cart: !!a }); } /** * Dispense multiple selections in a cart. * WARNING: This method sends dispense commands in batches of 10 and waits for machines to be available before sending the next batch. * @param data Array of objects containing machine and selection details for each dispense command. * @param data.machine Machine index for each dispense command. * @param data.selection Selection number (1-81) for each dispense command. * @returns Promise resolving to an array of objects containing selection and dispense result for each command. */ async dispenseCart(e = []) { const t = []; for (let n = 0; n < e.length; n += 10) t.push(e.slice(n, n + 10)); let s = []; for (const n of t) try { const a = await Promise.all( n.map((o) => this.dispense({ machine: o.machine, selection: o.selection, cart: !0 })) ), i = [...new Set(n.map((o) => o.machine))]; await new Promise((o) => { const h = setInterval(() => { i.every( (l) => this.getMachineStatus(l)?.availabilityToDispense === "AVAILABLE-TO-DISPENSE" ) && (clearInterval(h), o(!0)); }, 300); }); for (const o of i) this._machineStatus[this._getMachineIndex(o)]?.availabilityToDispense === "WAITING-COLLECTION" && this.emit("waiting-collection", { machine: o !== null ? o + 1 : null }); const c = n.map((o, h) => ({ machine: o.machine, selection: o.selection, dispensed: a[h] })); s = s.concat(c); } catch (a) { console.error("Error sending dispense command:", a); } return s; } /** * Get dispense status from channel using a token. * @param options Object containing the token. * @param options.token Dispense token. * @returns Promise resolving when the command is sent. */ async requestDispenseStatusFromChannel({ token: e }) { const t = this.cmd.getDispenseStatusFromChannel({ token: e }); return await this.send(t, { alias: "getDispenseStatusFromChannel" }); } /** * Dispense from a selection. * @param options Object containing selection dispense details. * @param options.selection Selection number. * @param options.cart Cart flag (optional, defaults to false). * @returns Promise resolving when the command is sent. */ async dispenseFromSelection({ selection: e, cart: t = !1 }) { const s = _(), n = this.cmd.dispenseFromSelection({ token: s, selection: e }); return await this.send(n, { alias: "dispenseFromSelection" }), this._dispensingTokens[s] = { cart: !!t, resolve: () => { }, reject: () => { } }, new Promise((a, i) => { this._dispensingTokens[s].resolve = a, this._dispensingTokens[s].reject = i; }); } /** * Get dispense status from selection using a token. * @param options Object containing the token. * @param options.token Dispense token. * @returns Promise resolving when the command is sent. */ async requestDispenseStatusFromSelection({ token: e }) { const t = this.cmd.getDispenseStatusFromSelection({ token: e }); return await this.send(t, { alias: "getDispenseStatusFromSelection" }); } /** * Control lights. * @param options Object containing machine and light status. * @param options.machine Machine index. * @param options.turnOn Turn lights on or off. * @returns Promise resolving when the command is sent. */ async _configureLights({ machine: e, turnOn: t, alias: s }) { const n = this._getMachineIndex(e), a = this.cmd.controlLights({ machine: n, turnOn: t }); return await this.send(a, { alias: s }); } /** * Turn lights on for a machine. * @param options Object containing the machine index. * @param options.machine Machine index. * @returns Promise resolving when the command is sent. */ async lightsOn({ machine: e }) { return this._configureLights({ machine: e, turnOn: !0, alias: "lightsOn" }); } /** * Turn lights off for a machine. * @param options Object containing the machine index. * @param options.machine Machine index. * @returns Promise resolving when the command is sent. */ async lightsOff({ machine: e }) { return this._configureLights({ machine: e, turnOn: !1, alias: "lightsOff" }); } /** * Reset faults and perform self-test. * @param options Object containing the machine index. * @param options.machine Machine index. * @returns Promise resolving when the command is sent. */ async resetFaultsAndSelfTest({ machine: e }) { const t = this._getMachineIndex(e), s = this.cmd.resetFaultsAndSelfTest({ machine: t }); return await this.send(s, { alias: "resetFaultsAndSelfTest" }); } /** * Perform collect cycle. * @param options Object containing the machine index. * @param options.machine Machine index. * @returns Promise resolving when the command is sent. */ async collect({ machine: e }) { const t = this._getMachineIndex(e), s = this.cmd.performCollectCycle({ machine: t }); return await this.send(s, { alias: "performCollectCycle" }); } /** * Dispense from a channel with extended options. * @param options Object containing extended dispense details. * @param options.machine Machine index. * @param options.tray Tray number. * @param options.channel Channel number. * @param options.speed Dispense speed. * @param options.timePostRun Time post run. * @param options.fragileOrHeavy Fragile or heavy flag. * @param options.typeAdjustElevator Elevator adjustment type. * @param options.timeAdjustElevator Elevator adjustment time. * @param options.cart Cart flag (optional, defaults to false). * @returns Promise resolving when the command is sent. */ async dispenseFromChannelExtended({ machine: e, tray: t, channel: s, speed: n, timePostRun: a, fragileOrHeavy: i, typeAdjustElevator: c, timeAdjustElevator: o, cart: h = !1 }) { if (!this.isAvailableToDispense({ machine: e })) throw new Error(`Machine ${e} is not available to dispense`); const d = this._getMachineIndex(e), l = _(), m = this.cmd.dispenseFromChannelExtended({ token: l, machine: d, tray: t, channel: s, speed: n, timePostRun: a, fragileOrHeavy: i, typeAdjustElevator: c, timeAdjustElevator: o }); return await this.send(m, { alias: "dispenseFromChannelExtended" }), this._dispensingTokens[l] = { cart: !!h, resolve: () => { }, reject: () => { } }, new Promise((I, D) => { this._dispensingTokens[l].resolve = I, this._dispensingTokens[l].reject = D; }); } /** * Get dispense status from channel with extended options using a token. * @param options Object containing the token. * @param options.token Dispense token. * @returns Promise resolving when the command is sent. */ async requestDispenseStatusFromChannelExtended({ token: e }) { const t = this.cmd.getDispe