If you are building a Bluetooth Low Energy peripheral, the most natural test peer is the device your customers will actually use: a smartphone.
It runs the same operating system your users run, executes a real Bluetooth stack, and exhibits the same quirks that real users will encounter. Testing against a real phone feels like testing against reality, and intuitively it seems like the right choice. It is not. For automated testing, a real smartphone is one of the worst test peers you can choose, and the reasons are worth understanding because they reveal something important about what test automation actually requires.
This article is about why simulating the phone — using an HCI dongle running a programmable Bluetooth host stack on your test PC — is almost always the right answer for automation, when a real phone is still needed despite this, and what changes when you adopt the simulated approach.
What real smartphones are actually like as test peers
Start with the practical. A smartphone is a complex consumer device that was not designed for use as test infrastructure. Its scheduler is not deterministic; the operating system can preempt your test app at any moment to handle a notification, a background task, or its own internal housekeeping. Its Bluetooth stack is buried under several layers of operating system permissions and may behave differently between releases of the OS, between manufacturers, and between Android skins. Its battery management policies will sometimes disconnect Bluetooth devices to save power, regardless of what your test is doing. Its physical state — charged, screen on, app foregrounded — affects what timing behaviour you observe.
Now imagine running an automated test suite against this. Each test starts by ensuring the phone is in a known state: app installed, app launched, Bluetooth turned on, no other apps interfering, screen on so the OS does not kill the app, charger connected so the test does not drain the battery. The test framework has to handle the phone getting stuck in some unrecoverable state and rebooting it. It has to handle the OS prompting for permissions mid-test. It has to handle iOS automation, which is genuinely difficult because Apple deliberately makes it so, and Android automation, which is fragile in different ways across different Android versions and OEM customisations. Multiple parallel tests need multiple phones, each with its own setup ritual and its own collection of subtle behavioural differences.
After all of this, the test results still vary depending on the phone’s mood. A test that passes on Tuesday fails on Wednesday because the OS pushed an update overnight that changed Bluetooth scheduling behaviour. A test that passes when the phone is plugged in fails when it is on battery, because the power management is more aggressive on battery. A test that takes thirty seconds on a Pixel 6 takes forty-five on an iPhone 12, not because anything in the device under test changed, but because the two phones have different scheduling characteristics and different Bluetooth stack timings.
This is not a hypothetical complaint. It is the daily reality of teams that build their BLE automation around real phones, and it explains why those teams’ test suites tend to be small, slow, and only run before releases. The infrastructure overhead of keeping the phones operational consumes the engineering capacity that should have been spent expanding the test coverage, and the result is a programme that never quite reaches the level of reliability that justifies trusting the suite as a release gate.

What the BLE stack actually looks like
To understand the alternative, it is worth taking a moment on the BLE architecture, because the trick that makes simulation possible depends on a specific structural property of how Bluetooth is built.
A Bluetooth Low Energy implementation is split into two halves: a controller and a host. The controller handles the lowest-level radio behaviour — the link layer, the physical layer, the timing-critical packet exchange that has to happen at exactly the right moments to maintain a connection. The host handles everything above that — the GATT protocol, the attribute database, the security manager, the connection management logic, the application-level Bluetooth APIs your code calls.
Between the two halves is a standardised interface called HCI, the Host-Controller Interface. HCI is the same on every Bluetooth-compliant system, by specification. The controller emits HCI events; the host issues HCI commands. As long as both halves speak HCI correctly, they can be implemented independently, by different vendors, on different processors, and they will work together. This is not an accident of the Bluetooth design — it is a deliberate architectural choice that allows controllers and hosts to be sourced separately and combined freely.
This split is usually invisible. On a smartphone, the Bluetooth chip in the phone runs the controller, and the operating system runs the host. The HCI traffic between them is internal to the phone and not exposed. On an embedded device, the controller and host typically run on the same chip, and the HCI is again internal. Most Bluetooth developers can build entire careers without explicitly thinking about HCI, because both halves come pre-integrated in whatever chipset they are using.
But HCI does not have to be hidden. It is a standardised, public protocol, and Bluetooth USB dongles exist that expose it directly. When you plug a Bluetooth dongle into a Linux PC and run BlueZ, the dongle is the controller, the Linux kernel is the host, and the HCI traffic flows between them over USB. The dongle is, in effect, a Bluetooth radio that you can drive with any host stack you choose.
What “simulating a smartphone” actually means
Now the punchline. If a smartphone’s Bluetooth peer-ness is just the combination of a Bluetooth controller (the chip in the phone) and a Bluetooth host stack (the OS-level software), then you can replicate it with the equivalent components: an HCI dongle (a Bluetooth controller you can plug in) and a host stack you control (a Python implementation, or BlueZ scripted from Python, or one of several other options).
From your device under test’s perspective, the over-the-air Bluetooth communication is indistinguishable from a real phone. The dongle emits the same advertising packets, scans, makes connections, and exchanges GATT messages as a real phone would. The link-layer behaviour is identical, because the link layer is implemented in the controller chip — the same kind of chip the phone has, often the exact same chip family. The only thing that has changed is what is sitting on the other side of the HCI: a deterministic Python script instead of an unpredictable mobile operating system.
This is not approximate simulation. It is real Bluetooth, with a programmable peer. The dongle is a real Bluetooth radio. The host stack is a real Bluetooth implementation. The communication is real over-the-air, with real RF, real link-layer timing, real connection management. What you have replaced is the unpredictable part — the operating system that you do not control — with a deterministic part that you do.
It is worth dwelling on this, because the framing matters. People who hear “simulate the phone” sometimes assume the simulation is fake in some sense — that the device under test is somehow being lied to or that the test is missing something. It is not. The device under test is exchanging real Bluetooth packets with a real Bluetooth radio. The packet contents and timing are identical to what a phone would produce. The only thing that is “simulated” is the abstraction layer above HCI, which is the layer the device under test cannot see anyway.

What this gives you that a real phone cannot
The advantages are large and worth enumerating individually, because each one solves a specific problem that real-phone automation cannot solve.
Determinism comes first. The simulated host runs your script. There is no operating system scheduler to fight. There are no background tasks to interrupt your test. There are no permission prompts. The behaviour of the test peer is exactly what your script tells it to be, every time, on every run. A test that passed yesterday will pass today unless something in the device under test changed, which is the property you wanted from your test framework all along.
Timing precision is the second. A real phone’s Bluetooth stack has scheduling jitter measured in tens of milliseconds, sometimes more, because the OS scheduler can defer Bluetooth work in favour of other tasks. A scripted host stack has jitter measured in microseconds, because it is executing your code directly on a PC without an unpredictable OS scheduler in between. For tests that depend on timing — connection interval verification, supervision timeout testing, latency measurement — this is the difference between a reliable test and a flaky one.
Repeatability is the third. A scripted host stack starts in the same state every time. Connect, run the test, disconnect, reset the script — and the next run begins identically. There is no accumulated state from previous tests, no OS-level cache that affects the next connection, no leftover bonding information that needs to be cleared. The test environment is genuinely stateless in a way that no real phone can match, and stateless test environments are the ones that produce trustworthy results.
Parallelism is the fourth. One PC with multiple HCI dongles can run multiple simulated phones simultaneously, each on its own dongle, each running its own test. The same PC can simulate many peripherals at once, too, presenting different services and behaviours to a single device under test. A test that requires a phone connected to ten devices, or ten phones connected to one device, becomes a configuration choice rather than a hardware procurement project. The economics of scaling up the test suite change qualitatively.
Behaviour you cannot get from real phones is the fifth, and the most powerful capability — the one most teams underuse. A scripted host stack can do things that a real phone, by design, will never do: send malformed GATT responses, disconnect at protocol-spec-forbidden moments, request connection parameters that no production OS would request, send notifications faster than any real app would, deliberately violate the specification in specific documented ways. These are not edge cases for fun; they are the inputs your firmware will encounter in the wild from buggy peers, malicious actors, or RF errors. The simulated peer is the only way to test that handling systematically, because no real test peer can be programmed to misbehave.
When you still need a real phone
Simulation is the right default for automation, but it does not eliminate the case for real-phone testing entirely. There are categories of testing where the real phone’s quirks are exactly what you want to test against, and being honest about which categories those are is part of getting the overall strategy right.
Interoperability is the obvious one. If your customers will use your device with a specific phone model, you need to know that the device works with that phone in particular, not with an abstract specification of what a phone should do. iOS and Android Bluetooth stacks have undocumented behaviours that occasionally trip up devices that are otherwise specification-compliant. Real-phone interoperability tests catch these. They should run regularly, but they do not need to run on every commit, and they should not be the foundation of the test suite — they are a separate, slower-cadence layer that complements the per-commit simulated testing.
User-experience verification is another. The pairing flow that takes the user through a series of screens, the visual feedback when a connection is established, the latency of a button press translating to a device action — these are aspects of the product that exist on the phone, not on the device. They need to be tested on real phones, by real testers or by mobile UI automation, and that work is genuinely complementary to the simulated-peer testing of the device’s BLE behaviour. The two layers are testing different things.
Mobile application testing is the third. If you are testing the mobile app, you want it running on the platform your users will use. The simulated peer in this case is the device under test from the app’s perspective — and depending on the architecture, it may be useful to simulate either side or both, with simulated devices presenting controlled BLE behaviour to a real app running on a real phone.
The right framing is layered: simulated peers for the high-volume, high-frequency automation that catches regressions and verifies behaviour; real phones for the lower-frequency interoperability and UX verification work that confirms the simulated tests reflect reality. Each layer does what it is best at, and the test suite is the union of the two.

The shift this enables
The deeper consequence of moving to simulated peers is that BLE automation stops being a bottleneck. Tests run in seconds rather than minutes. They run in parallel rather than serialised on a phone rack. They produce reliable results that the team trusts. They cover scenarios that real-phone testing could never reach, because they include the negative-input cases and the timing-precise cases and the simultaneous-multiple-peer cases that no real phone can produce. And the entire BLE feature set becomes part of the per-commit feedback loop, not the once-per-release manual run.
This is what good wireless automation feels like, and the choice of test peer is what unlocks it. The temptation to test against real phones because real phones are what users use is understandable, but it is the wrong frame. Users use real phones to interact with the device, and that experience deserves its own dedicated testing layer. Your test framework, however, is not a user. It is infrastructure, and infrastructure deserves test peers that are designed for the job — peers that are deterministic, parallelisable, programmable, and capable of producing inputs that real phones cannot. An HCI dongle and a Python script are not a compromise. They are the right tool.
needCode builds production-grade automated test infrastructure for embedded wireless products, including BLE host stack simulation that runs on test PCs and replaces real phones in the per-commit pipeline. We have implemented this approach across BLE mesh, mobile-app testing, and multi-protocol IoT engagements. If you want to talk through what it would take to remove smartphones from your automation flow, we are happy to walk you through it.
Book a free discovery call or get in touch
Further reading
- Bluetooth Low Energy Encryption — the SMP/GATT-layer mechanics the scripted host can probe directly; pairs with the “behaviour you cannot get from real phones” argument
- BLE Over-the-Air Firmware Updates: How to Ship Updates That Don’t Brick Devices — OTA tests are one of the biggest practical wins from simulated peers (controlled transfer interruption)
- Anatomy of a Production OTA Pipeline — the release pipeline that runs the simulated-peer suite as a per-commit gate
- Bluetooth Low Energy Power Optimization — power optimization needs the timing precision (microsecond jitter) the scripted host provides; a real phone makes those measurements impossible

