Developing a Mobile App for Self-Service Laundry
A self-service laundry without a mobile app means coins and lines at the payment terminal. With an app: scan the QR code on the machine, select a wash program, pay, and get a notification when the cycle is done. For network operators: remote machine monitoring, utilization statistics, and price management without visiting each location.
Machine Control: Communication Protocol
Self-service washing machines are controlled via an IoT module, either built-in or installed separately: ESP32 or Raspberry Pi with GSM/Wi-Fi connectivity. The module connects to the machine's control board via relays (button emulation) or through UART/RS485 if the machine has a service interface.
Most commercial machine manufacturers (Electrolux Professional, Miele Professional, Speed Queen) provide an API or service protocol documentation — request it directly from the vendor. For budget machines without protocol support, relay-based control works: the module detects the "cycle started" signal from a current sensor (SCT-013) and publishes status to the server.
Architecture: IoT-module ↔ MQTT-broker (Mosquitto/HiveMQ) ↔ backend ↔ mobile app via WebSocket.
// Android: subscribe to machine status via MQTT
class LaundryMachineMonitor(private val machineId: String) {
private val mqttClient: MqttAndroidClient = /* initialization */
fun subscribeToMachine(onUpdate: (MachineStatus) -> Unit) {
mqttClient.subscribe("laundry/$machineId/status", 1) { _, message ->
val json = String(message.payload)
val status = Json.decodeFromString<MachineStatus>(json)
onUpdate(status)
}
}
fun startCycle(program: WashProgram, token: String) {
val command = Json.encodeToString(StartCycleCommand(program, token))
mqttClient.publish("laundry/$machineId/command", command.toByteArray(), 1, false)
}
}
@Serializable
data class MachineStatus(
val state: MachineState, // IDLE, RUNNING, DONE, ERROR
val programName: String?,
val remainingSeconds: Int?,
val errorCode: String?
)
Payment and App Store Review Bypass
The key challenge: Apple considers wallet balance top-ups "digital goods" and requires IAP with a 30% commission. However, if the wallet is used for physical services (laundry is a physical service), external payment processing can be used directly.
Scheme: balance top-up redirects to Safari/SafariViewController to a payment page (Yandex.Kassa, Stripe, CloudPayments). Paying for a specific cycle uses API debit from the balance. Apple Guidelines 3.1.5(b) permit this for "real goods and services."
Android with Google Pay is simpler: PaymentsClient with card or WebView integration.
UX: Queue and Booking
Users want to know if a machine is free before traveling to the laundromat. A location map with real-time machine availability indicators is the key home screen feature. Filtering options: "only available machines," "with dryers."
Machine reservations for 10–15 minutes is controversial. Without reservations: you arrive to find everything busy. With reservations: many abandoned bookings. Compromise: paid booking (deducts 1 unit), credited toward cycle payment.
Push notification 5 minutes before cycle end and upon completion via FCM/APNs. Server-side: a worker checks remaining time from machine data and schedules push via FCM Schedule (Android) or APNs with apns-expiration.
Loyalty Program
Points accumulation for wash cycles is a simple retention mechanic. Every Nth cycle is free. Implementation on the server; the mobile app displays progress via API.
Developing a mobile app for a laundry network with payment, machine management via MQTT, and notifications: 8–12 weeks. With location maps, loyalty program, and CMS for network management: 4–5 months. Pricing is calculated individually.







