How We Built IoT Mobile Apps to Control Smart Vehicles and Engine Systems
Connected mobility. Real control. Built for what moves the world.
Published: Sept 16, 2026
Connected Vehicle App in a Nutshell
- The problem
Vehicle and engine data is difficult to access and manage in real time.
- The solution
Integrate IoT devices with intuitive mobile applications.
- The result
Remote monitoring and control from anywhere.
- The takeaway
TABLE OF CONTENTS
WRITTEN BY
A connected product is only useful if people have a practical way to interact with it.
For many IoT products, that interface is no longer a physical switch, control panel, or dedicated display. It is a mobile application, tablet application, web dashboard—or a combination of all three.
But building an application that communicates with real hardware is very different from building a conventional mobile app.
When a user presses a button, something physical may happen.
An engine may start or stop. A light may switch on. An inverter may change state. An air-conditioning system may respond. A controller may report an alarm. A value displayed on the screen may be coming directly from an embedded system rather than a cloud database.
The application therefore sits at the boundary between software and the physical world.
We have built one such connected-vehicle cross platform app for an Australian client.
The engagement involved two different applications:
01
Application 1
A Flutter mobile and tablet application that communicates with electronics inside a smart bus over Bluetooth Low Energy (BLE) and allows users to control vehicle functions such as the engine, lights, inverter, and air conditioning.
02
Application 2
An application designed around the functionality of a diesel-engine controller, bringing controller-related monitoring and control interactions into a software interface.
Although the applications served different purposes, they exposed the same fundamental IoT engineering challenge:
How do you turn a mobile device into a dependable interface for a physical machine?
That is the engineering story behind the product.
The case-study in 30 Seconds
The problem
Operators needed a simpler software interface for interacting with functions that traditionally depended on physical vehicle controls and dedicated engine-controller interfaces.
The hardware
ESP32-based electronics were integrated into the truck, providing Bluetooth Low Energy connectivity between the physical vehicle systems and the application.
The application
A cross-platform application was developed using Flutter for mobile phones and tablets.
The connectivity
The application communicates locally over BLE, allowing vehicle functions to be controlled without depending on internet connectivity.
The security
Passkey-based Bluetooth pairing restricts communication to authorized devices.
The second use case
A separate application was developed to reproduce controller-style interactions for a diesel engine, moving part of the experience of a dedicated engine controller into software.
The bigger lesson
An IoT application is not simply a mobile UI connected to some APIs.
It is part of the product itself.
A Mobile App That Controls Something Physical Is Different
Most mobile applications operate entirely inside the digital world.
A user clicks a button
The application calls an API
A database record changes
The screen updates
With an IoT application, that same button might result in a command reaching an embedded controller inside a truck and changing the state of an electrical or mechanical system.
The path starts to look more like:
User
Mobile App
Wireless Communication
Embedded Controller
Physical System
And information travels in the opposite direction as well:
Physical System
Embedded Controller
Wireless Communication
Mobile App
User
That difference changes the way the application needs to be designed.
Connectivity can disappear.
The hardware may be powered off.
A command might be sent while the device is disconnecting.
The physical state of the machine may change independently of the application.
Another device may reconnect later.
The user may close and reopen the application.
The application therefore needs to understand not just screens and buttons, but also device discovery, connection lifecycle, hardware state, command handling, reconnection, security, and synchronization.
This was central to both the client applications.
Two Applications, One Connected-Vehicle Problem
The work involved two different ways of bringing vehicle functionality into software.
The first was about direct control of heavy-duty vehicle functions.
The second was about turning functionality normally associated with a diesel-engine controller into a software experience.
The distinction is important.
In the first application, the mobile device behaves like a convenient remote interface to different systems distributed around the truck.
In the second, the application moves closer to the role of a dedicated controller interface: presenting engine-related operating information and exposing controller-style interactions through software.
Together, the two applications illustrate two common categories of IoT application development:
Remote Device Control
The application exposes functions performed by the connected product.
Examples include switching equipment, controlling accessories, changing modes, or triggering device functions.
Digital Controller Interface
The application represents the state and functionality of an embedded or industrial controller through software.
Instead of simply issuing an isolated ON/OFF command, the application becomes part of the operator’s interface to the machine.
That second category is especially important in industrial IoT, connected equipment, automotive systems, energy systems, machinery, and OEM products.
Application 1: Controlling a Smart Heavy-Duty Vehicle Through BLE
The first application was developed using Flutter, allowing a common application codebase to support both mobile and tablet interfaces.
At the hardware level, ESP32 microcontrollers were embedded within the power heavy-duty vehicle. The ESP32 provided the BLE communication layer between the application and different vehicle functions.
The application could be used to control functions including:
Engine
Lights
Inverter
Air conditioning
The important architectural decision was that these operations did not require an internet connection.
Communication happened locally.
That makes sense for an application whose primary responsibility is controlling equipment physically close to the user. If a driver is standing beside the heavy-duty vehicle, switching a vehicle function should not depend on:
when the phone and vehicle are already only a few metres apart.
Cloud connectivity is extremely useful in IoT—but it should not automatically sit in the middle of every interaction.
BLE gave the system a direct local communication channel. With the app, BLE allowed the mobile device to communicate directly with the ESP32.
This gave the system an important characteristic:
The fundamental vehicle-control experience could continue without internet connectivity.
That architecture is applicable far beyond logistics & vehicles. We see the same decision when designing applications for:
Industrial machinery
Energy systems
Smart appliances
EV accessories
Pumps
Agricultural equipment
Medical and wellness devices
Building-control products
Portable equipment
Field equipment
Securing Access to the Heavy-Duty Vehicles
A Bluetooth demo can be surprisingly easy to build.
Scan for devices -> Find the device -> Connect -> Write a value to a BLE characteristic -> Watch something happen
A production application needs considerably more than that.
The mobile app therefore included a structured scan-and-connect experience that allowed users to discover nearby ESP32 devices and establish a connection before accessing the vehicle’s controls.
The application included dedicated:
flows so that connection management was part of the product experience rather than an engineering utility hidden behind the UI.
That distinction matters.
The end user should understand:
Good IoT application development hides the complexity of the communication layer without hiding important information about whether the product is actually connected.
Convenience cannot come at the expense of access control.
If an application can control real equipment, connecting to that equipment must not be as simple as discovering a Bluetooth advertisement.
The mobile application therefore used passkey-based BLE pairing.
Only authorized users who successfully completed the pairing process could establish the required connection with the vehicle system.
Once pairing was completed, information about the paired device could be stored locally to support future connections.
The basic lifecycle became:
This is another important difference between a prototype IoT application and something intended for real-world use.
Connectivity answers:
Connectivity answers:
“Can my phone talk to the device?”
Security answers:
“Should this phone be allowed to talk to the device?”
Both need to be designed together.
Reconnection Is a Feature, Not a Technical Detail
Users do not think about BLE sessions.
They think: “I already connected this truck yesterday. Why do I have to set everything up again?”
After a successful pairing, the mobile app therefore stored the relevant device information locally.
This enabled persistent device relationships and supported automatic reconnection, particularly on Android where BLE reconnection behaviour could be used to improve the experience.
That removes unnecessary friction from everyday use.
This sounds like a small UX improvement.
But for an IoT product, Connectivity behaviour is part of the user experience.
A beautifully designed application that constantly loses the hardware connection feels like a bad product.
Managing Real-Time Application State with Flutter
Once an application starts controlling several hardware functions, UI state becomes increasingly important.
Imagine that the application contains controls for:
- Engine
- Air conditioning
- Lights
- Connection status
- Inverter
- Device information
The application needs a predictable way to update the interface as the state changes.
For this project, Flutter's Provider package was used for reactive state management.
Instead of allowing BLE logic and individual UI widgets to maintain independent versions of the device state, the application could maintain a cleaner separation between:
When a relevant value changed, the appropriate widgets could react without requiring unnecessary UI rebuilding or tightly coupling communication code to individual screens.
That becomes particularly valuable in IoT applications because state can change from two directions.
A user can initiate a change from the application.
But the connected device can also report a change.
A well-designed application needs to cope with both.
Closing the Loop with Notifications
Control without feedback creates uncertainty.
Did the command reach the system?
Did the engine state actually change?
Is the state shown by the application still current?
The mobile app therefore also supported notifications informing users about changes to the engine state.
This helps move the interaction away from a purely command-driven design, towards a closed-loop model:
Closed-loop interaction becomes increasingly important as connected products become more operationally significant.
The application should not simply assume that because a user pressed a button, the physical operation successfully happened.
Application 2: Turning an Engine Controller into a Software Experience
The second application approached the problem from another direction.
Instead of primarily controlling individual functions distributed across the power-heavy vehicles, the objective was to replicate the functionality and interaction model of a power heavy duty vehicle - engine controller in an application.
That is an interesting IoT problem because a conventional engine controller is more than a collection of buttons.
It represents the state of a machine.
The controller is where an operator sees what the engine is doing, understands its operating condition, receives status or fault information, and performs available control actions.
Moving that interaction into an application means recreating that relationship digitally.
Conceptually, the architecture changes
Embedded Interface
while information from the engine and controller flows back toward the application.
The result is not simply a remote-control app.
It is a software representation of a hardware control interface.
Replicating a Controller Is Primarily a State Problem
The difficult part is ensuring that what the user sees corresponds to what the physical system is actually doing.
A controller-oriented application may need to represent operating state, control state, status information, alarms or faults, and other engine-related information received from the connected system.
Every displayed value or condition has an origin in the device.
Every control action has an effect outside the application.
That means the application needs a clearly defined state model.
This separation makes the application easier to maintain and reduces the risk of allowing UI behaviour to become disconnected from hardware behaviour.
A Screen Is Not the Source of Truth
This is one of the most important lessons when developing software for IoT products.
The UI should not become the source of truth for the physical machine.
Suppose an operator presses START.
A conventional app developer might immediately change the screen to:
Engine: Running
But pressing START and successfully reaching the running state are two different events.
A hardware-aware application should instead think in states such as:
The same applies to fault conditions, operational information, switches, outputs, and other controller functions.
This distinction becomes particularly important when replacing or complementing physical control panels.
The application should represent the machine.
It should not merely represent what the application hopes the machine is doing.
Designing the Application Around Hardware Behaviour
Developing applications like these requires mobile and embedded teams to work together.
A mobile developer needs answers to questions that normally do not appear in a standard app project:
How is a valid device identified during scanning?
What information is available after connection?
What happens when two commands arrive quickly?
Which values are reported asynchronously?
What should the UI display when communication is lost?
What happens when the embedded controller restarts?
Does pairing survive an application restart?
Does the device state survive a connection drop?
These decisions form the actual contract between firmware and software.
That is why connected-product development works best when the mobile application is designed with the device architecture, rather than after the hardware has been completed.
The Application Is Part of the IoT Architecture
For many connected products, architecture diagrams make the mobile application look like the final box:
But the software interface often has much more responsibility than that diagram suggests.
In this application’s local BLE architecture, the application participates directly in device discovery, authentication, session management, state handling, commands, and operator feedback.
A simplified architecture looks like:
Secure Pairing
Layer
And state travels back through the same chain.
This is a useful architectural pattern for products where the operator and device are usually physically close.
It can also coexist with cloud connectivity.
It can also coexist with cloud connectivity.
while separately providing:
The local path handles immediate equipment interaction.
The cloud path handles functions such as remote visibility, analytics, fleet management, historical data, device management, and administration.
What This Project Taught Us About IoT App Development
The project reinforced several principles that apply to almost every connected-product application we build.
Connectivity Is UX
Connection and reconnection affect the whole product experience.
Local Control Has Value
Not every command needs to travel through the cloud.
Hardware Owns the State
The application should reflect confirmed machine state.
Security Starts at Pairing
Controlling equipment requires controlled access.
Firmware and App Are One System
Both sides need a clearly defined communication contract.
The Bigger Engineering Story Behind The Application
It would be easy to describe the project as:
Technically, that is true.
But it misses most of the interesting work.
The actual system involved:
- Mobile UX
- Persistent device relationships
- Embedded communication
- BLE device discovery
- Connection and reconnection management
- Physical equipment control
- Secure pairing
- Reactive state management
- Controller-state representation
That combination is what makes connected-product software different from ordinary application development.
The application is not sitting beside the product.
The application is part of the product.
The project started as a vehicle-control application, but the engineering challenge went much deeper than building screens in Flutter. The application had to discover hardware, authenticate connections, maintain BLE sessions, manage real-time state and translate software actions into dependable physical behaviour.
That is what connected-product development ultimately requires: treating the application, connectivity, firmware and hardware as one product rather than separate pieces.
Building Software Around a Connected Product?
We work on mobile apps, web platforms and backend systems that communicate with real devices and embedded hardware.
- Drafted using AI