Put-to-light
With put-to-light, every bin has a light (and usually a button) that shows the operator where to put: the bin lights up after a scan, often with the quantity on a small display, and the operator presses its button when the unit is in. The install drives the lights of any vendor through one of two neutral interfaces, an HTTP gateway or an MQTT broker, and has a simulator for trying it out without hardware.
The lights are an addition, never a dependency: a scan never waits for them and never fails because of them. If the hardware is offline, scanning goes on, and the lights catch up when it is back.
Choose a driver#
SLOTTING_LIGHTS |
|
|---|---|
none (default) |
No hardware. The light state can still be read (below) |
http |
POST the changes to your light gateway: HTTP gateway |
mqtt |
Publish the changes to an MQTT broker, one topic per bin: MQTT |
simulator |
No hardware: the wall drawing shows the lights and its bins work as buttons: Simulator |
SLOTTING_LIGHTS_RESYNC_MS (default 60000, 1000 to 86400000) is how often the install sends the whole state again
(below). The other settings are per driver.
The light state#
The install doesn't send "light on" and "light off" commands that your hardware has to keep track of. It works out, from the state of the waves, how every bin's light should look, and sends what changed. Each bin is in one of three states:
| State | When | Shown as (your choice) |
|---|---|---|
put |
Put here: the bin of a pending put (waves with confirmed puts), or, without confirmation, the bins of each operator's latest scan, until that operator's next scan in the wave | Lit, often blinking, with quantity on the display |
complete |
The order in this bin is complete: pack it out | Lit in another colour, steady |
| off | Anything else (free bins, orders still being filled, released orders, closed waves) | Dark |
- A bin with a pending put shows
put, with theskuandquantityof its oldest pending put; else the latest put; elsecomplete. So without confirmation, the bin of the scan that completed an order keeps showingputuntil that operator's next scan, while the order's other bins already showcomplete. - Every operator (the
operatorof the scans) keeps their own latest put lit, so several operators can work one wall. Undoing a scan turns its light off. - With confirmed puts, only pending puts light up as
put: confirming the put turns it off (or tocomplete, when it was the order's last).
The state belongs to the layout, across all its waves. Read it any time, whatever the driver:
curl -s "$SLOTTING_URL/api/layouts/PUTWALL-A/lights"[
{ "binId": "A-01-01", "wallId": "A", "address": "A-01-01", "state": "put", "waveId": "WAVE-CURL-2", "orderId": "ORD-2001", "quantity": 1, "sku": "MUG" }
]Bins that are not listed are off. address is the bin's light address.
How the install keeps the lights right#
- After every change, the install compares the new state with what it sent last and sends only the bins that changed,
offincluded. - On start, and every
SLOTTING_LIGHTS_RESYNC_MS, it sends the whole state again: every lit bin, andofffor bins that may still be lit (on start, for every bin of the layout). After a failed send, the next send of that layout is a whole state too, also when it was already waiting (a change made while the failed send was under way), so nothing the failed send carried is lost. - So your gateway or modules must set the state they receive (
putwith this quantity,complete,off), not toggle, and may receive the same state several times. - Failed sends are logged as warnings, once per outage, and never fail a scan.
With several instances, each one sends the changes it makes, and every instance resends the whole state periodically, so the hardware ends up with the same state whichever instance it heard last.
HTTP gateway#
For a light controller with an HTTP interface, or a small service of yours that talks to the vendor's controller.
| Variable | |
|---|---|
SLOTTING_LIGHTS_URL |
Required: the gateway's http:// or https:// URL. No user name or password in the URL |
SLOTTING_LIGHTS_TOKEN |
Optional: sent as Authorization: Bearer <token> (1 to 4096 visible characters) |
The install sends a POST with Content-Type: application/json per layout and change:
{
"layoutId": "PUTWALL-A",
"changes": [
{ "address": "A-01-01", "binId": "A-01-01", "wallId": "A", "state": "put", "quantity": 2, "sku": "MUG" },
{ "address": "A-01-02", "binId": "A-01-02", "wallId": "A", "state": "off" }
]
}| Field | |
|---|---|
layoutId |
The layout the bins belong to |
changes[] |
Bins whose light must change: address, binId, wallId, state (put, complete or off), and for put the quantity and sku to show |
all |
Only in a resync: the layout's whole light state, as in GET /api/layouts/{layoutId}/lights. A gateway that prefers to replace its state can use it; changes then holds every lit bin and the bins to turn off |
Answer 2xx within 2 seconds. Any other answer, a timeout or a redirect (not followed) counts as failed, and the
layout is sent as a whole state with the next change and at the next resync.
When an operator presses a bin's button, the gateway calls the press route of the install.
MQTT#
For lights that speak MQTT, or a gateway that bridges MQTT to the vendor's bus.
| Variable | |
|---|---|
SLOTTING_LIGHTS_MQTT_URL |
Required: mqtt://broker:1883, or mqtts://broker:8883 for TLS. A user name and password may be in the URL |
SLOTTING_LIGHTS_MQTT_USERNAME, SLOTTING_LIGHTS_MQTT_PASSWORD |
The broker login, if it isn't in the URL (these win) |
SLOTTING_LIGHTS_MQTT_CA_FILE |
A PEM file with the CA certificate of your broker (private CA). Needs an mqtts:// URL. It replaces the system's CAs for the broker connection, so a broker with a public certificate needs no CA file |
SLOTTING_LIGHTS_MQTT_PREFIX |
The first topic levels, default slotting (letters, digits, ., _, -, levels separated by /) |
The install publishes each bin's state retained, with QoS 1, to
<prefix>/<layoutId>/<address>/setwith the payload
{ "state": "put", "quantity": 2, "sku": "MUG", "binId": "A-01-01" }state is put, complete or off (off and complete without quantity and sku). Because the messages are
retained, a module that restarts or reconnects gets its bin's current state from the broker at once. In a topic, the layout
id and the address keep letters, digits and . _ : -; any other character is percent-encoded (UTF-8), so a light address
A/01 is the single topic level A%2F01.
Button presses: the install subscribes to <prefix>/+/+/press (QoS 1). A module (or gateway) publishes any payload (up
to 1 KiB; it is not read) to
<prefix>/<layoutId>/<address>/pressnot retained: retained press messages are ignored, so a stale press can't confirm a put when the install reconnects.
A press is handled exactly like the press route; a press with nothing to do is logged and ignored.
While the install has no valid license, MQTT presses are ignored (with a warning in the log), just as the press route
answers 402.
The install connects with a random client id and a clean session, reconnects every 5 seconds when the broker is gone, and logs the connection state (never the password). On every reconnect it sends the whole state of every layout (a broker that restarted without persistence has lost the retained states), so changes made while the broker was offline arrive once it is back.
Restrict who may press. Any client that can publish to <prefix>/<layoutId>/<address>/press confirms puts and
releases orders: the install can't tell a module from any other MQTT client. Configure the broker's ACLs so only your light
modules or gateways may publish to <prefix>/+/+/press, only the install may publish to <prefix>/+/+/set, and
nobody else may write under the prefix (for example Mosquitto acl_file with a user per gateway, topic write slotting/+/+/press; EMQX or HiveMQ authorization rules). Give the install its own broker user with exactly that:
subscribe <prefix>/+/+/press, publish <prefix>/+/+/set.
Button presses#
curl -s -X POST "$SLOTTING_URL/api/lights/press" -H 'Content-Type: application/json' \
-d '{ "layoutId": "PUTWALL-A", "address": "A-01-01" }'POST /api/lights/press with the layout and the light's address (its light address, else the bin
id). The bin decides what the press means:
| The bin | The press | Answer |
|---|---|---|
| Has a pending put (confirmed puts) | Confirms the bin's oldest pending put, like a scan of the bin label | { "action": "confirmed", "result": ConfirmResult } |
Holds a complete order |
Releases the order: packed out, all its bins are free | { "action": "released", "orderIds": [...], "bins": [...] } |
Just confirmed by a press, or its order completed, less than SLOTTING_PRESS_RELEASE_GUARD_MS ago |
Nothing changes: the press repeats the one before (a double press, a bouncing button, a redelivered MQTT message) | 200 { "action": "ignored", "reason": "duplicate" } (a press confirmed a put in this bin) or "too_soon" (the order just completed) |
| Anything else (a free bin, an order still being filled, an unknown address) | Nothing changes | 409 not_pending |
So one button does both jobs of a put-to-light wall: press after putting (with confirmed puts), and press after emptying
the bin at pack-out. A complete order lights all its bins complete; pressing any of them releases the whole order.
Because the same button confirms and releases, a press right after another one of the bin is ignored for
SLOTTING_PRESS_RELEASE_GUARD_MS (default 3000, 0 to 600000; 0 turns the guard off): the last put's press must not
also pack out the order, and a press the broker delivers twice must not confirm the next put. An ignored press is not an
error (200); press again after the pause. An invalid value falls back to the default.
{"action":"released","orderIds":["ORD-2001"],"bins":[{"id":"A-01-01","wallId":"A"}]}The press route is a change like any other: it needs a license (402 otherwise), and it refuses requests from browser
pages on other origins (Network and security); a gateway calling from a server sends
no Origin and is not affected. It works with every SLOTTING_LIGHTS setting, so an HTTP gateway can report presses
while the install drives the lights over MQTT, or the other way round.
The simulator#
SLOTTING_LIGHTS=simulator needs no hardware. On the admin page (/), the Station tab has a Light simulator
switch that shows every wall of the station's layout with its lights: put bins pulse with the quantity, complete bins
are steady, and clicking a lit bin presses its button. Scan at the station, click the bin, and watch the put being
confirmed or the order being released.
The same in your own pages: <slotting-wall lights simulate-buttons> polls the light
state and shows it; with simulate-buttons a click (or Enter or Space) on a lit bin presses its button. Without
simulate-buttons it only shows the lights, which is useful next to real hardware too, for example on a supervisor's
screen. The light state and the press route are available with every driver, so the simulator works next to real lights.
Light addresses#
A bin's light is addressed by the bin's lightAddress in the layout, or by the bin id when it has none. Give bins an
address when your light modules are numbered differently from the bin labels:
{ "id": "A-01-01", "x": 0, "y": 30, "width": 40, "height": 30, "depth": 40, "lightAddress": "ctrl1/017" }- 1 to 64 characters of
A-Z a-z 0-9 . _ : / -, unique in the layout. - An address may not be another bin's id (that is the other bin's address when it has none).
- The setup editor has a Light address column (empty means the bin id). In the CSV import, set it afterwards in the editor or in the JSON.