Skip to main content

ble_device_simulator 0.1.1 copy "ble_device_simulator: ^0.1.1" to clipboard
ble_device_simulator: ^0.1.1 copied to clipboard

Simulated Bluetooth LE heart-rate, blood pressure, SpO2, thermometer, cycling, running and scale devices that send real GATT bytes. Test BLE apps without hardware.

ble_device_simulator #

pub package pub points likes CI License: MIT

Build and test Bluetooth LE health and fitness apps without hardware.

Simulated heart-rate straps, blood pressure cuffs, thermometers, pulse oximeters, power meters, foot pods and scales that send the exact bytes real devices send, following the Bluetooth SIG specs.

  • Write tests for BLE code: in CI, on every developer's laptop, with no device in a drawer somewhere
  • Reproduce edge cases on demand: a slipped strap, a fever, low oxygen, a flat battery, a dropped connection
  • Deterministic: the same seed always gives the same readings, and simulated time only moves when you say so
  • Real bytes: every notification is checked in this package's tests by parsing it with ble_gatt_parser
  • Pure Dart: works in Flutter widget tests, plain Dart tests and on the web
final strap = SimulatedHeartRateMonitor()..connect();

strap.notifications(GattCharacteristicIds.heartRateMeasurement).listen((bytes) {
  print(GattParser.parse('2a37', bytes)); // HeartRateMeasurement(bpm: 74, ...)
});

strap.tick();               // one second of simulated time
strap.skinContact = false;  // the strap slips off
strap.batteryLevel = 5;     // battery warning
strap.disconnect();         // out of range

Install #

dart pub add dev:ble_device_simulator

Add it as a regular dependency instead if you also want simulated devices in a demo or debug build.

Devices #

Class Service Sends Edge cases
SimulatedHeartRateMonitor Heart Rate (0x180D) bpm and RR-intervals every second skinContact = false, custom bpm range
SimulatedBloodPressureMonitor Blood Pressure (0x1810) A reading when you call measure() Custom systolic and diastolic ranges
SimulatedThermometer Health Thermometer (0x1809) Ear temperature every second fever = true
SimulatedPulseOximeter Pulse Oximeter (0x1822) SpO2, pulse and perfusion index lowOxygen = true
SimulatedPowerMeter Cycling Power (0x1818) Watts and crank revolutions, for cadence Custom power and rpm ranges
SimulatedRunningPod Running Speed and Cadence (0x1814) Speed, cadence and distance Custom speed range
SimulatedWeightScale Weight Scale (0x181D) A measurement when you call weigh() Optional BMI and height

Every device also has Device Information (manufacturer, model, firmware) and Battery (0x180F), with read(), connect(), disconnect(), connectionState, batteryLevel and services.

Testing a Flutter app #

Put a small interface between your app and your BLE plugin, and use the simulator in tests:

abstract class HeartRateSource {
  Stream<List<int>> get measurements;
}

/// In the app: flutter_blue_plus, flutter_reactive_ble or your own plugin.
class BluetoothHeartRateSource implements HeartRateSource {
  BluetoothHeartRateSource(this.characteristic);
  final BluetoothCharacteristic characteristic;

  @override
  Stream<List<int>> get measurements => characteristic.onValueReceived;
}

/// In tests and demos.
class SimulatedHeartRateSource implements HeartRateSource {
  SimulatedHeartRateSource(this.device);
  final SimulatedHeartRateMonitor device;

  @override
  Stream<List<int>> get measurements =>
      device.notifications(GattCharacteristicIds.heartRateMeasurement);
}
testWidgets('shows a warning when the strap slips', (tester) async {
  final strap = SimulatedHeartRateMonitor()..connect();
  await tester.pumpWidget(HeartRateScreen(source: SimulatedHeartRateSource(strap)));

  strap.tick();
  await tester.pump();
  expect(find.textContaining('bpm'), findsOneWidget);

  strap.skinContact = false;
  strap.tick();
  await tester.pump();
  expect(find.text('Check your strap'), findsOneWidget);
});

Time #

Simulated time only moves when you call tick(), which advances one second and sends that second's notifications synchronously. That keeps tests fast and predictable. For demos, start(interval: ...) ticks on a timer: a shorter interval runs simulated time faster. Call stop() or dispose() when you're done.

Encoders #

The devices are built on GattEncoder, which you can also use directly to build any measurement by hand:

final bytes = GattEncoder.bloodPressure(
  systolic: 142,
  diastolic: 91,
  pulseRate: 88,
  timestamp: DateTime(2026, 1, 1, 8),
);

It covers heart rate, blood pressure, temperature, pulse oximetry, weight, cycling speed and cadence, cycling power, running speed and cadence, battery level and strings, plus the IEEE 11073 SFLOAT and FLOAT number formats.

About the author #

Built by Chandra ObulaReddy, a Flutter architect who has shipped Bluetooth LE and wearable integrations for safety, healthcare and fitness products. See also ble_gatt_parser, which parses the bytes these devices send.

1
likes
160
points
88
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Simulated Bluetooth LE heart-rate, blood pressure, SpO2, thermometer, cycling, running and scale devices that send real GATT bytes. Test BLE apps without hardware.

Repository (GitHub)
View/report issues

Topics

#bluetooth #ble #testing #health #fitness

License

MIT (license)

Dependencies

meta

More

Packages that depend on ble_device_simulator