https://github.com/tidev/appcelerator.ble
A collection of API's to connect and communicate with BLE compatible devices via Bluetooth LE
https://github.com/tidev/appcelerator.ble
appcelerator appcelerator-titanium ble bluetooth-low-energy javascript titanium-mobile
Last synced: 7 months ago
JSON representation
A collection of API's to connect and communicate with BLE compatible devices via Bluetooth LE
- Host: GitHub
- URL: https://github.com/tidev/appcelerator.ble
- Owner: tidev
- License: other
- Created: 2020-07-07T07:59:43.000Z (over 5 years ago)
- Default Branch: master
- Last Pushed: 2024-03-06T21:49:19.000Z (almost 2 years ago)
- Last Synced: 2024-05-01T11:49:16.645Z (over 1 year ago)
- Topics: appcelerator, appcelerator-titanium, ble, bluetooth-low-energy, javascript, titanium-mobile
- Language: JavaScript
- Homepage: https://titaniumsdk.com/api/modules/ble.html
- Size: 2.38 MB
- Stars: 7
- Watchers: 13
- Forks: 3
- Open Issues: 31
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
README
# Appcelerator Bluetooth Low Energy Module
- This module brings Bluetooth Low Energy into the mobile apps for titanium app developers.
- Using Bluetooth Low Energy module, developers can bring feature like:
- Act as BLE Central :
- Central can scan nearby peripheral, connect and exchange data with the peripherals
- Central can subscribe with peripheral to get latest updates for peripheral
- Act as BLE Peripheral:
- Peripheral can advertise services, connect and exchange data with multiple central.
- Use L2CAP Channel:
- L2CAP is introduced with IOS 11 and Android 10, its used to transfer large amount of data between central and
peripheral at real time.
- Main use case addressed by this module is Exchange of Data and Communicating with Central and
Peripherals that supports Bluetooth Low Energy.
## Getting Started
### Android
- Set the ``` ``` element in tiapp.xml, such as this:
``` xml
appcelerator.ble
```
- To access this module from JavaScript, you would do the following:
``` js
var BLE = require("appcelerator.ble");
```
The BLE variable is a reference to the Module object.
### iOS
- Edit the `plist` with following `uses-permission` element to the ios plist section of the
tiapp.xml file.
``` xml
NSBluetoothAlwaysUsageDescription
usage description string
NSBluetoothPeripheralUsageDescription
usage description string
```
- If your app needs to run in background to perform certain Bluetooth-related tasks, Edit the `plist` with following `uses-permission` element to the ios plist section of the
tiapp.xml file.
``` xml
UIBackgroundModes
bluetooth-central
bluetooth-peripheral
```
- Set the ``` ``` element in tiapp.xml, such as this:
- Edit the `plist` with following `uses-permission` element to the ios plist section, if your are adding iBeacon Scan
``` xml
NSLocationWhenInUseUsageDescription
Allow Location permission
NSLocationAlwaysUsageDescription
Allow Location permission
```
- Set the ``` ``` element in tiapp.xml, such as this:
``` xml
appcelerator.ble
```
- To access this module from JavaScript, you would do the following:
``` js
var BLE = require("appcelerator.ble");
```
The BLE variable is a reference to the Module object.
# Act As Central Application
## Follow basic steps to create Central application:
- Use `initCentralManager` to create Central Manager
``` js
var centralManager = BLE.initCentralManager();
```
- Check for `didUpdateState` event for `centralManager` status
- Once `centralManager` is in `BLE.MANAGER_STATE_POWERED_ON` state, scan for peripherals using `startScan`
``` js
centralManager.startScan();
```
- Use `peripherals` property to get all discovered peripherals
``` js
var peripherals = centralManager.peripherals;
```
- Use `connect` to connect to peripheral
``` js
centralManager.connectPeripheral({
peripheral: peripheral,
options: {
[BLE.CONNECT_PERIPHERAL_OPTIONS_KEY_NOTIFY_ON_CONNECTION]: true,
[BLE.CONNECT_PERIPHERAL_OPTIONS_KEY_NOTIFY_ON_DISCONNECTION]: true
}
});
```
- Use `isConnected` to check if connected
``` js
peripheral.isConnected
```
- Use `discoverServices` to discover services
``` js
peripheral.discoverServices();
```
result will be return in `didDiscoverServices` event
``` js
peripheral.addEventListener('didDiscoverServices', function (e) {});
```
- Use `discoverCharacteristics`
``` js
peripheral.discoverCharacteristics({
service: service
});
```
result will be return in `didDiscoverCharacteristics` event
``` js
connectedPeripheral.addEventListener('didDiscoverCharacteristics', function (e) {});
```
- Use `subscribeToCharacteristic` and `unsubscribeFromCharacteristic` to subscribe or unsubscribe
``` js
peripheral.subscribeToCharacteristic({
characteristic: charactersticObject
});
peripheral.unsubscribeFromCharacteristic({
characteristic: charactersticObject
});
```
- Use `cancelPeripheralConnection` to disconnect the connection
``` js
centralManager.cancelPeripheralConnection({ peripheral: peripheral });
```
- As the module currently provides support to act only as central for the Android, hence to test the example application, user can use any heart-rate peripheral
or the peripheral simulator in order to do the connection and data-exchange with the central.
## Follow basic steps to create Central application and use Channel for communication:
- Use `initCentralManager` to create Central Manager
``` js
var centralManager = BLE.initCentralManager();
```
- Check for `didUpdateState` event for `centralManager` status
- Once `centralManager` is in `BLE.MANAGER_STATE_POWERED_ON` state, scan for perpherals using `startScan`
``` js
centralManager.startScan();
```
- Use `peripherals` property to get all discovered peripherals
``` js
var peripherals = centralManager.peripherals;
```
- Use `connect` to connect to peripheral
``` js
centralManager.connectPeripheral({
peripheral: peripheral,
options: {
[BLE.CONNECT_PERIPHERAL_OPTIONS_KEY_NOTIFY_ON_CONNECTION]: true,
[BLE.CONNECT_PERIPHERAL_OPTIONS_KEY_NOTIFY_ON_DISCONNECTION]: true
}
});
```
- Use `isConnected` to check if connected
``` js
peripheral.isConnected
```
- Use `discoverServices` to discover services
``` js
peripheral.discoverServices();
```
result will be return in `didDiscoverServices` event
``` js
peripheral.addEventListener('didDiscoverServices', function (e) {});
```
- Use `discoverCharacteristics`
``` js
peripheral.discoverCharacteristics({
service: service
});
```
result will be return in `didDiscoverCharacteristics` event
``` js
connectedPeripheral.addEventListener('didDiscoverCharacteristics', function (e) {});
```
- Use `subscribeToCharacteristic` and `unsubscribeFromCharacteristic` to subscribe or unsubscribe
``` js
peripheral.subscribeToCharacteristic({
characteristic: charactersticObject
});
peripheral.unsubscribeFromCharacteristic({
characteristic: charactersticObject
});
```
- Get `psmIdentifier` from `didUpdateValueForCharacteristic` event and open `channel`
``` js
peripheral.addEventListener('didUpdateValueForCharacteristic', function (e) {
if (e.errorCode !== null) {
alert('Error while didUpdateValueForCharacteristic' + e.errorCode + '/' + e.errorDomain + '/' + e.errorDescription);
return;
}
let value = e.value.toString();
if (value) {
e.sourcePeripheral.openL2CAPChannel({
psmIdentifier: Number(e.value.toString())
});
}
});
```
- Get `channel` object from `didOpenChannel` event and set event `onDataReceived` for received data and `onStreamError` for stream errors
``` js
connectedPeripheral.addEventListener('didOpenChannel', function (e) {
if (e.errorCode !== null) {
alert('Error while opening channel' + e.errorCode + '/' + e.errorDomain + '/' + e.errorDescription);
return;
}
channel = e.channel;
channel.addEventListener('onDataReceived', function (e) {
var data = e.data;
});
channel.addEventListener('onStreamError', function (e) {
alert('Error ' + e.errorCode + '/' + e.errorDomain + '/' + e.errorDescription);
});
});
```
- Use `write` function from channel to write values
``` js
var newBuffer = Ti.createBuffer({ value: 'hello world' });
channel.write({
data: newBuffer
});
```
- Use `cancelPeripheralConnection` to disconnect the connection
``` js
centralManager.cancelPeripheralConnection({ peripheral: peripheral });
```
- Use `close` function to close channel
``` js
channel.close();
```
# Act As Peripheral Application
## Follow basic steps to create Peripheral application:
- Use `initPeripheralManager` to create Peripheral Manager
``` js
var peripheralManager = BLE.initPeripheralManager();
```
- Use `createMutableCharacteristic` to create charracteristic
``` js
charProperties = [ BLE.CHARACTERISTIC_PROPERTIES_READ, BLE.CHARACTERISTIC_PROPERTIES_WRITE_WITHOUT_RESPONSE, BLE.CHARACTERISTIC_PROPERTIES_NOTIFY ];
charPermissions = [ BLE.CHARACTERISTIC_PERMISSION_READABLE, BLE.CHARACTERISTIC_PERMISSION_WRITEABLE ];
var characteristic = BLE.createMutableCharacteristic({
uuid: characteristicUUID,
properties: charProperties,
permissions: charPermissions
});
```
- Use `addService` to add service
``` js
service = peripheralManager.addService({
uuid: serviceUUID,
primary: true,
characteristics: [ characteristic ]
});
```
- Once `peripheralManager` is in `BLE.MANAGER_STATE_POWERED_ON` state, start advertising using `startAdvertising`
``` js
var name = IOS ? 'BLE-Sample' : true;
peripheralManager.startAdvertising({
localName: name,
serviceUUIDs: servicesUUIDs
});
```
- Use `updateValue` to update charracteristic value
``` js
var buffer = Ti.createBuffer({ value: 'hello world' });
peripheralManager.updateValue({
characteristic: characteristic,
data: buffer,
central: centrals
});
```
- Use `stopAdvertising` to stop advertising
``` js
peripheralManager.stopAdvertising();
```
- Use `closePeripheral` to close the peripheral after it is done with the peripheral operations. (Android only)
``` js
peripheralManager.closePeripheral();
```
## Follow basic steps to create Peripheral application which use channels for communication:
- Use `initPeripheralManager` to create Peripheral Manager
``` js
var peripheralManager = BLE.initPeripheralManager();
```
- Use `createMutableCharacteristic` to create charracteristic
``` js
var characteristic = BLE.createMutableCharacteristic({
uuid: BLE.CBUUID_L2CAPPSM_CHARACTERISTIC_STRING,
properties: [ BLE.CHARACTERISTIC_PROPERTIES_READ, BLE.CHARACTERISTIC_PROPERTIES_INDICATE ],
permissions: [ BLE.CHARACTERISTIC_PERMISSION_READABLE ]
});
```
- Use `addService` to add service
``` js
var service = peripheralManager.addService({
uuid: serviceUUID,
primary: true,
characteristics: [ characteristic ]
});
```
- Once `peripheralManager` is in `BLE.MANAGER_STATE_POWERED_ON` state, use `publishL2CAPChannel` to publish channel and start advertising using `startAdvertising`
``` js
peripheralManager.publishL2CAPChannel({
encryptionRequired: false
});
peripheralManager.startAdvertising({
localName: name,
serviceUUIDs: servicesUUIDs
});
```
- Update `psmIdentifier` to characteristic in `didPublishL2CAPChannel` event
``` js
peripheralManager.addEventListener('didPublishL2CAPChannel', function (e) {
var psmBuffer = Ti.createBuffer({ value: e.psm + '' });
manager.updateValue({
characteristic: characteristic,
data: psmBuffer,
central: centrals
});
});
```
- Get Channel from `didOpenL2CAPChannel` event and set `onDataReceived` event to read values and `onStreamError` event for check stream errors
``` js
peripheralManager.addEventListener('didOpenL2CAPChannel', function (e) {
var channel = e.channel;
channel.addEventListener('onDataReceived', function (e) {
var data = e.data;
});
channel.addEventListener('onStreamError', function (e) {});
});
```
- Use `write` function from channel to write values
``` js
var newBuffer = Ti.createBuffer({ value: 'hello world' });
channel.write({
data: newBuffer
});
```
- Use `close` function to close channel
``` js
channel.close();
```
- Use `stopAdvertising` to stop advertising
``` js
peripheralManager.stopAdvertising();
```
- Use `closePeripheral` to close the peripheral after it is done with the peripheral operations. (Android only)
``` js
peripheralManager.closePeripheral();
```
# iBeacon Application (iOS Only)
## Follow basic steps to adverstise iBeacon:
- Use `initPeripheralManager` to create Peripheral Manager
``` js
var peripheralManager = BLE.initPeripheralManager();
```
- Use `createBeaconRegion` to create BeaconRegion
``` js
var beaconRegion = BLE.createBeaconRegion({
uuid: '135C8F13-6A2D-46ED-AA71-FB956FC23742',
major: 1,
minor: 100,
identifier: 'com.appcelerator.BluetoothLowEnergy.beacon'
});
```
- Once `peripheralManager` is in `BLE.MANAGER_STATE_POWERED_ON` state, start advertising using `startAdvertisingBeaconRegion`
``` js
peripheralManager.startAdvertisingBeaconRegion({
beaconRegion: beaconRegion
});
```
## Follow basic steps to create iBeacon Scanner application:
- Edit the `plist` with following `uses-permission` element to the ios plist section
``` xml
NSLocationWhenInUseUsageDescription
Allow Location permission
NSLocationAlwaysUsageDescription
Allow Location permission
```
- Use `initPeripheralManager` to create Region Manager
``` js
var regionManager = BLE.createRegionManager();
```
- Use `requestWhenInUseAuthorization` to request location permission
``` js
regionManager.requestWhenInUseAuthorization();
```
- Use `createBeaconRegion` to create BeaconRegion
``` js
var beaconRegion = BLE.createBeaconRegion({
uuid: '135C8F13-6A2D-46ED-AA71-FB956FC23742',
major: 1,
minor: 100,
identifier: 'com.appcelerator.BluetoothLowEnergy.beacon'
});
```
- Once `regionManager` is in `BLE.LOCATION_MANAGER_AUTHORIZATION_STATUS_AUTHORIZED_WHEN_IN_USE | BLE.LOCATION_MANAGER_AUTHORIZATION_STATUS_AUTHORIZED_ALWAYS` state, use `startRegionMonitoring` to start monitoring and start ranging using `startRangingBeaconsInRegion`
``` js
regionManager.startRegionMonitoring({
beaconRegion: beaconRegion
});
regionManager.startRangingBeaconsInRegion({
beaconRegion: beaconRegion
});
```
- Get ranged beacons from `didRangeBeacons` event and check `proximity` and `accuracy` to check beacon location
``` js
var didRangeBeacons = (e) => {
var becaons = e.beacons;
if (becaons.length === 0) {
alert('No beacon in range');
return;
}
var proximity = becaons[0].proximity;
var accuracy = becaons[0].accuracy;
switch (proximity) {
case BLE.BEACON_PROXIMITY_UNKNOWN:
alert('Beacon Location : UNKNOWN');
break;
case BLE.BEACON_PROXIMITY_IMMEDIATE:
alert('Beacon Location : IMMEDIATE (approx. ' + accuracy + 'm)');
break;
case BLE.BEACON_PROXIMITY_NEAR:
alert('Beacon Location : NEAR (approx. ' + accuracy + 'm)');
break;
case BLE.BEACON_PROXIMITY_FAR:
alert('Beacon Location : FAR (approx. ' + accuracy + 'm)');
break;
default:
alert('Beacon Location : UNKNOWN');
break;
}
};
regionManager.addEventListener('didRangeBeacons', didRangeBeacons);
```
- Use `stopRegionMonitoring` to stop monitoring and stop ranging using `stopRangingBeaconsInRegion`
``` js
regionManager.stopRegionMonitoring({
beaconRegion: beaconRegion
});
regionManager.stopRangingBeaconsInRegion({
beaconRegion: beaconRegion
});
```
## Read Data from TiBuffer
- you can access bytes from TiBuffer using:
``` js
for (i = 0; i < buffer.length; i++) {
var byte = buffer[i];
}
```
## Example
- Please see the `example/` folder.
- Please see the `example/ImageTransferUsingChannelStream` folder for how to use channel stream API's to transfer bigger data like images.
- Please see the `example/beacon` folder for iBeacon sample.
## Observations
### Android
- This behaviour is observed on certain android devices. While starting the BLE scan, make sure the location service is turned-on in order to receive the scan results.
- It is observed with certain fitness watches (may be other BLE hardware too) that upon connecting them with android-central application, the connection gets auto-disconnected after certain period of time(ranging from immediately to up-to 50s or more).
The fix is to first pair your peripheral-device(watch or any other hardware) with android device via Settings->Bluetooth screen and then do the connection procedure from central-application.
### iOS
- Beacon do not have background support
## Building
Simply run `appc run -p ios --build-only` and `appc run -p android --build-only` which will compile and package your module.
Copy the module zip file into the root folder of your Titanium application or in the Titanium system folder (e.g. `/Library/Application Support/Titanium`).
## Author
Axway
## License
Copyright (c) 2020 by Axway, Inc. Please see the LICENSE file for further details.