All work
Reference architectureA pattern we build with, written up in full. Not a delivered client project.

Vending fleet: telemetry and remote support

A machine 400 km away stops selling. This is the software chain that tells you why without sending a technician.

Area
Mobile apps and connected machines
Written
2026
Built with
  • Embedded Android
  • Kotlin
  • MQTT
  • Node.js
  • PostgreSQL
  • React
The open front of a coffee vending machine during a service visit: control boards and a coin unit on the door, tubing running down from the mixing heads, and a bucket on the floor catching what is flushed through.
Inside this project

The problem

A vending or kiosk operator has three separate blind spots. The machine knows what happened but keeps it locally. The payment provider knows a card was charged but not whether anything came out of the slot. The support line has neither, so every ambiguous complaint costs a site visit.

The software problem is not the dispense — it is reconciling charged with delivered, and doing it fast enough that a customer on the phone gets an answer.

How we build it

1. The machine application

A single-purpose application on the machine: product selection, payment, dispense, and a local queue. It assumes the network is down, because sooner or later it is. Every event — coin inserted, card authorised, motor turned, optical sensor triggered — is written to a local append-only log first and published second.

2. The transport

MQTT over TLS with per-device credentials, a last-will message so a machine going quiet is an event rather than silence, and a shadow document holding the configuration the machine should be running.

3. The service

A small ingest service that turns device events into two things: a ledger row (charged / dispensed / refunded, reconciled by transaction id) and a health record (temperature, door state, stock level, firmware version, last seen).

4. The screen the support team actually uses

One page per machine: current state, the last fifty events in plain language, stock by slot, and two buttons that matter — re-dispense and refund — both recorded against the operator who pressed them.

What you would get

  • The machine application and its update channel
  • An ingest service and event schema you own
  • A fleet dashboard, and a single-machine view built for a phone call
  • A reconciliation report that finance will accept

Where it gets hard

Clock skew between the machine and the server makes event ordering a lie — so the device stamps a monotonic sequence number, not just a timestamp. Firmware rollout needs a staged channel and a rollback, because a bad update on a fleet is a very expensive lesson. And optical sensors fail open: without a second signal, “dispensed” is an assumption.

Typical architecture

A machine reporting to ingest, then to a ledger and a support viewmachinelocal log firstthen publishMQTTingestcharged vs dispensedledgerhealthremote command, logged
A pattern we build from, not this project’s own design. No client data or client system is depicted.

Next

Order intake agent for a wholesale back office

Read it

Have a version of this problem?

Tell us what your setup looks like. We will tell you which parts of this apply and which do not.