Skip to main content

Listeners

Here is the angular stone of Webserial, the listeners. With them, you can listen to the events that the device emits.

How to listen to an event

When you create a new instance of the Jofemar class, you can listen to the events that the device emits.

machine.on('serial:message', (data) => {
console.log(data);
});

Each event has a different data structure, so you need to check the data structure for each event.

Note

All events will return SerialEvent as shown in the image below.

Locale Dropdown

Get all available listeners

For jofemar class there events that you can listen to, of course only listen to the events that you need.

Object

To get all the available listeners, you can use the availableListeners property.

console.log(machine.availableListeners);

The result will be an object with the available listeners, and if you are listen each event

[
{
"type": "channel:status",
"listening": false
},
{
"type": "channels",
"listening": false
},
{
"type": "check:beeper",
"listening": false
},
{
"type": "check:elevator-speed",
"listening": false
},
{
"type": "check:engine-voltage",
"listening": false
},
{
"type": "check:expiration-after",
"listening": false
},
{
"type": "check:expiration-by-temperature",
"listening": false
},
{
"type": "check:extractor-after-dispense",
"listening": false
},
{
"type": "check:isolation-tray",
"listening": false
},
{
"type": "check:language",
"listening": false
},
{
"type": "check:machine-id",
"listening": false
},
{
"type": "check:push-over",
"listening": false
},
{
"type": "check:standby-after-collect",
"listening": false
},
{
"type": "check:standby-without-collect",
"listening": false
},
{
"type": "check:temperature-before-expiration",
"listening": false
},
{
"type": "check:temperature-scale",
"listening": false
},
{
"type": "clock:registers",
"listening": false
},
{
"type": "dispensed",
"listening": false
},
{
"type": "dispensing",
"listening": false
},
{
"type": "dispensing:withdrawal",
"listening": false
},
{
"type": "door:event",
"listening": false
},
{
"type": "jofemar:error",
"listening": false
},
{
"type": "jofemar:warning",
"listening": false
},
{
"type": "keyboard:pressed",
"listening": false
},
{
"type": "machine:activity",
"listening": false
},
{
"type": "machine:faults",
"listening": false
},
{
"type": "not-dispensed",
"listening": false
},
{
"type": "program:version",
"listening": false
},
{
"type": "reset:errors",
"listening": false
},
{
"type": "command-executed",
"listening": false
},
{
"type": "serial:connected",
"listening": false
},
{
"type": "serial:connecting",
"listening": false
},
{
"type": "serial:disconnected",
"listening": false
},
{
"type": "serial:error",
"listening": false
},
{
"type": "serial:lost",
"listening": false
},
{
"type": "serial:message",
"listening": true
},
{
"type": "serial:need-permission",
"listening": false
},
{
"type": "serial:reconnect",
"listening": false
},
{
"type": "serial:sent",
"listening": false
},
{
"type": "serial:soft-reload",
"listening": false
},
{
"type": "serial:timeout",
"listening": false
},
{
"type": "serial:unsupported",
"listening": false
},
{
"type": "temperature:current",
"listening": false
},
{
"type": "temperature:working",
"listening": false
},
{
"type": "machine:status",
"listening": false
},
{
"type": "unknown",
"listening": false
},
{
"type": "corrupt:message",
"listening": false
}
]

Array

But sometimes you don't want the object you want only an array with the available listeners, you can do this:

machine.availableListeners.map(el => el.type)

And one more time here is the result

[
"channel:status",
"channels",
"check:beeper",
"check:elevator-speed",
"check:engine-voltage",
"check:expiration-after",
"check:expiration-by-temperature",
"check:extractor-after-dispense",
"check:isolation-tray",
"check:language",
"check:machine-id",
"check:push-over",
"check:standby-after-collect",
"check:standby-without-collect",
"check:temperature-before-expiration",
"check:temperature-scale",
"clock:registers",
"dispensed",
"dispensing",
"dispensing:withdrawal",
"door:event",
"jofemar:error",
"jofemar:warning",
"keyboard:pressed",
"machine:activity",
"machine:faults",
"not-dispensed",
"program:version",
"reset:errors",
"command-executed",
"serial:connected",
"serial:connecting",
"serial:disconnected",
"serial:error",
"serial:lost",
"serial:message",
"serial:need-permission",
"serial:reconnect",
"serial:sent",
"serial:soft-reload",
"serial:timeout",
"serial:unsupported",
"temperature:current",
"temperature:working",
"machine:status",
"unknown",
"corrupt:message"
]

Serial connected

When the serial is connected, this event is dispatched.

machine.on('serial:connected', event => {
console.log(event.detail);
});

Serial connecting

When the serial is trying to connect, this event is dispatched.

machine.on('serial:connecting', event => {
// without data
});

Serial disconnected

When the serial is disconnected, this event is dispatched.

machine.on('serial:disconnected', event => {
console.log(event.detail);
});

Serial error

When the serial has an error, this event is dispatched.

machine.on('serial:error', event => {
console.log(event.detail);
});

Serial lost

When the serial is lost, this event is dispatched.

machine.on('serial:lost', event => {
console.log(event.detail);
});

Serial message

When the serial receives a message, this event is dispatched.

Note

This event is dispatched along others events that send event of machine, so this event is only for debug.

machine.on('serial:message', event => {
console.log(event.detail);
});

Serial need permission

When the serial needs permission, this event is dispatched. This occurs because user interaction is needed to request the serial.

Recommendation: Use a button or a screen to show what is happening.

machine.on('serial:need-permission', event => {
console.log(event.detail);
});

Serial reconnect

When the serial is trying to reconnect, this event is dispatched.

machine.on('serial:reconnect', event => {
// without data
});

Serial sent

When the serial sends a message to machine, this event is dispatched.

Note

This event is more oriented for debug.

machine.on('serial:sent', event => {
console.log(event.detail);
});
structure event.detail
{
"event": "string",
"bytes": []
}

Serial soft reload

When the serial is trying to soft reload, this event is dispatched.

machine.on('serial:soft-reload', event => {
// without data
});

Serial timeout

When the serial has a timeout, this event is dispatched.

machine.on('serial:timeout', event => {
console.log(event.detail);
});

Serial unsupported

When the serial is unsupported, this event is dispatched.

machine.on('serial:unsupported', event => {
console.log(event.detail);
});

Channel status

This event is dispatched when you request the status of the channel.

machine.on('channel:status', event => {
console.log(event.detail.active);
});

Channels

When you run assignChannels method, the device will emit the channels event when finish the process.

machine.on('channels', event => {
console.log(event.detail.channels);
});
// structure of event.detail.channels
// [{
// selection: 1,
// active: true,
// },
// {
// selection: 2,
// active: false,
// }, ...
// ]

Check events

All the next events will start with check: because they are events that return when you consult something.

Check beeper

Possible values are true or false.

machine.on('check:beeper', event => {
// enable = true, disable = false
console.log(event.detail.beeper);
});

Check elevator speed

Possible values are low or high.

machine.on('check:elevator-speed', event => {
console.log(event.detail.speed);
});

Check engine voltage

Voltage will be a number between 5 and 9.5

machine.on('check:engine-voltage', event => {
console.log(event.detail.voltage);
});

Check expiration after X minutes

Will return the minutes before the expiration.

machine.on('check:expiration-after', event => {
console.log(event.detail.minutes);
});

Check expiration by temperature

Possible values are true or false.

machine.on('check:expiration-by-temperature', event => {
console.log(event.detail.enabled);
});

Check extractor after dispense

Return seconds that the extractor will be active after dispense.

machine.on('check:extractor-after-dispense', event => {
console.log(event.detail.seconds);
});

Check isolation tray

Return the number of the isolation tray.

machine.on('check:isolation-tray', event => {
console.log(event.detail.enabled);
});

Check language

Return the language of the machine. Possible values are:

  • Spanish
  • English
  • French
  • unknown
machine.on('check:language', event => {
console.log(event.detail.language);
});

Check machine ID

Return the machine ID.

machine.on('check:machine-id', event => {
console.log(event.detail);
});

Check push over

Return is the selection consult is enabled or disabled to push over.

machine.on('check:push-over', event => {
console.log(event.detail.push);
});

Check standby after collect

Return the seconds that the machine will be waiting before go to standby after collect.

machine.on('check:standby-after-collect', event => {
console.log(event.detail.seconds);
});

Check standby without collect

Return the minutes that the machine will be waiting before go to standby without collect.

machine.on('check:standby-without-collect', event => {
console.log(event.detail.minutes);
});

Check temperature before expiration

Return the temperature before the expiration.

machine.on('check:temperature-before-expiration', event => {
console.log(event.detail.temperature);
});

Check temperature scale

Return the temperature scale.

Possible values are:

  • Celsius
  • Fahrenheit
machine.on('check:temperature-scale', event => {
console.log(event.detail.scale);
});

Clock registers

Return date and time of the machine.

  • day is the day of the month
  • month is the month of the year
  • year is the year
  • hours is the hours of the day
  • minutes is the minutes of the hour
  • formatted has the format hh:mm DD-MM-YY
  • date is an instance of Date
machine.on('clock:registers', event => {
console.log(event.detail.formatted);
// or
console.log(event.detail.date.toLocaleString());
});

Dispensed

This event is dispatched when the machine dispenses a product, however the result of const result = await dispatch(...) is more convenient because you can continue the execution of the code.

i.e: Dispensing cart of 5 products, you can continue the execution of the code after the first product is dispensed in a loop.

machine.on('dispensed', event => {
// this event not return any data inside the event.detail
});

Dispensing

This event is dispatched when the machine is in process of dispensing a product.

machine.on('dispensing', event => {
console.log(event.detail);
});

Structure of event detail

event.detail
{
"status": null,
"counter": 6,
"limit": 40
}

Dispensing withdrawal

This event is dispatched when the machine says the elevator is full, and you need to recall the products.

Note

The event will be sent each second until seconds counter is 0.

Info

Or you can call method productRemovedContinueDispensing to continue the dispensing process.

machine.on('dispensing:withdrawal', event => {
console.log(event.detail);
});

Structure of event detail

event.detail
{
"elevator": true,
"seconds": 50,
"description": "Please recall products from the elevator"
}

Door event

This event is dispatched when the door is opened or closed. open is a boolean value.

machine.on('door:event', event => {
console.log(event.detail.open);
});

Jofemar error

This event is dispatched when the machine emits an error.

machine.on('jofemar:error', event => {
console.log(event.detail.type, event.detail.severity);
});

Possible type of error:

typeseverityDescription
jamhighElevator doesn't move; move slowly or jammed
malfunctionhighFault in elevator belt or photo sensors
photo-transistorshighFault in any of the cabinet's photo sensors
without-channelshighNo channels detected
fault-keyboardhighFault in keyboard
eeprom-writing-errorcriticalEeprom writing error
channels-power-consumption-detector-faultycriticalChannels power consumption detector faulty
elevator-not-find-delivery-positionhighElevator does not find delivery position
interior-elevator-blockedlowInterior of the elevator blocked
error-tester-product-detectorhighError in tester of product detector

Jofemar warning

This event is dispatched when the machine emits a warning.

machine.on('jofemar:warning', event => {
console.log(event.detail.type, event.detail.severity);
});

Possible type of warning:

typeseverityDescription
invalid-traylowInvalid requested tray
invalid-channellowInvalid requested channel
empty-channellowEmpty channel (no stock)
fault-product-detectorlowDetecting product (product in elevator)
display-disconnectedlowFault in 485 BUS (display disconnected)
product-under-elevatorlowProduct under the elevator alarm
error-approaching-positionhighError when elevator approaching to a position
fault-temperature-controllowFault communicating with temperature control
thermometer-disconnectedlowThermometer is disconnected
thermometer-programming-lostlowThermometer programming lost
thermometer-faultylowThermometer faulty
elevator-not-find-channel-traylowElevator does not find channel/tray
product-expired-temperaturelowProduct expired due to temperature
automatic-door-faultylowAutomatic door faulty

Keyboard pressed

This event is dispatched when the user presses a key on the keyboard.

Values for ascii when user press key are:

  • A B C D
  • 6 7 8 9
  • 2 3 4 5
  • * 0 1 #
machine.on('keyboard:pressed', event => {
console.log(event.detail.ascii);
});

Machine activity

This event is dispatched when you request the machine activity.

machine.on('machine:activity', event => {
console.log(event.detail);
});

This event is more complex than the others, so here is the structure of the event detail.

Types of activity

to divide the types, we have 3 types of activity:

  • hhmmssWddMMAA
  • HDU
  • DU.d

hhmmssWddMMAA

Structure of hhmmssWddMMAA

type 'hhmmssWddMMAA'
{
"ascii": "A",
"type": "hhmmssWddMMAA",
"date": "Instance of 'Date'",
"hex": [],
"formatted": "8/22/2024, 11:58:07 AM",
"meaning": "description"
}

meanings:

{
"A": "Attempt to close product exit door",
"C": "CLosing of exterior door",
"H": "Error on opening of product exit door",
"I": "New attempt to arrive at product exit position after an error on first attempt",
"J": "Power on cooling unit",
"K": "Power off cooling unit",
"L": "Start of defrosting",
"M": "End of defrosting",
"O": "Opening of exterior door",
"R": "Memory reset",
"S": "Error on going to product exit position",
"Y": "Power on machine",
"Z": "Power off machine",
"c": "Closing of inner door",
"e": "New attempt to extract from channel due no product detection when elevator arrived to product exit position",
"o": "Opening of inner door"
}

HDU

Structure of HDU

type 'HDU'
{
"ascii": "D",
"type": "HDU",
"hex": [],
"hundreds": 1,
"dozens": 1,
"decimals": 0,
"channel": 1,
"meaning": "description"
}

meanings:

{
"B": "Error on going to tray channel",
"D": "Error on product detector",
"E": "Extraction of channel ok",
"F": "Error on engine intensity detection",
"G": "Error on product exit door"
}

DU.d

Structure of DU.d

time is in seconds

type 'DU.d'
{
"ascii": "T",
"type": "DU.d",
"dozens": 1,
"units": 1,
"decimals": 0,
"time": 11.0,
"meaning": "Extraction time (in seconds)"
}

Machine faults

This event is dispatched when you request the machine faults. This will return the number of faults and the faults in an array.

machine.on('machine:faults', event => {
console.log(event.detail);
});
structure event.detail
{
"no_faults": 2,
"faults": [
"one",
"two"
]
}

Possible values for faults are:

  • Busy
  • Invalid tray
  • Invalid channel
  • Empty channel
  • Jam in elevator engine
  • Malfunction in the elevator belt or product detector
  • Failure in one of the photo transistors in the cabinet
  • No channels detected
  • Product detector fault
  • Machine display is disconnected
  • Product alarm under elevator
  • Error when elevator approaching to a position
  • Fault in keyboard
  • Eeprom writing error
  • Fault communicating with temperature control
  • The thermometer is disconnected
  • Thermometer programming lost
  • Thermometer faulty
  • Channels power consumption detector faulty
  • Elevator does not find channel or tray
  • Elevator does not find delivery product position
  • Interior of elevator blocked
  • Error in tester of product detector
  • Waiting for product to be removed
  • Product expired by temperature reasons
  • Automatic door faulty
  • Product is expired
  • Product detector didn't change during its verification test

Not dispensed

This event is dispatched when the machine doesn't dispense a product. However, the result of const result = await dispatch(...) is more convenient because you can continue the execution of the code.

i.e: Dispensing cart of 5 products, you can continue the execution of the code after the first product is dispensed in a loop.

machine.on('not-dispensed', event => {
console.log(event.detail.reason);
});

Possible values for reason are:

  • timeout
  • no-stock
  • elevator-locked (Re-dispense will occur after elevator is unlocked, no action needed)
  • no-response (Re-dispense will occur when machine responds, no action needed)

Program version

This event is dispatched when you request the program version.

machine.on('program:version', event => {
console.log(event.detail.version);
});

Reset errors

This event is dispatched when you request to reset the errors (resetMachineErrors method or resetAllErrors method). The reason it's because the machine will check machine, and this can take around 25-60 seconds.

machine.on('reset:errors', event => {
console.log(event.detail);

// console.log(Date.now() > ended_at.getTime()); // do things with the information
});
Note

instance of 'Date' is javascript date object

structure event.detail
{
"description": "Resetting machine errors",
"duration": 25,
"started_at": "instance of 'Date'",
"finished_at": "instance of 'Date'"
}

Command executed

This event is dispatched when you send a command to the machine and the machine confirm receipt of the command.

machine.on('command-executed', event => {
console.log(event.detail); // nothing relevant
});

Current temperature

This event is dispatched when you request the current temperature.

machine.on('temperature:current', event => {
console.log(event.detail.formatted);
});

Structure of event detail

structure event.detail
{
"sign": "+",
"tens": 1,
"units": 0,
"decimals": 0,
"type_degrees": "C",
"formatted": "+10.0°C",
"decimal_point": ".",
"degrees": "°"
}

Working temperature

This event is dispatched when you request the working temperature.

This is the temperature that the machine stop freezing.

machine.on('temperature:working', event => {
console.log(event.detail.temperature);
});

Structure of event detail

structure event.detail
{
"hex": [],
"temperature": {
"traditional": 0.5,
"ice_plus": -25
}
}

Machine status

This event is dispatched when you request the machine status.

machine.on('machine:status', event => {
console.log(event.detail);
});

Unknown

This event is dispatched?.

machine.on('unknown', event => {
console.log(event.detail);
});

Corrupt message

This event is dispatched when the machine receives a corrupt message.

machine.on('corrupt:message', event => {
console.log(event.detail)
});