# Bluetooth (Beta)

{% hint style="warning" %}
BLE support is currently in **Beta**. Some functionality is not available yet, and it may require further stability updates.
{% endhint %}

{% hint style="info" %}
BLE support is currently only available for customers on the [Enterprise](https://journeyapps.com/pricing/) plan.
{% endhint %}

{% hint style="info" %}
**Compatibility Requirements**

A custom-branded container is necessary for Android, iOS and Windows for any `Bluetooth` functions. Please contact [JourneyApps Support](mailto:support@journeyapps.com) to request one.
{% endhint %}

{% hint style="success" %}
**TypeScript is recommended**

The `Bluetooth` functions in JourneyApps rely on async-await. While it may be possible to work around this in a JavaScript app with promises, we strongly recommend using TypeScript.
{% endhint %}

JourneyApps' Bluetooth Low Energy (BLE) support allows users to scan for and connect to nearby BLE devices in real-time. The simplest way to achieve this is using `Bluetooth.requestDevice()`. For more advanced use cases, `Bluetooth.requestLEScan()` is available. More information on both these methods can be found below.

## Bluetooth.requestDevice()

`Bluetooth.requestDevice()` requests a device according to filters.

On Web, a list of devices is returned to the user, from which the user can proceed to select one.

<img src="https://2865107717-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F9TCHLR67eLHBOjPvHhud%2Fuploads%2Fgit-blob-18c3283f88d05ac7c94ddbfd1f5dc2899e608124%2Fble-request-device.png?alt=media" alt="" data-size="original">

On Windows, Android and iOS, `Bluetooth.requestDevice()` the first matching device is automatically selected. We recommend using `Bluetooth.requestLEScan()` (see below) on these platforms should the user need to select a device.

### Usage example

{% code title="view\.ts" %}

```typescript
async function scan() {
    const device = await Bluetooth.requestDevice({acceptAllDevices: true});    

    // To establish a connection to the device, use `device.gatt.connect()`

    // Note: In many cases, no device name will be reported. We use this
    // as a filter just to reduce noise for the example.
    if (device.name) {
        device.gatt.connect().then(() => {
            console.log('Connected to ', device.name);
            notification.info('Connected to: ' + device.name);
        }).catch(err => {
            console.error('Failed to connect to', device.name, err);
            notification.error('Failed to connect to: ' + device.name);
        });
    }
}
```

{% endcode %}

## Bluetooth.requestLEScan()

{% hint style="info" %}
**Compatibility requirements**

`Bluetooth.requestLEScan()` was introduced in version 4.84.0 of the JourneyApps Runtime. It is supported on Windows, Android and iOS only.
{% endhint %}

`Bluetooth.requestLEScan()` should be used (instead of `Bluetooth.requestDevice()`) where the app needs more control over the BLE scanning process. It is based on [this spec](https://webbluetoothcg.github.io/web-bluetooth/scanning.html). Note the following differences from this spec:

1. Added the `signal` parameter to cancel scanning.
2. Events do not include `manufacturerData`, `serviceData`, `txPower` or `appearance`.

{% hint style="info" %}
Ensure that your TypeScript app has the following version in `package.json`: `"@journeyapps/runtime-build": "^2.0.2"`. Note that after updating `package.json`, you need to run **Update yarn**.
{% endhint %}

### Usage example

Note that in this example the first device is being connected to. In a real app, you'd typically add these devices to a list (for example, you'd create LocalDB objects and display these in a suitable UI component) for the user to select one.

{% code title="view\.ts" %}

```typescript
// AbortController is optional, but makes explicitly stopping the scan easier.
// Scanning is automatically stopped when navigating to a different view.
let controller: AbortController;
async function scan() {
    // Cancel existing scans, if any
    controller?.abort();
    controller = new AbortController();

    Bluetooth.addEventListener('advertisementreceived', (event) => {
        const device: journey.BluetoothDevice = event.device;
        // Note: In many cases, no device name will be reported. We use this
        // as a filter just to reduce noise for the example.
        if (device.name) {
            notification.info('Device: ' + device.name + ' ' + event.rssi);
            // In a real app, you'd typically add these devices to a list,
            // instead of connecting directly.
            // To establish a connection to the device, use `device.gatt.connect()`
            device.gatt.connect().then(() => {
                console.log('Connected to ', device.name);
                notification.info('Connected to: ' + device.name);
            }).catch(err => {
                console.error('Failed to connect to', device.name, err);
                notification.error('Failed to connect to: ' + device.name);
            });
        }
    })
      
    await Bluetooth.requestLEScan({
        // In most cases, you'd want to filter the devices instead, e.g.:
        // filters: [{services: ['ffff0001-0b3a-11ec-9a03-0242ac130003']}]});
        acceptAllAdvertisements: true,
        // Set this to true to receive multiple events for the same device, e.g. to update the rssi
        keepRepeatedDevices: false,
        // We specify the signal to manually control stopping of the scan
        signal: controller.signal
    });

}

function stopScan() {
    controller?.abort();
}
```

{% endcode %}
