@stoprocent/noble 1.9.2-16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +11 -0
- package/.eslintrc.js +25 -0
- package/.github/FUNDING.yml +2 -0
- package/.github/workflows/fediverse-action.yml +16 -0
- package/.github/workflows/nodepackage.yml +77 -0
- package/.github/workflows/npm-publish.yml +26 -0
- package/.github/workflows/prebuild.yml +65 -0
- package/.nycrc.json +4 -0
- package/CHANGELOG.md +119 -0
- package/LICENSE +20 -0
- package/MAINTAINERS.md +1 -0
- package/README.md +833 -0
- package/assets/noble-logo.png +0 -0
- package/assets/noble-logo.svg +13 -0
- package/binding.gyp +19 -0
- package/codecov.yml +5 -0
- package/examples/advertisement-discovery.js +65 -0
- package/examples/cache-gatt-discovery.js +198 -0
- package/examples/cache-gatt-reconnect.js +164 -0
- package/examples/echo.js +104 -0
- package/examples/enter-exit.js +78 -0
- package/examples/peripheral-explorer-async.js +133 -0
- package/examples/peripheral-explorer.js +225 -0
- package/examples/pizza/README.md +15 -0
- package/examples/pizza/central.js +194 -0
- package/examples/pizza/pizza.js +60 -0
- package/index.d.ts +203 -0
- package/index.js +6 -0
- package/lib/characteristic.js +161 -0
- package/lib/characteristics.json +449 -0
- package/lib/descriptor.js +72 -0
- package/lib/descriptors.json +47 -0
- package/lib/distributed/bindings.js +326 -0
- package/lib/hci-socket/acl-stream.js +60 -0
- package/lib/hci-socket/bindings.js +788 -0
- package/lib/hci-socket/crypto.js +74 -0
- package/lib/hci-socket/gap.js +432 -0
- package/lib/hci-socket/gatt.js +809 -0
- package/lib/hci-socket/hci-status.json +71 -0
- package/lib/hci-socket/hci.js +1264 -0
- package/lib/hci-socket/signaling.js +76 -0
- package/lib/hci-socket/smp.js +140 -0
- package/lib/hci-uart/bindings.js +569 -0
- package/lib/hci-uart/hci-serial-parser.js +70 -0
- package/lib/hci-uart/hci.js +1336 -0
- package/lib/mac/binding.gyp +26 -0
- package/lib/mac/bindings.js +11 -0
- package/lib/mac/src/ble_manager.h +41 -0
- package/lib/mac/src/ble_manager.mm +435 -0
- package/lib/mac/src/callbacks.cc +222 -0
- package/lib/mac/src/callbacks.h +84 -0
- package/lib/mac/src/napi_objc.h +12 -0
- package/lib/mac/src/napi_objc.mm +50 -0
- package/lib/mac/src/noble_mac.h +34 -0
- package/lib/mac/src/noble_mac.mm +264 -0
- package/lib/mac/src/objc_cpp.h +26 -0
- package/lib/mac/src/objc_cpp.mm +126 -0
- package/lib/mac/src/peripheral.h +23 -0
- package/lib/manufacture.js +48 -0
- package/lib/noble.js +593 -0
- package/lib/peripheral.js +219 -0
- package/lib/resolve-bindings-web.js +9 -0
- package/lib/resolve-bindings.js +44 -0
- package/lib/service.js +72 -0
- package/lib/services.json +92 -0
- package/lib/webbluetooth/bindings.js +368 -0
- package/lib/websocket/bindings.js +321 -0
- package/lib/win/binding.gyp +23 -0
- package/lib/win/bindings.js +11 -0
- package/lib/win/src/ble_manager.cc +802 -0
- package/lib/win/src/ble_manager.h +77 -0
- package/lib/win/src/callbacks.cc +274 -0
- package/lib/win/src/callbacks.h +33 -0
- package/lib/win/src/napi_winrt.cc +76 -0
- package/lib/win/src/napi_winrt.h +12 -0
- package/lib/win/src/noble_winrt.cc +308 -0
- package/lib/win/src/noble_winrt.h +34 -0
- package/lib/win/src/notify_map.cc +62 -0
- package/lib/win/src/notify_map.h +50 -0
- package/lib/win/src/peripheral.h +23 -0
- package/lib/win/src/peripheral_winrt.cc +296 -0
- package/lib/win/src/peripheral_winrt.h +82 -0
- package/lib/win/src/radio_watcher.cc +125 -0
- package/lib/win/src/radio_watcher.h +61 -0
- package/lib/win/src/winrt_cpp.cc +82 -0
- package/lib/win/src/winrt_cpp.h +11 -0
- package/lib/win/src/winrt_guid.cc +12 -0
- package/lib/win/src/winrt_guid.h +13 -0
- package/misc/nrf52840dk.hex +6921 -0
- package/misc/prj.conf +43 -0
- package/package.json +96 -0
- package/test/lib/characteristic.test.js +791 -0
- package/test/lib/descriptor.test.js +249 -0
- package/test/lib/distributed/bindings.test.js +918 -0
- package/test/lib/hci-socket/acl-stream.test.js +188 -0
- package/test/lib/hci-socket/bindings.test.js +1756 -0
- package/test/lib/hci-socket/crypto.test.js +55 -0
- package/test/lib/hci-socket/gap.test.js +1089 -0
- package/test/lib/hci-socket/gatt.test.js +2392 -0
- package/test/lib/hci-socket/hci.test.js +1891 -0
- package/test/lib/hci-socket/signaling.test.js +94 -0
- package/test/lib/hci-socket/smp.test.js +268 -0
- package/test/lib/manufacture.test.js +77 -0
- package/test/lib/peripheral.test.js +623 -0
- package/test/lib/resolve-bindings.test.js +102 -0
- package/test/lib/service.test.js +195 -0
- package/test/lib/webbluetooth/bindings.test.js +190 -0
- package/test/lib/websocket/bindings.test.js +456 -0
- package/test/noble.test.js +1565 -0
- package/test.js +131 -0
- package/with-bindings.js +5 -0
- package/ws-slave.js +404 -0
package/README.md
ADDED
|
@@ -0,0 +1,833 @@
|
|
|
1
|
+
# 
|
|
2
|
+
|
|
3
|
+
[](https://travis-ci.org/abandonware/noble)
|
|
4
|
+
[](https://gitter.im/abandonware/noble?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [](#backers)
|
|
5
|
+
[](#sponsors)
|
|
6
|
+
|
|
7
|
+
A Node.js BLE (Bluetooth Low Energy) central module.
|
|
8
|
+
|
|
9
|
+
Want to implement a peripheral? Check out [bleno](https://github.com/abandonware/bleno).
|
|
10
|
+
|
|
11
|
+
__Note:__ macOS / Mac OS X, Linux, FreeBSD and Windows are currently the only supported OSes.
|
|
12
|
+
|
|
13
|
+
## Documentation
|
|
14
|
+
|
|
15
|
+
* [Quick Start Example](#quick-start-example)
|
|
16
|
+
* [Installation](#installation)
|
|
17
|
+
* [API docs](#api-docs)
|
|
18
|
+
* [Advanced usage](#advanced-usage)
|
|
19
|
+
* [Common problems](#common-problems)
|
|
20
|
+
|
|
21
|
+
## Quick Start Example
|
|
22
|
+
|
|
23
|
+
```javascript
|
|
24
|
+
// Read the battery level of the first found peripheral exposing the Battery Level characteristic
|
|
25
|
+
|
|
26
|
+
const noble = require('@abandonware/noble')({extended: false});
|
|
27
|
+
|
|
28
|
+
noble.on('stateChange', async (state) => {
|
|
29
|
+
if (state === 'poweredOn') {
|
|
30
|
+
await noble.startScanningAsync(['180f'], false);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
noble.on('discover', async (peripheral) => {
|
|
35
|
+
await noble.stopScanningAsync();
|
|
36
|
+
await peripheral.connectAsync();
|
|
37
|
+
const {characteristics} = await peripheral.discoverSomeServicesAndCharacteristicsAsync(['180f'], ['2a19']);
|
|
38
|
+
const batteryLevel = (await characteristics[0].readAsync())[0];
|
|
39
|
+
|
|
40
|
+
console.log(`${peripheral.address} (${peripheral.advertisement.localName}): ${batteryLevel}%`);
|
|
41
|
+
|
|
42
|
+
await peripheral.disconnectAsync();
|
|
43
|
+
process.exit(0);
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Installation
|
|
48
|
+
|
|
49
|
+
* [Prerequisites](#prerequisites)
|
|
50
|
+
* [UART](#uart)
|
|
51
|
+
* [OS X](#os-x)
|
|
52
|
+
* [Linux](#linux)
|
|
53
|
+
* [Ubuntu, Debian, Raspbian](#ubuntu-debian-raspbian)
|
|
54
|
+
* [Fedora and other RPM-based distributions](#fedora-and-other-rpm-based-distributions)
|
|
55
|
+
* [Intel Edison](#intel-edison)
|
|
56
|
+
* [FreeBSD](#freebsd)
|
|
57
|
+
* [Windows](#windows)
|
|
58
|
+
* [Docker](#docker)
|
|
59
|
+
* [Installing and using the package](#installing-and-using-the-package)
|
|
60
|
+
|
|
61
|
+
### Prerequisites
|
|
62
|
+
|
|
63
|
+
#### UART
|
|
64
|
+
|
|
65
|
+
The reason for this fork was to create more universal transport that can work across multiple operating systems.
|
|
66
|
+
Idea is to use Zephyr HCI over UART firmware and create noble driver to interface with HCI over UART.
|
|
67
|
+
|
|
68
|
+
##### Known Issues
|
|
69
|
+
What I have found so far that when using extended MTU and sending large amount of data Zephyr stops responding in rare cases. I have played with Zephyr configuration parameters in order to increase buffer sizes but with some luck. Sometimes when transfering fast, large payloads, with high MTU you can still hit the limit and Zephyr needs to be rebooted.
|
|
70
|
+
|
|
71
|
+
##### How to use this?
|
|
72
|
+
|
|
73
|
+
1. You will need NRF5x module (e.g. nRF52840 PDK)
|
|
74
|
+
2. If you have `nRF52840 PDK` you can in fact just use compiled HEX [misc/nrf52840dk.hex](misc/nrf52840dk.hex) (Buad Rate set to `1000000`)
|
|
75
|
+
3. If you want to compile it yourself:
|
|
76
|
+
1. You will need to install Zephyr ([https://docs.zephyrproject.org/latest/getting_started/index.html](https://docs.zephyrproject.org/latest/getting_started/index.html))
|
|
77
|
+
2. Compile HCI UART Example - `west build -p auto -b <your-board-name> zephyr/samples/bluetooth/hci_uart`
|
|
78
|
+
- e.g. When using `nRF52840 PDK` call `west build -p auto -b nrf52840dk_nrf52840 zephyr/samples/bluetooth/hci_uart`
|
|
79
|
+
4. Flash the firmware to Nordic Board e.g. using `nrfjprog`
|
|
80
|
+
- e.g. `nrfjprog -f NRF52 --program misc/nrf52840dk.hex –-chiperase --reset`
|
|
81
|
+
5. When you get a nordic board connected to the PC/Mac etc. with UART interface you are good to go.
|
|
82
|
+
6. In order to run any example from the examples folder or your own code you have to provide UART port by defining env variable: `NOBLE_HCI_UART_PORT`. Optionally if you use different Baud Rate you can change it by specifing `NOBLE_HCI_UART_BAUD_RATE`. Default value is `1000000`
|
|
83
|
+
7. e.g. `NOBLE_HCI_UART_PORT=/dev/tty.usbmodem0006837533091 node examples/peripheral-explorer.js b8:27:eb:83:9b:19`
|
|
84
|
+
|
|
85
|
+
#### OS X
|
|
86
|
+
|
|
87
|
+
* Install [Xcode](https://itunes.apple.com/ca/app/xcode/id497799835?mt=12)
|
|
88
|
+
* On newer versions of OSX, allow bluetooth access on the terminal app: "System Preferences" —> "Security & Privacy" —> "Bluetooth" -> Add terminal app (see [Sandboxed terminal](#sandboxed-terminal))
|
|
89
|
+
|
|
90
|
+
#### Linux
|
|
91
|
+
|
|
92
|
+
* Kernel version 3.6 or above
|
|
93
|
+
* `libbluetooth-dev` needs to be installed. For instructions for specific distributions, see below.
|
|
94
|
+
* To set the necessary privileges to run without sudo, [see this section](#running-without-rootsudo-linux-specific). This is required for all distributions (Raspbian, Ubuntu, Fedora, etc). You will not get any errors if running without sudo, but nothing will happen.
|
|
95
|
+
|
|
96
|
+
##### Ubuntu, Debian, Raspbian
|
|
97
|
+
|
|
98
|
+
See the [generic Linux notes above](#linux) first.
|
|
99
|
+
|
|
100
|
+
```sh
|
|
101
|
+
sudo apt-get install bluetooth bluez libbluetooth-dev libudev-dev
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Make sure `node` is on your `PATH`. If it's not, some options:
|
|
105
|
+
* Symlink `nodejs` to `node`: `sudo ln -s /usr/bin/nodejs /usr/bin/node`
|
|
106
|
+
* [Install Node.js using the NodeSource package](https://nodejs.org/en/download/package-manager/#debian-and-ubuntu-based-linux-distributions)
|
|
107
|
+
|
|
108
|
+
If you are having trouble connecting to BLE devices on a Raspberry Pi, you should disable the `pnat` plugin. Add the following line at the bottom of `/etc/bluetooth/main.conf`:
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
DisablePlugins=pnat
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Then restart the system.
|
|
115
|
+
|
|
116
|
+
See [Issue #425 · OpenWonderLabs/homebridge-switchbot](https://github.com/OpenWonderLabs/homebridge-switchbot/issues/425#issuecomment-1190864279).
|
|
117
|
+
|
|
118
|
+
##### Fedora and other RPM-based distributions
|
|
119
|
+
|
|
120
|
+
See the [generic Linux notes above](#linux) first.
|
|
121
|
+
|
|
122
|
+
```sh
|
|
123
|
+
sudo yum install bluez bluez-libs bluez-libs-devel
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
##### Intel Edison
|
|
127
|
+
|
|
128
|
+
See the [generic Linux notes above](#linux) first.
|
|
129
|
+
|
|
130
|
+
See [Configure Intel Edison for Bluetooth LE (Smart) Development](http://rexstjohn.com/configure-intel-edison-for-bluetooth-le-smart-development/).
|
|
131
|
+
|
|
132
|
+
#### FreeBSD
|
|
133
|
+
|
|
134
|
+
Make sure you have GNU Make:
|
|
135
|
+
|
|
136
|
+
```sh
|
|
137
|
+
sudo pkg install gmake
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Disable automatic loading of the default Bluetooth stack by putting [no-ubt.conf](https://gist.github.com/myfreeweb/44f4f3e791a057bc4f3619a166a03b87) into `/usr/local/etc/devd/no-ubt.conf` and restarting devd (`sudo service devd restart`).
|
|
141
|
+
|
|
142
|
+
Unload `ng_ubt` kernel module if already loaded:
|
|
143
|
+
|
|
144
|
+
```sh
|
|
145
|
+
sudo kldunload ng_ubt
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Make sure you have read and write permissions on the `/dev/usb/*` device that corresponds to your Bluetooth adapter.
|
|
149
|
+
|
|
150
|
+
#### Windows
|
|
151
|
+
|
|
152
|
+
[node-gyp requirements for Windows](https://github.com/TooTallNate/node-gyp#installation)
|
|
153
|
+
|
|
154
|
+
Install the required tools and configurations using Microsoft's [windows-build-tools](https://github.com/felixrieseberg/windows-build-tools) from an elevated PowerShell or cmd.exe (run as Administrator).
|
|
155
|
+
|
|
156
|
+
```cmd
|
|
157
|
+
npm install --global --production windows-build-tools
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
[node-bluetooth-hci-socket prerequisites](#windows)
|
|
161
|
+
* Compatible Bluetooth 5.0 Zephyr HCI-USB adapter (you need to add BLUETOOTH_HCI_SOCKET_USB_VID and BLUETOOTH_HCI_SOCKET_USB_PID to the process env)
|
|
162
|
+
* Compatible Bluetooth 4.0 USB adapter
|
|
163
|
+
* [WinUSB](https://msdn.microsoft.com/en-ca/library/windows/hardware/ff540196(v=vs.85).aspx) driver setup for Bluetooth 4.0 USB adapter, using [Zadig tool](http://zadig.akeo.ie/)
|
|
164
|
+
|
|
165
|
+
See [@don](https://github.com/don)'s setup guide on [Bluetooth LE with Node.js and Noble on Windows](https://www.youtube.com/watch?v=mL9B8wuEdms&feature=youtu.be&t=1m46s)
|
|
166
|
+
|
|
167
|
+
#### Docker
|
|
168
|
+
|
|
169
|
+
Make sure your container runs with `--network=host` options and all specific environment preriquisites are verified.
|
|
170
|
+
|
|
171
|
+
### Installing and using the package
|
|
172
|
+
|
|
173
|
+
```sh
|
|
174
|
+
npm install @abandonware/noble
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
In Windows OS add your custom hci-usb dongle to the process env
|
|
178
|
+
```sh
|
|
179
|
+
set BLUETOOTH_HCI_SOCKET_USB_VID=xxx
|
|
180
|
+
set BLUETOOTH_HCI_SOCKET_USB_PID=xxx
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
```javascript
|
|
184
|
+
const noble = require('@abandonware/noble')({extended: false});
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## API docs
|
|
188
|
+
|
|
189
|
+
All operations have two API variants – one expecting a callback, one returning a Promise (denoted by `Async` suffix).
|
|
190
|
+
|
|
191
|
+
Additionally, there are events corresponding to each operation (and a few global events).
|
|
192
|
+
|
|
193
|
+
For example, in case of the "discover services" operation of Peripheral:
|
|
194
|
+
|
|
195
|
+
* There's a `discoverServices` method expecting a callback:
|
|
196
|
+
```javascript
|
|
197
|
+
peripheral.discoverServices((error, services) => {
|
|
198
|
+
// callback - handle error and services
|
|
199
|
+
});
|
|
200
|
+
```
|
|
201
|
+
* There's a `discoverServicesAsync` method returning a Promise:
|
|
202
|
+
```javascript
|
|
203
|
+
try {
|
|
204
|
+
const services = await peripheral.discoverServicesAsync();
|
|
205
|
+
// handle services
|
|
206
|
+
} catch (e) {
|
|
207
|
+
// handle error
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
* There's a `servicesDiscover` event emitted after services are discovered:
|
|
211
|
+
```javascript
|
|
212
|
+
peripheral.once('servicesDiscover', (services) => {
|
|
213
|
+
// handle services
|
|
214
|
+
});
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
API structure:
|
|
218
|
+
|
|
219
|
+
* [Scanning and discovery](#scanning-and-discovery)
|
|
220
|
+
* [_Event: Adapter state changed_](#event-adapter-state-changed)
|
|
221
|
+
* [Start scanning](#start-scanning)
|
|
222
|
+
* [_Event: Scanning started_](#event-scanning-started)
|
|
223
|
+
* [Stop scanning](#stop-scanning)
|
|
224
|
+
* [_Event: Scanning stopped_](#event-scanning-stopped)
|
|
225
|
+
* [_Event: Peripheral discovered_](#event-peripheral-discovered)
|
|
226
|
+
* [_Event: Warning raised_](#event-warning-raised)
|
|
227
|
+
* [Reset device](#reset-device)
|
|
228
|
+
* [Peripheral](#peripheral)
|
|
229
|
+
* [Connect](#connect)
|
|
230
|
+
* [_Event: Connected_](#event-connected)
|
|
231
|
+
* [Cancel a pending connection](#cancel-a-pending-connection)
|
|
232
|
+
* [Disconnect](#disconnect)
|
|
233
|
+
* [_Event: Disconnected_](#event-disconnected)
|
|
234
|
+
* [Update RSSI](#update-rssi)
|
|
235
|
+
* [_Event: RSSI updated_](#event-rssi-updated)
|
|
236
|
+
* [Discover services](#discover-services)
|
|
237
|
+
* [Discover all services and characteristics](#discover-all-services-and-characteristics)
|
|
238
|
+
* [Discover some services and characteristics](#discover-some-services-and-characteristics)
|
|
239
|
+
* [_Event: Services discovered_](#event-services-discovered)
|
|
240
|
+
* [Read handle](#read-handle)
|
|
241
|
+
* [_Event: Handle read_](#event-handle-read)
|
|
242
|
+
* [Write handle](#write-handle)
|
|
243
|
+
* [_Event: Handle written_](#event-handle-written)
|
|
244
|
+
* [Service](#service)
|
|
245
|
+
* [Discover included services](#discover-included-services)
|
|
246
|
+
* [_Event: Included services discovered_](#event-included-services-discovered)
|
|
247
|
+
* [Discover characteristics](#discover-characteristics)
|
|
248
|
+
* [_Event: Characteristics discovered_](#event-characteristics-discovered)
|
|
249
|
+
* [Characteristic](#characteristic)
|
|
250
|
+
* [Read](#read)
|
|
251
|
+
* [_Event: Data read_](#event-data-read)
|
|
252
|
+
* [Write](#write)
|
|
253
|
+
* [_Event: Data written_](#event-data-written)
|
|
254
|
+
* [Broadcast](#broadcast)
|
|
255
|
+
* [_Event: Broadcast sent_](#event-broadcast-sent)
|
|
256
|
+
* [Subscribe](#subscribe)
|
|
257
|
+
* [_Event: Notification received_](#event-notification-received)
|
|
258
|
+
* [Unsubscribe](#unsubscribe)
|
|
259
|
+
* [Discover descriptors](#discover-descriptors)
|
|
260
|
+
* [_Event: Descriptors discovered_](#event-descriptors-discovered)
|
|
261
|
+
* [Descriptor](#descriptor)
|
|
262
|
+
* [Read value](#read-value)
|
|
263
|
+
* [_Event: Value read_](#event-value-read)
|
|
264
|
+
* [Write value](#write-value)
|
|
265
|
+
* [_Event: Value written_](#event-value-written)
|
|
266
|
+
|
|
267
|
+
### Scanning and discovery
|
|
268
|
+
|
|
269
|
+
#### _Event: Adapter state changed_
|
|
270
|
+
|
|
271
|
+
```javascript
|
|
272
|
+
noble.on('stateChange', callback(state));
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
`state` can be one of:
|
|
276
|
+
* `unknown`
|
|
277
|
+
* `resetting`
|
|
278
|
+
* `unsupported`
|
|
279
|
+
* `unauthorized`
|
|
280
|
+
* `poweredOff`
|
|
281
|
+
* `poweredOn`
|
|
282
|
+
|
|
283
|
+
#### Start scanning
|
|
284
|
+
|
|
285
|
+
```javascript
|
|
286
|
+
noble.startScanning(); // any service UUID, no duplicates
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
noble.startScanning([], true); // any service UUID, allow duplicates
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
var serviceUUIDs = ['<service UUID 1>', ...]; // default: [] => all
|
|
293
|
+
var allowDuplicates = falseOrTrue; // default: false
|
|
294
|
+
|
|
295
|
+
noble.startScanning(serviceUUIDs, allowDuplicates[, callback(error)]); // particular UUIDs
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
__NOTE:__ `noble.state` must be `poweredOn` before scanning is started. `noble.on('stateChange', callback(state));` can be used to listen for state change events.
|
|
299
|
+
|
|
300
|
+
#### _Event: Scanning started_
|
|
301
|
+
|
|
302
|
+
```javascript
|
|
303
|
+
noble.on('scanStart', callback);
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
The event is emitted when:
|
|
307
|
+
* Scanning is started
|
|
308
|
+
* Another application enables scanning
|
|
309
|
+
* Another application changes scanning settings
|
|
310
|
+
|
|
311
|
+
#### Stop scanning
|
|
312
|
+
|
|
313
|
+
```javascript
|
|
314
|
+
noble.stopScanning();
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
#### _Event: Scanning stopped_
|
|
318
|
+
|
|
319
|
+
```javascript
|
|
320
|
+
noble.on('scanStop', callback);
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
The event is emitted when:
|
|
324
|
+
* Scanning is stopped
|
|
325
|
+
* Another application stops scanning
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
#### _Event: Peripheral discovered_
|
|
329
|
+
|
|
330
|
+
```javascript
|
|
331
|
+
noble.on('discover', callback(peripheral));
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
* `peripheral`:
|
|
335
|
+
```javascript
|
|
336
|
+
{
|
|
337
|
+
id: '<id>',
|
|
338
|
+
address: '<BT address'>, // Bluetooth Address of device, or 'unknown' if not known
|
|
339
|
+
addressType: '<BT address type>', // Bluetooth Address type (public, random), or 'unknown' if not known
|
|
340
|
+
connectable: trueOrFalseOrUndefined, // true or false, or undefined if not known
|
|
341
|
+
advertisement: {
|
|
342
|
+
localName: '<name>',
|
|
343
|
+
txPowerLevel: someInteger,
|
|
344
|
+
serviceUuids: ['<service UUID>', ...],
|
|
345
|
+
serviceSolicitationUuid: ['<service solicitation UUID>', ...],
|
|
346
|
+
manufacturerData: someBuffer, // a Buffer
|
|
347
|
+
serviceData: [
|
|
348
|
+
{
|
|
349
|
+
uuid: '<service UUID>',
|
|
350
|
+
data: someBuffer // a Buffer
|
|
351
|
+
},
|
|
352
|
+
// ...
|
|
353
|
+
]
|
|
354
|
+
},
|
|
355
|
+
rssi: integerValue,
|
|
356
|
+
mtu: integerValue // MTU will be null, until device is connected and hci-socket is used
|
|
357
|
+
};
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
__Note:__ On macOS, the address will be set to '' if the device has not been connected previously.
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
#### _Event: Warning raised_
|
|
364
|
+
|
|
365
|
+
```javascript
|
|
366
|
+
noble.on('warning', callback(message));
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### Reset device
|
|
370
|
+
|
|
371
|
+
```javascript
|
|
372
|
+
noble.reset()
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
### Peripheral
|
|
376
|
+
|
|
377
|
+
#### Connect
|
|
378
|
+
|
|
379
|
+
```javascript
|
|
380
|
+
peripheral.connect([callback(error)]);
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
Some of the bluetooth devices doesn't connect seamlessly, may be because of bluetooth device firmware or kernel. Do reset the device with noble.reset() API before connect API.
|
|
384
|
+
|
|
385
|
+
#### _Event: Connected_
|
|
386
|
+
|
|
387
|
+
```javascript
|
|
388
|
+
peripheral.once('connect', callback);
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
#### Cancel a pending connection
|
|
392
|
+
|
|
393
|
+
```javascript
|
|
394
|
+
peripheral.cancelConnect();
|
|
395
|
+
// Will emit a 'connect' event with error
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
#### Disconnect
|
|
399
|
+
|
|
400
|
+
```javascript
|
|
401
|
+
peripheral.disconnect([callback(error)]);
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
#### _Event: Disconnected_
|
|
405
|
+
|
|
406
|
+
```javascript
|
|
407
|
+
peripheral.once('disconnect', callback);
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
#### Update RSSI
|
|
411
|
+
|
|
412
|
+
```javascript
|
|
413
|
+
peripheral.updateRssi([callback(error, rssi)]);
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
#### _Event: RSSI updated_
|
|
417
|
+
|
|
418
|
+
```javascript
|
|
419
|
+
peripheral.once('rssiUpdate', callback(rssi));
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
#### Discover services
|
|
423
|
+
|
|
424
|
+
```javascript
|
|
425
|
+
peripheral.discoverServices(); // any service UUID
|
|
426
|
+
|
|
427
|
+
var serviceUUIDs = ['<service UUID 1>', ...];
|
|
428
|
+
peripheral.discoverServices(serviceUUIDs[, callback(error, services)]); // particular UUIDs
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
#### Discover all services and characteristics
|
|
432
|
+
|
|
433
|
+
```javascript
|
|
434
|
+
peripheral.discoverAllServicesAndCharacteristics([callback(error, services, characteristics)]);
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
#### Discover some services and characteristics
|
|
438
|
+
|
|
439
|
+
```javascript
|
|
440
|
+
var serviceUUIDs = ['<service UUID 1>', ...];
|
|
441
|
+
var characteristicUUIDs = ['<characteristic UUID 1>', ...];
|
|
442
|
+
peripheral.discoverSomeServicesAndCharacteristics(serviceUUIDs, characteristicUUIDs, [callback(error, services, characteristics));
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
#### _Event: Services discovered_
|
|
446
|
+
|
|
447
|
+
```javascript
|
|
448
|
+
peripheral.once('servicesDiscover', callback(services));
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
#### Read handle
|
|
452
|
+
|
|
453
|
+
```javascript
|
|
454
|
+
peripheral.readHandle(handle, callback(error, data));
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
#### _Event: Handle read_
|
|
458
|
+
|
|
459
|
+
```javascript
|
|
460
|
+
peripheral.once('handleRead<handle>', callback(data)); // data is a Buffer
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
`<handle>` is the handle identifier.
|
|
464
|
+
|
|
465
|
+
#### Write handle
|
|
466
|
+
|
|
467
|
+
```javascript
|
|
468
|
+
peripheral.writeHandle(handle, data, withoutResponse, callback(error));
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
#### _Event: Handle written_
|
|
472
|
+
|
|
473
|
+
```javascript
|
|
474
|
+
peripheral.once('handleWrite<handle>', callback());
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
`<handle>` is the handle identifier.
|
|
478
|
+
|
|
479
|
+
### Service
|
|
480
|
+
|
|
481
|
+
#### Discover included services
|
|
482
|
+
|
|
483
|
+
```javascript
|
|
484
|
+
service.discoverIncludedServices(); // any service UUID
|
|
485
|
+
|
|
486
|
+
var serviceUUIDs = ['<service UUID 1>', ...];
|
|
487
|
+
service.discoverIncludedServices(serviceUUIDs[, callback(error, includedServiceUuids)]); // particular UUIDs
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
#### _Event: Included services discovered_
|
|
491
|
+
|
|
492
|
+
```javascript
|
|
493
|
+
service.once('includedServicesDiscover', callback(includedServiceUuids));
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
#### Discover characteristics
|
|
497
|
+
|
|
498
|
+
```javascript
|
|
499
|
+
service.discoverCharacteristics() // any characteristic UUID
|
|
500
|
+
|
|
501
|
+
var characteristicUUIDs = ['<characteristic UUID 1>', ...];
|
|
502
|
+
service.discoverCharacteristics(characteristicUUIDs[, callback(error, characteristics)]); // particular UUIDs
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
#### _Event: Characteristics discovered_
|
|
506
|
+
|
|
507
|
+
```javascript
|
|
508
|
+
service.once('characteristicsDiscover', callback(characteristics));
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
* `characteristics`
|
|
512
|
+
```javascript
|
|
513
|
+
{
|
|
514
|
+
uuid: '<uuid>',
|
|
515
|
+
properties: ['...'] // 'broadcast', 'read', 'writeWithoutResponse', 'write', 'notify', 'indicate', 'authenticatedSignedWrites', 'extendedProperties'
|
|
516
|
+
};
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
### Characteristic
|
|
520
|
+
|
|
521
|
+
#### Read
|
|
522
|
+
|
|
523
|
+
```javascript
|
|
524
|
+
characteristic.read([callback(error, data)]);
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
#### _Event: Data read_
|
|
528
|
+
|
|
529
|
+
```javascript
|
|
530
|
+
characteristic.on('data', callback(data, isNotification));
|
|
531
|
+
|
|
532
|
+
characteristic.once('read', callback(data, isNotification)); // legacy
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
Emitted when:
|
|
536
|
+
* Characteristic read has completed, result of `characteristic.read(...)`
|
|
537
|
+
* Characteristic value has been updated by peripheral via notification or indication, after having been enabled with `characteristic.notify(true[, callback(error)])`
|
|
538
|
+
|
|
539
|
+
**Note:** `isNotification` event parameter value MAY be `undefined` depending on platform. The parameter is **deprecated** after version 1.8.1, and not supported on macOS High Sierra and later.
|
|
540
|
+
|
|
541
|
+
#### Write
|
|
542
|
+
|
|
543
|
+
```javascript
|
|
544
|
+
characteristic.write(data, withoutResponse[, callback(error)]); // data is a Buffer, withoutResponse is true|false
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
* `withoutResponse`:
|
|
548
|
+
* `false`: send a write request, used with "write" characteristic property
|
|
549
|
+
* `true`: send a write command, used with "write without response" characteristic property
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
#### _Event: Data written_
|
|
553
|
+
|
|
554
|
+
```javascript
|
|
555
|
+
characteristic.once('write', withoutResponse, callback());
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
Emitted when characteristic write has completed, result of `characteristic.write(...)`.
|
|
559
|
+
|
|
560
|
+
#### Broadcast
|
|
561
|
+
|
|
562
|
+
```javascript
|
|
563
|
+
characteristic.broadcast(broadcast[, callback(error)]); // broadcast is true|false
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
#### _Event: Broadcast sent_
|
|
567
|
+
|
|
568
|
+
```javascript
|
|
569
|
+
characteristic.once('broadcast', callback(state));
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
Emitted when characteristic broadcast state changes, result of `characteristic.broadcast(...)`.
|
|
573
|
+
|
|
574
|
+
#### Subscribe
|
|
575
|
+
|
|
576
|
+
```javascript
|
|
577
|
+
characteristic.subscribe([callback(error)]);
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
Subscribe to a characteristic.
|
|
581
|
+
|
|
582
|
+
Triggers `data` events when peripheral sends a notification or indication. Use for characteristics with "notify" or "indicate" properties.
|
|
583
|
+
|
|
584
|
+
#### _Event: Notification received_
|
|
585
|
+
|
|
586
|
+
```javascript
|
|
587
|
+
characteristic.once('notify', callback(state));
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
Emitted when characteristic notification state changes, result of `characteristic.notify(...)`.
|
|
591
|
+
|
|
592
|
+
#### Unsubscribe
|
|
593
|
+
|
|
594
|
+
```javascript
|
|
595
|
+
characteristic.unsubscribe([callback(error)]);
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
Unsubscribe from a characteristic.
|
|
599
|
+
|
|
600
|
+
Use for characteristics with "notify" or "indicate" properties
|
|
601
|
+
|
|
602
|
+
#### Discover descriptors
|
|
603
|
+
|
|
604
|
+
```javascript
|
|
605
|
+
characteristic.discoverDescriptors([callback(error, descriptors)]);
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
#### _Event: Descriptors discovered_
|
|
609
|
+
|
|
610
|
+
```javascript
|
|
611
|
+
characteristic.once('descriptorsDiscover', callback(descriptors));
|
|
612
|
+
```
|
|
613
|
+
* `descriptors`:
|
|
614
|
+
```javascript
|
|
615
|
+
[
|
|
616
|
+
{
|
|
617
|
+
uuid: '<uuid>'
|
|
618
|
+
},
|
|
619
|
+
// ...
|
|
620
|
+
]
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
### Descriptor
|
|
624
|
+
|
|
625
|
+
#### Read value
|
|
626
|
+
|
|
627
|
+
```javascript
|
|
628
|
+
descriptor.readValue([callback(error, data)]);
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
#### _Event: Value read_
|
|
632
|
+
|
|
633
|
+
```javascript
|
|
634
|
+
descriptor.once('valueRead', data); // data is a Buffer
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
#### Write value
|
|
638
|
+
|
|
639
|
+
```javascript
|
|
640
|
+
descriptor.writeValue(data[, callback(error)]); // data is a Buffer
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
#### _Event: Value written_
|
|
644
|
+
|
|
645
|
+
```javascript
|
|
646
|
+
descriptor.once('valueWrite');
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
## Advanced usage
|
|
650
|
+
|
|
651
|
+
### Override default bindings
|
|
652
|
+
|
|
653
|
+
By default, noble will select appropriate Bluetooth device bindings based on your platform. You can provide custom bindings using the `with-bindings` module.
|
|
654
|
+
|
|
655
|
+
```javascript
|
|
656
|
+
var noble = require('@abandonware/noble/with-bindings')(require('./my-custom-bindings'));
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
### Running without root/sudo (Linux-specific)
|
|
660
|
+
|
|
661
|
+
Run the following command:
|
|
662
|
+
|
|
663
|
+
```sh
|
|
664
|
+
sudo setcap cap_net_raw+eip $(eval readlink -f `which node`)
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
This grants the `node` binary `cap_net_raw` privileges, so it can start/stop BLE advertising.
|
|
668
|
+
|
|
669
|
+
__Note:__ The above command requires `setcap` to be installed.
|
|
670
|
+
It can be installed the following way:
|
|
671
|
+
|
|
672
|
+
* apt: `sudo apt-get install libcap2-bin`
|
|
673
|
+
* yum: `su -c \'yum install libcap2-bin\'`
|
|
674
|
+
|
|
675
|
+
### Multiple Adapters (Linux-specific)
|
|
676
|
+
|
|
677
|
+
`hci0` is used by default.
|
|
678
|
+
|
|
679
|
+
To override, set the `NOBLE_HCI_DEVICE_ID` environment variable to the interface number.
|
|
680
|
+
|
|
681
|
+
For example, to specify `hci1`:
|
|
682
|
+
|
|
683
|
+
```sh
|
|
684
|
+
sudo NOBLE_HCI_DEVICE_ID=1 node <your file>.js
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
If you are using multiple HCI devices in one setup you can run two instances of noble with different binding configurations by initializing them seperatly in code:
|
|
688
|
+
|
|
689
|
+
```
|
|
690
|
+
const HCIBindings = require('@abandonware/noble/lib/hci-socket/bindings');
|
|
691
|
+
const Noble = require('@abandonware/noble/lib/noble');
|
|
692
|
+
|
|
693
|
+
const params = {
|
|
694
|
+
deviceId: 0,
|
|
695
|
+
userChannel: true,
|
|
696
|
+
extended: false
|
|
697
|
+
};
|
|
698
|
+
|
|
699
|
+
const noble = new Noble(new HCIBindings(params));
|
|
700
|
+
```
|
|
701
|
+
|
|
702
|
+
### Reporting all HCI events (Linux-specific)
|
|
703
|
+
|
|
704
|
+
By default, noble waits for both the advertisement data and scan response data for each Bluetooth address. If your device does not use scan response, the `NOBLE_REPORT_ALL_HCI_EVENTS` environment variable can be used to bypass it.
|
|
705
|
+
|
|
706
|
+
```sh
|
|
707
|
+
sudo NOBLE_REPORT_ALL_HCI_EVENTS=1 node <your file>.js
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
### bleno compatibility (Linux-specific)
|
|
711
|
+
|
|
712
|
+
By default, noble will respond with an error whenever a GATT request message is received. If your intention is to use bleno in tandem with noble, the `NOBLE_MULTI_ROLE` environment variable can be used to bypass this behaviour.
|
|
713
|
+
|
|
714
|
+
__Note:__ this requires a Bluetooth 4.1 adapter.
|
|
715
|
+
|
|
716
|
+
```sh
|
|
717
|
+
sudo NOBLE_MULTI_ROLE=1 node <your file>.js
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
## Common problems
|
|
721
|
+
|
|
722
|
+
### Maximum simultaneous connections
|
|
723
|
+
|
|
724
|
+
This limit is imposed by the Bluetooth adapter hardware as well as its firmware.
|
|
725
|
+
|
|
726
|
+
| Platform | |
|
|
727
|
+
| :-------------------------------- | --------------------- |
|
|
728
|
+
| OS X 10.11 (El Capitan) | 6 |
|
|
729
|
+
| Linux/Windows - Adapter-dependent | 5 (CSR based adapter) |
|
|
730
|
+
|
|
731
|
+
### Sandboxed terminal
|
|
732
|
+
|
|
733
|
+
On newer versions of OSX, the terminal app is sandboxed to not allow bluetooth connections by default. If you run a script that tries to access it, you will get an `Abort trap: 6` error.
|
|
734
|
+
|
|
735
|
+
To enable bluetooth, go to "System Preferences" —> "Security & Privacy" —> "Bluetooth" -> Add your terminal into allowed apps.
|
|
736
|
+
|
|
737
|
+
### Adapter-specific known issues
|
|
738
|
+
|
|
739
|
+
Some BLE adapters cannot connect to a peripheral while they are scanning (examples below). You will get the following messages when trying to connect:
|
|
740
|
+
|
|
741
|
+
Sena UD-100 (Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)): `Error: Command disallowed`
|
|
742
|
+
|
|
743
|
+
Intel Dual Band Wireless-AC 7260 (Intel Corporation Wireless 7260 (rev 73)): `Error: Connection Rejected due to Limited Resources (0xd)`
|
|
744
|
+
|
|
745
|
+
You need to stop scanning before trying to connect in order to solve this issue.
|
|
746
|
+
|
|
747
|
+
## Backers
|
|
748
|
+
|
|
749
|
+
Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/noble#backer)]
|
|
750
|
+
|
|
751
|
+
<a href="https://opencollective.com/noble/backer/0/website" target="_blank"><img src="https://opencollective.com/noble/backer/0/avatar.svg"></a>
|
|
752
|
+
<a href="https://opencollective.com/noble/backer/1/website" target="_blank"><img src="https://opencollective.com/noble/backer/1/avatar.svg"></a>
|
|
753
|
+
<a href="https://opencollective.com/noble/backer/2/website" target="_blank"><img src="https://opencollective.com/noble/backer/2/avatar.svg"></a>
|
|
754
|
+
<a href="https://opencollective.com/noble/backer/3/website" target="_blank"><img src="https://opencollective.com/noble/backer/3/avatar.svg"></a>
|
|
755
|
+
<a href="https://opencollective.com/noble/backer/4/website" target="_blank"><img src="https://opencollective.com/noble/backer/4/avatar.svg"></a>
|
|
756
|
+
<a href="https://opencollective.com/noble/backer/5/website" target="_blank"><img src="https://opencollective.com/noble/backer/5/avatar.svg"></a>
|
|
757
|
+
<a href="https://opencollective.com/noble/backer/6/website" target="_blank"><img src="https://opencollective.com/noble/backer/6/avatar.svg"></a>
|
|
758
|
+
<a href="https://opencollective.com/noble/backer/7/website" target="_blank"><img src="https://opencollective.com/noble/backer/7/avatar.svg"></a>
|
|
759
|
+
<a href="https://opencollective.com/noble/backer/8/website" target="_blank"><img src="https://opencollective.com/noble/backer/8/avatar.svg"></a>
|
|
760
|
+
<a href="https://opencollective.com/noble/backer/9/website" target="_blank"><img src="https://opencollective.com/noble/backer/9/avatar.svg"></a>
|
|
761
|
+
<a href="https://opencollective.com/noble/backer/10/website" target="_blank"><img src="https://opencollective.com/noble/backer/10/avatar.svg"></a>
|
|
762
|
+
<a href="https://opencollective.com/noble/backer/11/website" target="_blank"><img src="https://opencollective.com/noble/backer/11/avatar.svg"></a>
|
|
763
|
+
<a href="https://opencollective.com/noble/backer/12/website" target="_blank"><img src="https://opencollective.com/noble/backer/12/avatar.svg"></a>
|
|
764
|
+
<a href="https://opencollective.com/noble/backer/13/website" target="_blank"><img src="https://opencollective.com/noble/backer/13/avatar.svg"></a>
|
|
765
|
+
<a href="https://opencollective.com/noble/backer/14/website" target="_blank"><img src="https://opencollective.com/noble/backer/14/avatar.svg"></a>
|
|
766
|
+
<a href="https://opencollective.com/noble/backer/15/website" target="_blank"><img src="https://opencollective.com/noble/backer/15/avatar.svg"></a>
|
|
767
|
+
<a href="https://opencollective.com/noble/backer/16/website" target="_blank"><img src="https://opencollective.com/noble/backer/16/avatar.svg"></a>
|
|
768
|
+
<a href="https://opencollective.com/noble/backer/17/website" target="_blank"><img src="https://opencollective.com/noble/backer/17/avatar.svg"></a>
|
|
769
|
+
<a href="https://opencollective.com/noble/backer/18/website" target="_blank"><img src="https://opencollective.com/noble/backer/18/avatar.svg"></a>
|
|
770
|
+
<a href="https://opencollective.com/noble/backer/19/website" target="_blank"><img src="https://opencollective.com/noble/backer/19/avatar.svg"></a>
|
|
771
|
+
<a href="https://opencollective.com/noble/backer/20/website" target="_blank"><img src="https://opencollective.com/noble/backer/20/avatar.svg"></a>
|
|
772
|
+
<a href="https://opencollective.com/noble/backer/21/website" target="_blank"><img src="https://opencollective.com/noble/backer/21/avatar.svg"></a>
|
|
773
|
+
<a href="https://opencollective.com/noble/backer/22/website" target="_blank"><img src="https://opencollective.com/noble/backer/22/avatar.svg"></a>
|
|
774
|
+
<a href="https://opencollective.com/noble/backer/23/website" target="_blank"><img src="https://opencollective.com/noble/backer/23/avatar.svg"></a>
|
|
775
|
+
<a href="https://opencollective.com/noble/backer/24/website" target="_blank"><img src="https://opencollective.com/noble/backer/24/avatar.svg"></a>
|
|
776
|
+
<a href="https://opencollective.com/noble/backer/25/website" target="_blank"><img src="https://opencollective.com/noble/backer/25/avatar.svg"></a>
|
|
777
|
+
<a href="https://opencollective.com/noble/backer/26/website" target="_blank"><img src="https://opencollective.com/noble/backer/26/avatar.svg"></a>
|
|
778
|
+
<a href="https://opencollective.com/noble/backer/27/website" target="_blank"><img src="https://opencollective.com/noble/backer/27/avatar.svg"></a>
|
|
779
|
+
<a href="https://opencollective.com/noble/backer/28/website" target="_blank"><img src="https://opencollective.com/noble/backer/28/avatar.svg"></a>
|
|
780
|
+
<a href="https://opencollective.com/noble/backer/29/website" target="_blank"><img src="https://opencollective.com/noble/backer/29/avatar.svg"></a>
|
|
781
|
+
|
|
782
|
+
## Sponsors
|
|
783
|
+
|
|
784
|
+
Become a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/noble#sponsor)]
|
|
785
|
+
|
|
786
|
+
<a href="https://opencollective.com/noble/sponsor/0/website" target="_blank"><img src="https://opencollective.com/noble/sponsor/0/avatar.svg"></a>
|
|
787
|
+
<a href="https://opencollective.com/noble/sponsor/1/website" target="_blank"><img src="https://opencollective.com/noble/sponsor/1/avatar.svg"></a>
|
|
788
|
+
<a href="https://opencollective.com/noble/sponsor/2/website" target="_blank"><img src="https://opencollective.com/noble/sponsor/2/avatar.svg"></a>
|
|
789
|
+
<a href="https://opencollective.com/noble/sponsor/3/website" target="_blank"><img src="https://opencollective.com/noble/sponsor/3/avatar.svg"></a>
|
|
790
|
+
<a href="https://opencollective.com/noble/sponsor/4/website" target="_blank"><img src="https://opencollective.com/noble/sponsor/4/avatar.svg"></a>
|
|
791
|
+
<a href="https://opencollective.com/noble/sponsor/5/website" target="_blank"><img src="https://opencollective.com/noble/sponsor/5/avatar.svg"></a>
|
|
792
|
+
<a href="https://opencollective.com/noble/sponsor/6/website" target="_blank"><img src="https://opencollective.com/noble/sponsor/6/avatar.svg"></a>
|
|
793
|
+
<a href="https://opencollective.com/noble/sponsor/7/website" target="_blank"><img src="https://opencollective.com/noble/sponsor/7/avatar.svg"></a>
|
|
794
|
+
<a href="https://opencollective.com/noble/sponsor/8/website" target="_blank"><img src="https://opencollective.com/noble/sponsor/8/avatar.svg"></a>
|
|
795
|
+
<a href="https://opencollective.com/noble/sponsor/9/website" target="_blank"><img src="https://opencollective.com/noble/sponsor/9/avatar.svg"></a>
|
|
796
|
+
<a href="https://opencollective.com/noble/sponsor/10/website" target="_blank"><img src="https://opencollective.com/noble/sponsor/10/avatar.svg"></a>
|
|
797
|
+
<a href="https://opencollective.com/noble/sponsor/11/website" target="_blank"><img src="https://opencollective.com/noble/sponsor/11/avatar.svg"></a>
|
|
798
|
+
<a href="https://opencollective.com/noble/sponsor/12/website" target="_blank"><img src="https://opencollective.com/noble/sponsor/12/avatar.svg"></a>
|
|
799
|
+
<a href="https://opencollective.com/noble/sponsor/13/website" target="_blank"><img src="https://opencollective.com/noble/sponsor/13/avatar.svg"></a>
|
|
800
|
+
<a href="https://opencollective.com/noble/sponsor/14/website" target="_blank"><img src="https://opencollective.com/noble/sponsor/14/avatar.svg"></a>
|
|
801
|
+
<a href="https://opencollective.com/noble/sponsor/15/website" target="_blank"><img src="https://opencollective.com/noble/sponsor/15/avatar.svg"></a>
|
|
802
|
+
<a href="https://opencollective.com/noble/sponsor/16/website" target="_blank"><img src="https://opencollective.com/noble/sponsor/16/avatar.svg"></a>
|
|
803
|
+
<a href="https://opencollective.com/noble/sponsor/17/website" target="_blank"><img src="https://opencollective.com/noble/sponsor/17/avatar.svg"></a>
|
|
804
|
+
<a href="https://opencollective.com/noble/sponsor/18/website" target="_blank"><img src="https://opencollective.com/noble/sponsor/18/avatar.svg"></a>
|
|
805
|
+
<a href="https://opencollective.com/noble/sponsor/19/website" target="_blank"><img src="https://opencollective.com/noble/sponsor/19/avatar.svg"></a>
|
|
806
|
+
<a href="https://opencollective.com/noble/sponsor/20/website" target="_blank"><img src="https://opencollective.com/noble/sponsor/20/avatar.svg"></a>
|
|
807
|
+
<a href="https://opencollective.com/noble/sponsor/21/website" target="_blank"><img src="https://opencollective.com/noble/sponsor/21/avatar.svg"></a>
|
|
808
|
+
<a href="https://opencollective.com/noble/sponsor/22/website" target="_blank"><img src="https://opencollective.com/noble/sponsor/22/avatar.svg"></a>
|
|
809
|
+
<a href="https://opencollective.com/noble/sponsor/23/website" target="_blank"><img src="https://opencollective.com/noble/sponsor/23/avatar.svg"></a>
|
|
810
|
+
<a href="https://opencollective.com/noble/sponsor/24/website" target="_blank"><img src="https://opencollective.com/noble/sponsor/24/avatar.svg"></a>
|
|
811
|
+
<a href="https://opencollective.com/noble/sponsor/25/website" target="_blank"><img src="https://opencollective.com/noble/sponsor/25/avatar.svg"></a>
|
|
812
|
+
<a href="https://opencollective.com/noble/sponsor/26/website" target="_blank"><img src="https://opencollective.com/noble/sponsor/26/avatar.svg"></a>
|
|
813
|
+
<a href="https://opencollective.com/noble/sponsor/27/website" target="_blank"><img src="https://opencollective.com/noble/sponsor/27/avatar.svg"></a>
|
|
814
|
+
<a href="https://opencollective.com/noble/sponsor/28/website" target="_blank"><img src="https://opencollective.com/noble/sponsor/28/avatar.svg"></a>
|
|
815
|
+
<a href="https://opencollective.com/noble/sponsor/29/website" target="_blank"><img src="https://opencollective.com/noble/sponsor/29/avatar.svg"></a>
|
|
816
|
+
|
|
817
|
+
## Useful links
|
|
818
|
+
|
|
819
|
+
* [Bluetooth Development Portal](http://developer.bluetooth.org)
|
|
820
|
+
* [GATT Specifications](https://www.bluetooth.com/specifications/gatt/)
|
|
821
|
+
* [Bluetooth: ATT and GATT](http://epx.com.br/artigos/bluetooth_gatt.php)
|
|
822
|
+
|
|
823
|
+
## License
|
|
824
|
+
|
|
825
|
+
Copyright (C) 2015 Sandeep Mistry <sandeep.mistry@gmail.com>
|
|
826
|
+
|
|
827
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
828
|
+
|
|
829
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
830
|
+
|
|
831
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
832
|
+
|
|
833
|
+
[](https://github.com/igrigorik/ga-beacon)
|