{"id":19847051,"url":"https://github.com/polidea/blemulator_flutter","last_synced_at":"2025-05-01T21:31:50.674Z","repository":{"id":35931241,"uuid":"217254362","full_name":"Polidea/blemulator_flutter","owner":"Polidea","description":"BLEmulator Flutter: the Flutter BLE peripheral simulator","archived":false,"fork":false,"pushed_at":"2022-08-03T12:35:21.000Z","size":431,"stargazers_count":70,"open_issues_count":27,"forks_count":36,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-03-20T02:20:26.012Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Polidea.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-10-24T08:51:32.000Z","updated_at":"2024-03-12T13:46:50.000Z","dependencies_parsed_at":"2022-08-08T12:30:28.765Z","dependency_job_id":null,"html_url":"https://github.com/Polidea/blemulator_flutter","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Polidea%2Fblemulator_flutter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Polidea%2Fblemulator_flutter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Polidea%2Fblemulator_flutter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Polidea%2Fblemulator_flutter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Polidea","download_url":"https://codeload.github.com/Polidea/blemulator_flutter/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224278377,"owners_count":17285080,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-12T13:13:17.736Z","updated_at":"2024-11-12T13:13:18.249Z","avatar_url":"https://github.com/Polidea.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/Polidea/blemulator_flutter.svg?branch=master)](https://travis-ci.org/Polidea/blemulator_flutter)\n[![Frontside](https://img.shields.io/static/v1?label=Facilitated%20by\u0026message=frontside.io\u0026color=blue)](#facilitated-by-frontside)\n[![pub package](https://img.shields.io/pub/v/blemulator.svg)](https://pub.dev/packages/blemulator)\n\n![BLEmulator logo](site/logo_Blemulator.png)\n\n# BLEmulator\n\nPlugin for simulating Bluetooth Low Energy peripherals.\n\n**Note:** Works only with [FlutterBleLib](https://github.com/Polidea/FlutterBleLib).\n\nIt imitates the behaviour of [MultiPlatformBleAdapter](https://github.com/Polidea/MultiPlatformBleAdapter) and lets you create simulated peripherals in Dart. \nYour 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.\n\nThe simulation allows you to develop BLE applications on iOS simulator and/or Android emulator, and run automated tests.\n\n## How to use\n\nTo start simulating a BLE peripheral:\n1. obtain an instance of Blemulator\n2. add a SimulatedPeripheral\n3. call _blemulator.simulate()_\n4. call FlutterBleLib's _bleManager.createClient()_\n\n```dart\nBlemulator blemulator = Blemulator();\nblemulator.addSimulatedPeripheral(ExamplePeripheral());\nblemulator.simulate();\n\nBleManager bleManager = BleManager();\nbleManager.createClient(); //this creates an instance of native BLE\n```\n### Defining simple simulated peripheral\nThe following peripheral is based on [Texas Instruments CC2541 SensorTag](https://www.ti.com/tool/CC2541DK-SENSOR).\nTo keep the example clearer, only IR temperature service is simulated.\n```dart\nclass SensorTag extends SimulatedPeripheral {\n  SensorTag(\n      {String id = \"4C:99:4C:34:DE:76\",\n      String name = \"SensorTag\",\n      String localName = \"SensorTag\"})\n      : super(\n            name: name,\n            id: id,\n            advertisementInterval: Duration(milliseconds: 800),\n            services: [\n              SimulatedService(\n                  uuid: \"F000AA00-0451-4000-B000-000000000000\",\n                  isAdvertised: true,\n                  characteristics: [\n                    SimulatedCharacteristic(\n                        uuid: \"F000AA01-0451-4000-B000-000000000000\",\n                        value: Uint8List.fromList([101, 254, 64, 12]),\n                        convenienceName: \"IR Temperature Data\"),\n                    SimulatedCharacteristic(\n                        uuid: \"F000AA02-0451-4000-B000-000000000000\",\n                        value: Uint8List.fromList([0]),\n                        convenienceName: \"IR Temperature Config\"),\n                    SimulatedCharacteristic(\n                        uuid: \"F000AA03-0451-4000-B000-000000000000\",\n                        value: Uint8List.fromList([50]),\n                        convenienceName: \"IR Temperature Period\"),\n                  ],\n                  convenienceName: \"Temperature service\")\n            ]) {\n    scanInfo.localName = localName;\n  }\n\n  @override\n  Future\u003cbool\u003e onConnectRequest() async {\n    await Future.delayed(Duration(milliseconds: 200));\n    return super.onConnectRequest();\n  }\n}\n```\n\nThis creates a peripheral that advertises every 800 milliseconds while peripheral scan is on,\n waits for 200 milliseconds after receiving connection request before agreeing to connect and has a single service \n with three characteristics according to [SensorTag documentation](https://processors.wiki.ti.com/images/a/a8/BLE_SensorTag_GATT_Server.pdf).\n\nThe _convenienceName_ fields are optional and not used by the blemulator itself, but allow you to name created objects for better maintainability.\n\n### Changing advertisement data or scan info\n\nFor 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.\n\nIf you want to have more granular control over what is advertised, simply modify the _scanInfo_ property of the SimulatedPeripheral.\n The _scanInfo_ is broadcasted automatically while peripheral scan is on each _advertisementInterval_.\n \nScanInfo supports following data:\n```dart\nclass ScanInfo {\n  int rssi;\n  bool isConnectable;\n  int txPowerLevel;\n\n  Uint8List manufacturerData;\n  Map\u003cString, Uint8List\u003e serviceData;\n  List\u003cString\u003e serviceUuids;\n\n  String localName;\n  List\u003cString\u003e solicitedServiceUuids;\n  List\u003cString\u003e overflowUuids;\n}\n```\nYou can also provide it in the constructor of the SimulatedPeripheral.\n\n### Custom characteristic behaviour\nBlemulator does most of the heavy lifting for you and takes care of the basic stuff, but there's always more complicated logic.\nIf you need to validate values or writing to one characteristic has to trigger a change in the behaviour of different characteristic,\n you may need to extend SimulatedService or SimulatedCharacteristic classes.\n#### Limiting values supported by characteristic\n\nFollowing is an example of a characteristic that accepts only 0 or 1.\n```dart\nclass ExampleCharacteristic extends SimulatedCharacteristic {\n  ExampleCharacteristic({@required String uuid, String convenienceName})\n      : super(\n            uuid: uuid,\n            value: Uint8List.fromList([0]),\n            convenienceName: convenienceName);\n\n  @override\n  Future\u003cvoid\u003e write(Uint8List value, { bool sendNotification = true }) {\n    int valueAsInt = value[0];\n    if (valueAsInt != 0 \u0026\u0026 valueAsInt != 1) {\n      return Future.error(SimulatedBleError(\n          BleErrorCode.CharacteristicWriteFailed, \"Unsupported value\"));\n    } else {\n      return super.write(value); //this propagates value through the blemulator,\n      // allowing you to react to changes done to this characteristic\n    }\n  }\n}\n```\n\n\n#### Publishing notifications\nThis time peripheral has additional logic. _IR Temperature Config_ characteristic turns the IR thermometer on (1) and off (0).\n 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.\n\n```dart\nclass SensorTag extends SimulatedPeripheral {\n  static const String _serviceUuid = \"F000AA00-0451-4000-B000-000000000000\";\n  static const String _temperatureDataUuid =\n      \"F000AA01-0451-4000-B000-000000000000\";\n  static const String _temperatureConfigUuid =\n      \"F000AA02-0451-4000-B000-000000000000\";\n  static const String _temperaturePeriodUuid =\n      \"F000AA03-0451-4000-B000-000000000000\";\n\n  bool _readingTemperature;\n\n  SensorTag(\n      {String id = \"4B:99:4C:34:DE:77\",\n      String name = \"SensorTag\",\n      String localName = \"SensorTag\"})\n      : super(\n            name: name,\n            id: id,\n            advertisementInterval: Duration(milliseconds: 800),\n            services: [\n              SimulatedService(\n                  uuid: _serviceUuid,\n                  isAdvertised: true,\n                  characteristics: [\n                    SimulatedCharacteristic(\n                      uuid: _temperatureDataUuid,\n                      value: Uint8List.fromList([0, 0, 0, 0]),\n                      convenienceName: \"IR Temperature Data\",\n                      isWritableWithoutResponse: false,\n                      isWritableWithResponse: false,\n                      isNotifiable: true,\n                    ),\n                    SimulatedCharacteristic(\n                        uuid: _temperatureConfigUuid,\n                        value: Uint8List.fromList([0]),\n                        convenienceName: \"IR Temperature Config\"),\n                    SimulatedCharacteristic(\n                        uuid: _temperaturePeriodUuid,\n                        value: Uint8List.fromList([50]),\n                        convenienceName: \"IR Temperature Period\"),\n                  ],\n                  convenienceName: \"Temperature service\"),\n            ]) {\n    scanInfo.localName = localName;\n\n    getCharacteristicForService(_serviceUuid, _temperatureConfigUuid)\n        .monitor()\n        .listen((value) {\n      _readingTemperature = value[0] == 1;\n    });\n\n    _emitTemperature();\n  }\n\n  void _emitTemperature() async {\n    while (true) {\n      Uint8List delayBytes = await getCharacteristicForService(\n              _serviceUuid, _temperaturePeriodUuid)\n          .read();\n      int delay = delayBytes[0] * 10;\n      await Future.delayed(Duration(milliseconds: delay));\n      SimulatedCharacteristic temperatureDataCharacteristic =\n                  getCharacteristicForService(_serviceUuid, _temperatureDataUuid);\n      if (temperatureDataCharacteristic.isNotifying) {\n        if (_readingTemperature) {\n          temperatureDataCharacteristic\n              .write(Uint8List.fromList([101, 254, 64, Random().nextInt(255)]));\n        } else {\n          temperatureDataCharacteristic.write(Uint8List.fromList([0, 0, 0, 0]));\n        }\n      }\n    }\n  }\n\n  @override\n  Future\u003cbool\u003e onConnectRequest() async {\n    await Future.delayed(Duration(milliseconds: 200));\n    return super.onConnectRequest();\n  }\n}\n```\nThe example above could be refactored to a custom SimulatedService with all the\n logic that handles cross-characteristic mechanisms and a simplified SimulatedPeripheral that takes an instance of the newly created class.\n\n### Descriptors\n\nCharacteristics may hold descriptors using the optional parameter `descriptors`.\n\n```dart\nSimulatedCharacteristic(uuid: \"F000AA13-0451-4000-B000-000000000000\",\n                        value: Uint8List.fromList([30]),\n                        descriptors: [\n                          SimulatedDescriptor(\n                            uuid: \"F0002901-0451-4000-B000-000000000000\",\n                            value: Uint8List.fromList([0]),\n                            convenienceName:\n                                \"Example descriptor (Characteristic \"\n                                \"User Description)\",\n                          ),\n                        ],\n                        convenienceName: \"Accelerometer Period\");\n```\n\n### Working example\nIf you'd like to poke around some more, clone the repository and run the provided example.\n\nYou can also check out the [Simplified SensorTag implementation](https://github.com/Polidea/blemulator_flutter/blob/master/example/lib/example_peripherals/sensor_tag.dart)\n\n## Facilitated by Frontside \n[Frontside](https://github.com/thefrontside) provided architectural advice and financial support for this library on behalf of [Resideo](https://github.com/resideo).\n\n## Maintained by\nThis library is maintained by [Polidea](https://www.polidea.com/?utm_source=Github\u0026utm_medium=Npaid\u0026utm_campaign=Main\u0026utm_term=Code\u0026utm_content=GH_NOP_MPG_COD_BLM001)\n\n[Contact us](https://www.polidea.com/project/?utm_source=Github\u0026utm_medium=Npaid\u0026utm_campaign=Kontakt\u0026utm_term=Code\u0026utm_content=GH_NOP_KKT_COD_BLM001)\n\n[Learn more about Polidea's BLE services](https://www.polidea.com/services/ble/?utm_source=Github\u0026utm_medium=Npaid\u0026utm_campaign=Tech_BLE\u0026utm_term=Code\u0026utm_content=GH_NOP_BLE_COD_BLM001).\n\n### Maintainers\n\n## License\nCopyright 2019 Polidea Sp. z o.o\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\nhttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpolidea%2Fblemulator_flutter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpolidea%2Fblemulator_flutter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpolidea%2Fblemulator_flutter/lists"}