Coder Social home page Coder Social logo

cristoferdomingues / blemulator_flutter Goto Github PK

View Code? Open in Web Editor NEW

This project forked from polidea/blemulator_flutter

0.0 1.0 0.0 6.45 MB

BLEmulator Flutter: the Flutter BLE peripheral simulator

License: Other

Java 21.89% Kotlin 0.08% Ruby 0.90% Swift 0.09% Objective-C 29.14% Dart 47.52% C 0.38%

blemulator_flutter's Introduction

Build Status Frontside pub package

BLEmulator logo

BLEmulator

Plugin for simulating Bluetooth Low Energy peripherals.

Note: Works only with FlutterBleLib.

It imitates the behaviour of MultiPlatformBleAdapter and lets you create simulated peripherals in Dart. Your Flutter code for handling BLE will not be aware that it doesn't run on the real implementation, since the simulation is plugged in beneath the native bridge of FlutterBleLib.

The simulation allows you to develop BLE applications on iOS simulator and/or Android emulator, and run automated tests.

How to use

To start simulating a BLE peripheral:

  1. obtain an instance of Blemulator
  2. add a SimulatedPeripheral
  3. call blemulator.simulate()
  4. call FlutterBleLib's bleManager.createClient()
Blemulator blemulator = Blemulator();
blemulator.addSimulatedPeripheral(ExamplePeripheral());
blemulator.simulate();

BleManager bleManager = BleManager();
bleManager.createClient(); //this creates an instance of native BLE

Defining simple simulated peripheral

The following peripheral is based on Texas Instruments CC2541 SensorTag. To keep the example clearer, only IR temperature service is simulated.

class SensorTag extends SimulatedPeripheral {
  SensorTag(
      {String id = "4C:99:4C:34:DE:76",
      String name = "SensorTag",
      String localName = "SensorTag"})
      : super(
            name: name,
            id: id,
            advertisementInterval: Duration(milliseconds: 800),
            services: [
              SimulatedService(
                  uuid: "F000AA00-0451-4000-B000-000000000000",
                  isAdvertised: true,
                  characteristics: [
                    SimulatedCharacteristic(
                        uuid: "F000AA01-0451-4000-B000-000000000000",
                        value: Uint8List.fromList([101, 254, 64, 12]),
                        convenienceName: "IR Temperature Data"),
                    SimulatedCharacteristic(
                        uuid: "F000AA02-0451-4000-B000-000000000000",
                        value: Uint8List.fromList([0]),
                        convenienceName: "IR Temperature Config"),
                    SimulatedCharacteristic(
                        uuid: "F000AA03-0451-4000-B000-000000000000",
                        value: Uint8List.fromList([50]),
                        convenienceName: "IR Temperature Period"),
                  ],
                  convenienceName: "Temperature service")
            ]) {
    scanInfo.localName = localName;
  }

  @override
  Future<bool> onConnectRequest() async {
    await Future.delayed(Duration(milliseconds: 200));
    return super.onConnectRequest();
  }
}

This creates a peripheral that advertises every 800 milliseconds while peripheral scan is on, waits for 200 milliseconds after receiving connection request before agreeing to connect and has a single service with three characteristics according to SensorTag documentation.

The convenienceName fields are optional and not used by the blemulator itself, but allow you to name created objects for better maintainability.

Changing advertisement data or scan info

For your convenience you can mark SimulatedService as advertised, but be aware that this doesn't validate the size of advertised services array inside advertisement data.

If you want to have more granular control over what is advertised, simply modify the scanInfo property of the SimulatedPeripheral. The scanInfo is broadcasted automatically while peripheral scan is on each advertisementInterval.

ScanInfo supports following data:

class ScanInfo {
  int rssi;
  bool isConnectable;
  int txPowerLevel;

  Uint8List manufacturerData;
  Map<String, Uint8List> serviceData;
  List<String> serviceUuids;

  String localName;
  List<String> solicitedServiceUuids;
  List<String> overflowUuids;
}

You can also provide it in the constructor of the SimulatedPeripheral.

Custom characteristic behaviour

Blemulator does most of the heavy lifting for you and takes care of the basic stuff, but there's always more complicated logic. If you need to validate values or writing to one characteristic has to trigger a change in the behaviour of different characteristic, you may need to extend SimulatedService or SimulatedCharacteristic classes.

Limiting values supported by characteristic

Following is an example of a characteristic that accepts only 0 or 1.

class ExampleCharacteristic extends SimulatedCharacteristic {
  ExampleCharacteristic({@required String uuid, String convenienceName})
      : super(
            uuid: uuid,
            value: Uint8List.fromList([0]),
            convenienceName: convenienceName);

  @override
  Future<void> write(Uint8List value, { bool sendNotification = true }) {
    int valueAsInt = value[0];
    if (valueAsInt != 0 && valueAsInt != 1) {
      return Future.error(SimulatedBleError(
          BleErrorCode.CharacteristicWriteFailed, "Unsupported value"));
    } else {
      return super.write(value); //this propagates value through the blemulator,
      // allowing you to react to changes done to this characteristic
    }
  }
}

Publishing notifications

This time peripheral has additional logic. IR Temperature Config characteristic turns the IR thermometer on (1) and off (0). Regardless of that the IR Temperature Data emits data each (IR Temperature Period value times 10) milliseconds (as per specification linked above) and that may be actual reading or zero.

class SensorTag extends SimulatedPeripheral {
  static const String _serviceUuid = "F000AA00-0451-4000-B000-000000000000";
  static const String _temperatureDataUuid =
      "F000AA01-0451-4000-B000-000000000000";
  static const String _temperatureConfigUuid =
      "F000AA02-0451-4000-B000-000000000000";
  static const String _temperaturePeriodUuid =
      "F000AA03-0451-4000-B000-000000000000";

  bool _readingTemperature;

  SensorTag(
      {String id = "4B:99:4C:34:DE:77",
      String name = "SensorTag",
      String localName = "SensorTag"})
      : super(
            name: name,
            id: id,
            advertisementInterval: Duration(milliseconds: 800),
            services: [
              SimulatedService(
                  uuid: _serviceUuid,
                  isAdvertised: true,
                  characteristics: [
                    SimulatedCharacteristic(
                      uuid: _temperatureDataUuid,
                      value: Uint8List.fromList([0, 0, 0, 0]),
                      convenienceName: "IR Temperature Data",
                      isWritableWithoutResponse: false,
                      isWritableWithResponse: false,
                      isNotifiable: true,
                    ),
                    SimulatedCharacteristic(
                        uuid: _temperatureConfigUuid,
                        value: Uint8List.fromList([0]),
                        convenienceName: "IR Temperature Config"),
                    SimulatedCharacteristic(
                        uuid: _temperaturePeriodUuid,
                        value: Uint8List.fromList([50]),
                        convenienceName: "IR Temperature Period"),
                  ],
                  convenienceName: "Temperature service"),
            ]) {
    scanInfo.localName = localName;

    getCharacteristicForService(_serviceUuid, _temperatureConfigUuid)
        .monitor()
        .listen((value) {
      _readingTemperature = value[0] == 1;
    });

    _emitTemperature();
  }

  void _emitTemperature() async {
    while (true) {
      Uint8List delayBytes = await getCharacteristicForService(
              _serviceUuid, _temperaturePeriodUuid)
          .read();
      int delay = delayBytes[0] * 10;
      await Future.delayed(Duration(milliseconds: delay));
      SimulatedCharacteristic temperatureDataCharacteristic =
                  getCharacteristicForService(_serviceUuid, _temperatureDataUuid);
      if (temperatureDataCharacteristic.isNotifying) {
        if (_readingTemperature) {
          temperatureDataCharacteristic
              .write(Uint8List.fromList([101, 254, 64, Random().nextInt(255)]));
        } else {
          temperatureDataCharacteristic.write(Uint8List.fromList([0, 0, 0, 0]));
        }
      }
    }
  }

  @override
  Future<bool> onConnectRequest() async {
    await Future.delayed(Duration(milliseconds: 200));
    return super.onConnectRequest();
  }
}

The example above could be refactored to a custom SimulatedService with all the logic that handles cross-characteristic mechanisms and a simplified SimulatedPeripheral that takes an instance of the newly created class.

Descriptors

Characteristics may hold descriptors using the optional parameter descriptors.

SimulatedCharacteristic(uuid: "F000AA13-0451-4000-B000-000000000000",
                        value: Uint8List.fromList([30]),
                        descriptors: [
                          SimulatedDescriptor(
                            uuid: "F0002901-0451-4000-B000-000000000000",
                            value: Uint8List.fromList([0]),
                            convenienceName:
                                "Example descriptor (Characteristic "
                                "User Description)",
                          ),
                        ],
                        convenienceName: "Accelerometer Period");

Working example

If you'd like to poke around some more, clone the repository and run the provided example.

You can also check out the Simplified SensorTag implementation

Facilitated by Frontside

Frontside provided architectural advice and financial support for this library on behalf of Resideo.

Maintained by

This library is maintained by Polidea

Contact us

Learn more about Polidea's BLE services.

Maintainers

License

Copyright 2019 Polidea Sp. z o.o

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

blemulator_flutter's People

Contributors

mikolak avatar tomolv avatar bartoszwilk avatar pawelbyszewski avatar martawoldanska avatar bntnam avatar tomstokes avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.