Tuna

Use case Blog · 16 October 2026 · 7 min read

Running a fleet of smart vending machines: screens, payments and peripherals

The vending machine in a station or an office lobby is no longer just coils and a coin slot. Inside the newer ones there is a small Linux computer, often a Raspberry Pi or an industrial board, driving a touch screen, talking to a card reader and a coin unit, turning the motors that drop the product, and reading the temperature of the cabinet. All of that is software, and software needs updating: new screens for a promotion, a fix for the card reader, a new product layout. Driving to every machine with a laptop does not scale past a handful.

What runs inside a machine

Split the work into small services that each do one job. A typical machine has four:

Described together in tuna.json, they start in the right order and are updated and rolled back as one set:

{"services": {
  "payments": {"command": "./payments/run.sh", "cwd": "volume", "healthPath": "/health", "port": 7001},
  "vend":     {"command": "./vend/run.sh", "healthPath": "/health", "port": 7002},
  "shop":     {"command": "./shop/run.sh", "dependsOn": ["payments", "vend"],
               "port": 8080, "healthPath": "/health", "expose": true},
  "telemetry": {"command": "./telemetry/run.sh", "dependsOn": ["vend"]}}}

The payments service keeps its transaction journal on the volume, so a sale that happened while the network was down is still there after an update and can be settled later.

The screen is a kiosk

Turn on the kiosk for the fleet and every machine opens the shop service full screen at boot, with no desktop, no cursor and no right-click menu. While the app is still starting, the machine shows its own status page with the device name and the state of each service instead of a blank screen, and it switches to the shop as soon as the shop answers. Resolution and zoom are fleet settings that a single machine can override, which helps when one model has a different panel. From the hub you can ask any machine for a screenshot of what its customers are looking at right now.

Peripherals and permissions

Services run as an unprivileged tuna user, never as root. The installer gives that user the screen, touch input and audio. Card readers, coin units and motor boards usually sit on serial ports or GPIO pins, so add the user to those groups once when you prepare the image:

sudo usermod -aG dialout,gpio tuna

Keep the hardware code behind a small local API (the payments and vend services above). The shop screen then never touches a serial port, and you can test it on a laptop against a fake.

Updates that never strand a customer

A new release is installed next to the running one and only becomes current after every service with a health path answers. If payments fails to open the card reader, the machine goes back to the previous release by itself and reports which service failed and its last lines of output. A power cut in the middle of an update leaves the machine on the old or the new release, never half of each.

Roll out in steps. Mark the machine in your own office as a canary, then widen to a few sites, then everyone:

tuna push vending --notes "new card reader driver" --percent 10

Stock, sales and temperature on a dashboard

Every service gets its device's own key in TUNA_DEVICE_API_KEY, so the telemetry service can send readings without any credentials of yours on the machine:

curl -X POST "$TUNA_API_URL/api/devices/self/data" \
  -H "authorization: Bearer $TUNA_DEVICE_API_KEY" -H "content-type: application/json" \
  -d '{"temp": {"value": 4.2, "unit": "°C", "title": "Cabinet"}, "sales_today": 37, "door_open": false}'

Each machine gets a dashboard of what it sends, and the fleet dashboard puts the same values side by side, so a machine whose cooling is failing or whose door was left open stands out before the products spoil.

One fleet, many locations

Prices, the payment provider's endpoint and the location name differ from site to site. Set defaults for the fleet and let a machine override its own values, and the overrides are marked so you can see which machines are special. A machine that stops checking in shows up as silent and can send you a notification, and when you really need a shell, the remote terminal is off by default, asks for consent each time and records the session.

Try it with your own devices.
The first 10 devices are free, no card needed.
Get started

More to read