Client

A BLE device can connect to a remote device. The result of initiating a connection is a client. The client can be used to navigate the services implemented by the remote device as well as the service characteristics.

Connecting to a remote device

In order for a BLE device to establish a connection to a remote device, the device must know the address. In most cases, the BLE device needs to discover the address which is done by scanning remote devices. The following example shows how to scan for the first remote device that implements a specific service.

import ble

SCAN-DURATION ::= Duration --s=3

find-with-service central/ble.Central service/ble.BleUuid:
  central.scan --duration=SCAN-DURATION: | device/ble.RemoteScannedDevice |
    if device.data.service-classes.contains service:
        return device.address
  throw "no device found"

With the address available, the connection can be established. In the following example, we use the find-with-service function to find a remote device with an advertised battery service and establish a connection to that device. Note that the device might also support services that are not explicitly advertised.

// The battery service is defined in the Bluetooth specification.
// Devices that implement the battery service should (but don't
// need to) advertise it.
// For custom services use a full 128-bit UUID.
BATTERY-SERVICE ::= ble.BleUuid "180F"

main:
  adapter := ble.Adapter
  central := adapter.central

  address := find-with-service central BATTERY-SERVICE
  remote-device := central.connect address

Reading service characteristics

With the client in place, the battery service can be accessed. The battery service has a battery level characteristic which can be read out through the client.

import ble

BATTERY-SERVICE ::= ble.BleUuid "180F"
BATTERY-LEVEL   ::= ble.BleUuid "2A19"

SCAN-DURATION   ::= Duration --s=3

find-with-service central/ble.Central service/ble.BleUuid:
  central.scan --duration=SCAN-DURATION: | device/ble.RemoteScannedDevice |
    if device.data.service-classes.contains service:
        return device.address
  throw "no device found"

main:
  adapter := ble.Adapter
  central := adapter.central

  address := find-with-service central BATTERY-SERVICE
  remote-device := central.connect address
  // Discover the battery service.
  services := remote-device.discover-services [BATTERY-SERVICE]
  battery-service/ble.RemoteService := services.first

  // Discover the battery level characteristic.
  characteristics := battery-service.discover-characteristics [BATTERY-LEVEL]
  battery-level-characteristic/ble.RemoteCharacteristic := characteristics.first

  // Read the battery level which is a value between 0 and 100.
  value := battery-level-characteristic.read
  battery-level := value[0]

  print "Battery level of $address: $battery-level%"