@danidoble/webserial
Version:
WebSerial API wrapper
1,377 lines • 88.6 kB
JavaScript
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