Fault map and control surface for the spring-coil cabinet, derived from the drive board protocol.
Connecting… Live cabinet state loads after login.
Synced from the machine's vend log and stock table; this page checks for new data every 15–30 s. Prices are the machine's payment record for each sale; product names come from your VendSys export wherever one is loaded (bottom of this tab, or the Sales tab).
Needs attention
Today
Every pack sold on this day, grouped by product with its picture, biggest earner first. A faded, dashed pack was paid for but not delivered (and not handed over by a test vend since).
Through the day · one picture per pack
| Time | Type | Slot | Product | Payment | Delivery |
|---|---|---|---|---|---|
| waiting… | |||||
What left each slot today against what the machine says is left. Start of day is estimated as the stock reading plus what left the slot today before that reading, so it's only right if the slot wasn't restocked today; a negative count shows as 0 (count off).
| Slot | Product | Sold | Tests | Failed | Stock now | Start of day (est.) |
|---|---|---|---|---|---|---|
| waiting… | ||||||
Drop your VendSys sales export (.xlsx or .csv) here to check every payment against what the machine logged. Matched sales then show VendSys's product and amount everywhere on this page. The file is read and kept in this browser only — never uploaded; Forget clears it.
| VendSys time | Slot | VendSys product | Paid | Machine logged | Status |
|---|
Sales by day
Top products
Needs attention
click one to see it in the machineMachine health
All 50 coils report no fault (live, the drive board's own self-check).Live from the drive board's self-check per coil.Coil faults can't be shown right now: the cabinet's live coil feed isn't answering. Failed vends (such as code 235) count in Vend success and Needs attention.
Money is vend value: the price on each delivered vend (payment-matched, VendSys amounts where an export is loaded), not settled cash.
Every slot from the live stock table, one pack per unit on its coil; slot numbers are coloured by vend rate for the dates above. Hover or tap a slot, click to zoom in on its sales. Drag to turn, right-drag or two fingers to move, + / − or pinch to zoom, and click the screen to see what customers see.
Waiting for the stock table…
Still from the cabinet, proxied through /vending-api/camera.jpg. The device publishes a new frame about once a minute; this page reloads the image on the same cadence, and stops fetching stills while live view is showing or the tab is in the background.
Waiting for still…
Streams the Tapo stream2 feed through /vending-api/camera/hls/*. Pause and Back to still only stop the download to this browser; the cabinet keeps the stream warm, so resuming jumps straight to live. ffmpeg idles out about 15 minutes after this page is closed. Expect a few seconds of latency.
CPU, memory and storage on the cabinet's Android board (RK3288, 4 cores), from the latest stored sample via /vending-api/sysstat.
Customer sales only (technician test vends excluded). Figures are vend value — the price owed on each delivered vend, not confirmed settled cash.
From the dispense log matched to payment records. Prices come from the payment record. Product names come from your VendSys export wherever it covers the sale; otherwise from the machine's label at the time, or, where that label was out of date (its price wasn't what was paid), from what the slot holds now at the price paid, tagged “likely”.
Paid, not delivered — check for refund
What sells
Vend value by day
Sales by hour × weekday
Product names & prices
Every dispense the drive board reports, newest first, grouped by machine day (UTC+8).
Polled through /vending-api/vend-log. Sale: the app was polling a customer payment just before. Test: a backend remote action triggered it. Rows marked from history predate the live watcher and are inferred from the logs. Prices are corrected to the payment record, and names to VendSys where an export is loaded, or tagged “likely” where the machine's label was out of date (hover a tag to see what the machine logged). A plain sale that was delivered carries no badge.
| Time | Slot | Product | Payment | Delivery |
|---|---|---|---|---|
| waiting… | ||||
Per-slot quantity from the latest stored snapshot of the machine's product table through /vending-api/stock. Only slot, product and count are read — nothing else from that table is exposed. Empty test slots and slot numbers that have never been used are hidden; a negative count is shown as “count off”, never as out.
| Slot | Product | Qty | Level |
|---|---|---|---|
| waiting… | |||
Days left = the product's stock across all its slots ÷ its recent pace (sales in the last 7 days, or since it first sold if that's sooner), so a slot never carries sales from a product it held before. Empty slots of products that still sell come first, then the products that run out soonest. Products with no recent sales show “—”.
| Slot | Product | Qty | Sold/day | Days left | Runway |
|---|---|---|---|---|---|
| waiting… | |||||
Six trays, fifty motors. The top tray carries five double-width slots driven by paired coils on odd addresses; trays two through six carry nine single slots each. Select any coil to see what the stock table says is in it and where it sits.
Checking the machine's coil table…
In plain terms: the customer pays on the touchscreen, but the app there can't turn a motor itself. It sends a short coded order down a cable to the spring drive board, which turns that slot's spiral coil once. Each pack stands in its own turn of the coil, so the front one is pushed off the end and falls through a light curtain, the machine's only check that it really dropped. Then the board reports back: delivered, or an error code. The drawing is your cabinet to scale, filled from the stock table.
Example: slot 47
Per-slot failed-vend rate from the drive board's own ship results (the board reports a drop-sensor confirmation on each vend). A slot with repeated failures is flagged as a suspected jam and should be checked.
| Slot | Product | Fails | Attempts | Fail rate | Flag |
|---|---|---|---|---|---|
| waiting… | |||||
Recovered from the drive board resource table. Per-coil codes are bit-packed: the high nibble names the power-stage failure, the low nibble names the photocell failure, so a single byte reports both at once. Codes from 80 up are bus-level and are not attributable to one coil.
| Code | Hex | Class | Meaning |
|---|
Values read from the machine's own configuration broadcast. These are the settings the SDK exposes for adjustment. None are writable from this page — the write path is deliberately absent until you decide to build it.
What each panel needs before it stops being a snapshot. Ordered by dependency — each step needs the one above it.
The safest source. DriveControl already writes every ship attempt, fault code and heartbeat to /sdcard/TCNLog/. Tailing that file over the existing SSH tunnel fills the coil map without touching the serial bus at all.
A small service parses those lines into the state model this page already renders, one record per coil, and exposes them as JSON. Still read-only, still no contention for the UART.
Reading faults directly means issuing CMD_QUERY_SLOT_FAULTS on /dev/ttyS4. The port is world-writable, so this is possible, but the vending app owns that bus. Two writers on one UART will corrupt frames. Either arbitrate through the app or accept log-only telemetry.
Parameter changes and CMD_CLEAR_SLOT_FAULTS are the last step, behind a confirmation, with the machine out of service. A stray CMD_SHIP turns a real motor and drops real stock.