aboutsummaryrefslogtreecommitdiff
path: root/docs/ble.md
blob: 107e9e444222557c66e1d9282575d188864d14f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
Zephyr.js API for Bluetooth Low Energy (BLE)
============================================

* [Introduction](#introduction)
* [Web IDL](#web-idl)
* [API Documentation](#api-documentation)
* [Sample Apps](#sample-apps)

Introduction
------------
The BLE API is based off the [bleno API]
(https://github.com/sandeepmistry/bleno). Bluetooth Low Energy (aka
[Bluetooth Smart](https://www.bluetooth.com/what-is-bluetooth-technology/bluetooth-technology-basics/low-energy)) is a power-friendly version of Bluetooth
intended for IoT devices. It provides the ability to support low-bandwidth data
services to nearby devices.

A note about UUIDs. The BLE standard lets you have full 128-bit UUIDs or short
16-bit UUIDs (4 hex chars). We only support the short ones so far.

Based on the bleno API, these UUIDs are specified as a hexadecimal string, so
"2901" really means 0x2901. *NOTE: This seems like a bad practice and we should
perhaps require these numbers to be specified as "0x2901" instead, or else
treat them like decimals.*

Web IDL
-------
This IDL provides an overview of the interface; see below for documentation of
specific API functions.

```javascript
// require returns a BLE object
// var ble = require('ble');

[NoInterfaceObject]
interface BLE {
    void on(string eventType, EventCallback callback);
    void startAdvertising(string name, string[] uuids, string url);
    void stopAdvertising();
    void setServices();
    PrimaryService PrimaryService(PrimaryServiceInit init);
    Characteristic Characteristic(CharacteristicInit init);
    Descriptor Descriptor(DescriptorInit init);
};

callback EventCallback = void (various);  // callback arg depends on event

dictionary PrimaryServiceInit {
    string uuid;
    Characteristic[] characteristics;
};

dictionary CharacteristicInit {
    string uuid;
    string[] properties;                // 'read', 'write', 'notify'
    Descriptor[] descriptors;
    ReadCallback onReadRequest;         // optional
    WriteCallback onWriteRequest;       // optional
    SubscribeCallback onSubscribe;      // optional
    UnsubscribeCallback onUnsubscribe;  // optional
    NotifyCallback onNotify;            // optional
};

callback ReadCallback = void (unsigned long offset, FulfillReadCallback);
callback WriteCallback = void (Buffer data, unsigned long offset,
                               boolean withoutResponse, FulfillWriteCallback);
callback SubscribeCallback = void (unsigned long maxValueSize,
                                   FulfillSubscribeCallback);
callback FulfillReadCallback = void (CharacteristicResult result, Buffer data);
callback FulfillWriteCallback = void (CharacteristicResult result);
callback FulfillSubscribeCallback = void (Buffer data);

dictionary DescriptorInit {
    string uuid;
    string value;
};

[NoInterfaceObject]
interface Characteristic {
    attribute ReadCallback onReadRequest;
    attribute WriteCallback onWriteRequest;
    attribute SubscribeCallback onSubscribe;
    attribute UnsubscribeCallback onUnsubscribe;
    attribute NotifyCallback onNotify;
    unsigned long RESULT_SUCCESS;
    unsigned long RESULT_INVALID_OFFSET;
    unsigned long RESULT_INVALID_ATTRIBUTE_LENGTH;
    unsigned long RESULT_UNLIKELY_ERROR;
};
```

API Documentation
-----------------
### BLE.on

`void on(string eventType, EventCallback callback);`

The `eventType` can be one of the following:
* 'accept' - a BLE client has connected
  * callback should expect a string state:
    * 'poweredOn' - the BLE stack is now ready to be used
    * no others supported at this time
* 'advertisingStart' - BLE services have begun to be advertised
  * callback should currently expect an error integer (0 for success)
  * *NOTE: this may change*
* 'disconnect' - a BLE client has disconnected
  * *NOTE: callback currently receives a 0 but it should be "clientAddress"*
* 'stateChange' - state of BLE stack has changed
  * *NOTE: callback currently receives a 0 but it should be "clientAddress"*

### BLE.startAdvertising

`void startAdvertising(string name, string[] uuids, string url);`

The `name` is limited to 26 characters and will be advertised as the device
name to nearby BLE devices.

The `uuids` array may contain at most 7 16-bit UUIDs (four hex digits each).
These UUIDs identify available services to nearby BLE devices.

The `url` is optional and limited to around 24 characters (slightly more
if part of the URL is able to be [encoded]
(https://github.com/google/eddystone/tree/master/eddystone-url)). If provided,
this will be used to create a physical web advertisement that will direct users
to the given URL. At that URL they might be able to interact with the
advertising device somehow.

### BLE.stopAdvertising

`void stopAdvertising();`

Currently does nothing.

### BLE.setServices

`void setServices(PrimaryService[]);`

Pass an array of PrimaryService objects to set up the services that are
implemented by your app.

*NOTE: Currently this function only looks at the first service, but this will be
expanded.*

### BLE.PrimaryService constructor

`PrimaryService(PrimaryServiceInit init);`

The `init` object should contain a `uuid` field with a 16-bit service UUID (4
hex chars) and a `characteristics` field with an array of Characteristic
objects.

### BLE.Characteristic constructor

`Characteristic(CharacteristicInit init);`

The `init` object should contain:
* `uuid` field with a 16-bit characteristic UUID (4 hex chars)
* `properties` field with an array of strings that may include 'read', 'write',
  and 'notify', depending on what is supported
* `descriptors` field with an array of Descriptor objects

It may also contain these optional callback fields:
* `onReadRequest` function(offset, callback(result, data))
  * Called when the client is requesting to read data from the characteristic.
  * See below for common argument definitions
* `onWriteRequest` function(data, offset, withoutResponse, callback(result))
  * Called when the client is requesting to write data to the characteristic.
  * `withoutResponse` is true if the client doesn't want a response
    * *TODO: verify this*
* `onSubscribe` function(maxValueSize, callback(data))
  * Called when a client signs up to receive notify events when the
      characteristic changes.
  * `maxValueSize` is the maximum data size the client wants to receive.
* `onUnsubscribe` function()
  * *NOTE: Never actually called currently.*
* `onNotify` function()
  * *NOTE: Never actually called currently.*

Explanation of common arguments to the above functions:
* `offset` is a 0-based integer index into the data the characteristic
    represents.
* `result` is one of these values defined in the Characteristic object.
  * RESULT_SUCCESS
  * RESULT_INVALID_OFFSET
  * RESULT_INVALID_ATTRIBUTE_LENGTH
  * RESULT_UNLIKELY_ERROR
* `data` is a [Buffer](./buffer.md) object.

### BLE.Descriptor constructor

`Descriptor(DescriptorInit init);`

The `init` object should contain:
* `uuid` field with a 16-bit descriptor UUID (4 hex chars)
  * Defined descriptors are listed here in [Bluetooth Specifications](https://www.bluetooth.com/specifications/gatt/descriptors)
* `value` field with a string supplying the defined information
  * *NOTE: Values can also be Buffer objects, but that's not currently supported.*

Sample Apps
-----------
* [BLE sample](../samples/BLE.js)
* [WebBluetooth Demo](../samples/WebBluetoothDemo.js)