Espruino:Примеры/Рассылка BLE-объявлений при помощи Node.js/Python/C: различия между версиями

Материал из Онлайн справочника
Перейти к навигацииПерейти к поиску
Нет описания правки
Нет описания правки
Строка 5: Строка 5:
=Рассылка BLE-объявлений при помощи Node.js/Python/C#/Android<ref>[https://www.espruino.com/BLE+Advertising www.espruino.com - BLE Advertising with Node.js/Python/C#/Android]</ref>=
=Рассылка BLE-объявлений при помощи Node.js/Python/C#/Android<ref>[https://www.espruino.com/BLE+Advertising www.espruino.com - BLE Advertising with Node.js/Python/C#/Android]</ref>=


[Картинка]
Коммуницировать с [[Puck.js]] через [[BLE]] можно тремя разными способами:
 
* Подключитесь к [[Puck.js]] с другого устройства и отправьте данные на сервис [[Nordic UART]] (или сервис, который вы создали сами) – большинство устройств ([[ПК]], [[Mac]], [[Linux]], [[Android]]) одновременно могут быть подключены максимум к ''5-6'' устройствам.  
Коммуницировать с Puck.js через BLE можно тремя разными способами:
* Подключите [[Puck.js]] к устройству и коммуницируйте с сервисами этого устройства – большинство устройств поддерживают только одно одновременное подключение.  
* Подключитесь к Puck.js с другого устройства и отправьте данные на сервис Nordic UART (или сервис, который вы создали сами) – большинство устройств (ПК, Mac, Linux, Android) одновременно могут быть подключены максимум к 5-6 устройствам.  
* Рассылайте с помощью [[Puck.js]] объявления для устройств, находящихся в пределах BLE-диапазона – это работает только в одном направлении (от [[Puck.js]] к прослушивающему устройству), но так вы можете отправлять данные от какого угодно количества [[Puck.js]].
* Подключите Puck.js к устройству и коммуницируйте с сервисами этого устройства – большинство устройств поддерживают только одно одновременное подключение.  
* Рассылайте с помощью Puck.js объявления для устройств, находящихся в пределах BLE-диапазона – это работает только в одном направлении (от Puck.js к прослушивающему устройству), но так вы можете отправлять данные от какого угодно количества Puck.js.


Более подробно о том, что всё это значит, можно прочесть [https://www.espruino.com/About+Bluetooth+LE тут], а здесь мы сосредоточимся на способе с рассылкой BLE-объявлений.
Более подробно о том, что всё это значит, можно прочесть [https://www.espruino.com/About+Bluetooth+LE тут], а здесь мы сосредоточимся на способе с рассылкой BLE-объявлений.
Строка 19: Строка 17:
* [https://www.espruino.com/Interfacing#bluetooth-le Подключение через Node.js или Python].
* [https://www.espruino.com/Interfacing#bluetooth-le Подключение через Node.js или Python].


Чтобы преобразовать данные объявления в MQTT, можно воспользоваться программой [https://github.com/espruino/EspruinoHub EspruinoHub] (причём её также можно [https://www.espruino.com/BLE%20Node-RED использовать вместе с Node-RED]), но в этом руководстве мы сосредоточимся на написании собственного приложения-хоста.
Чтобы преобразовать данные объявления в [[MQTT]], можно воспользоваться программой [https://github.com/espruino/EspruinoHub EspruinoHub] (причём её также можно [https://www.espruino.com/BLE%20Node-RED использовать вместе с Node-RED]), но в этом руководстве мы сосредоточимся на написании собственного приложения-хоста.


Сначала нам нужно разослать BLE-объявления с данными. Это можно сделать при помощи метода NRF.setAdvertising().
Сначала нам нужно разослать BLE-объявления с данными. Это можно сделать при помощи метода NRF.setAdvertising().


Есть два главных типа рассылаемых данных:
Есть два главных типа рассылаемых данных:
* '''Сервисы''' – У каждого сервиса есть свой UUID. Он может быть 16-битным или 128-битным. 16-битные UUID [https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx присваиваются Bluetooth SIG], так что будьте внимательны и используйте правильные UUID. Вы можете задать собственные 128-битные UUID, но они, в-первых, должны быть случайными, и во-вторых, BLE-объявление очень невелико, так что после использования 128-битного UUID у вас останется мало свободного места. Например, можно воспользоваться UUID сервиса «0xFFFF» (для серийных устройств его использовать не стоит) с помощью команды NRF.setAdvertising({0xFFFF:"Hello"});.
* '''Сервисы''' – У каждого сервиса есть свой [[UUID]]. Он может быть 16-битным или 128-битным. 16-битные UUID [https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx присваиваются Bluetooth SIG], так что будьте внимательны и используйте правильные UUID. Вы можете задать собственные 128-битные UUID, но они, в-первых, должны быть случайными, и во-вторых, BLE-объявление очень невелико, так что после использования 128-битного UUID у вас останется мало свободного места. Например, можно воспользоваться UUID сервиса «0xFFFF» (для серийных устройств его использовать не стоит) с помощью команды '''NRF.setAdvertising({0xFFFF:"Hello"});'''.
* '''Данные производителя''' – Прошивка Espruino/Puck.js 1v95 и новее позволяет задать данные производителя. Это почти то же самое, как использовать сервисы с 16-битными UUID, однако для Espruino/Puck.js зарезервирован собственный 16-битный UUID (0x0590), который можно использовать для чего угодно.  
* '''Данные производителя''' – Прошивка [[Espruino]]/[[Puck.js]] 1v95 и новее позволяет задать данные производителя. Это почти то же самое, как использовать сервисы с 16-битными [[UUID]], однако для [[Espruino]]/[[Puck.js]] зарезервирован собственный 16-битный UUID (0x0590), который можно использовать для чего угодно.  


Ниже мы воспользуемся данными производителя. Подключитесь к Puck.js с помощью IDE и загрузите на него следующий код:
Ниже мы воспользуемся данными производителя. Подключитесь к [[Puck.js]] с помощью [[IDE]] и загрузите на него следующий код:


<syntaxhighlight lang="javascript" enclose="div">
<syntaxhighlight lang="javascript" enclose="div">
Строка 39: Строка 37:
</syntaxhighlight>
</syntaxhighlight>


Этот код рассылает в BLE-объявлениях один байт («0»), но с каждым нажатием на кнопку это значение будет увеличиваться.
Этот код рассылает в BLE-объявлениях один байт (''«0»''), но с каждым нажатием на кнопку это значение будет увеличиваться.


Теперь вам надо отключить онлайн-IDE от Puck.js, потому что Puck.js рассылает данные, только когда к нему не подключено никаких устройств.  
Теперь вам надо отключить онлайн-IDE от [[Puck.js]], потому что [[Puck.js]] рассылает данные, только когда к нему не подключено никаких устройств.  


Примечание: manufacturerData – это массив байтов (значений в диапазоне между 0 и 255). Более крупные значения будут обрезаны. Вы также можете задать строку – например, NRF.setAdvertising({},{manufacturer: 0x0590, manufacturerData:"Hello"});. Если указать слишком много данных (больше 21 байта), это может обернуться исключением DATA_SIZE.
'''Примечание:''' '''manufacturerData''' – это массив байтов (значений в диапазоне ''между 0 и 255''). Более крупные значения будут обрезаны. Вы также можете задать строку – например, NRF.setAdvertising({},'''{manufacturer: 0x0590, manufacturerData:"Hello"});'''. Если указать слишком много данных (''больше 21 байта''), это может обернуться исключением '''DATA_SIZE'''.


== Puck.js/Espruino ==
== Puck.js/Espruino ==


Кроме того, Puck.js умеет прослушивать BLE-объявления других устройств при помощи NRF.setScan() (для непрерывного прослушивания) или NRF.findDevices() (для прослушивания в пределах заданного периода времени и агрегации всех ответов). К примеру, вы можете запустить на другом Puck.js вот такой код...
Кроме того, [[Puck.js]] умеет прослушивать BLE-объявления других устройств при помощи NRF.setScan() (для непрерывного прослушивания) или NRF.findDevices() (для прослушивания в пределах заданного периода времени и агрегации всех ответов). К примеру, вы можете запустить на другом [[Puck.js]] вот такой код...


<syntaxhighlight lang="javascript" enclose="div">
<syntaxhighlight lang="javascript" enclose="div">
Строка 68: Строка 66:
</syntaxhighlight>
</syntaxhighlight>


Как и все прочие устройстве в пределах BLE-диапазона. После этого можно выполнить поиск manufacturer==0x0590 и извлечь передаваемые данные, прочитав поле manufacturerData.
Как и все прочие устройстве в пределах BLE-диапазона. После этого можно выполнить поиск '''manufacturer==0x0590''' и извлечь передаваемые данные, прочитав поле '''manufacturerData'''.


Примечание: Сканирование рассылаемых BLE-данных – очень энергоёмкий процесс, т.к. из-за этого Bluetooth-компоненту Puck.js нужно всегда оставаться включённым. Так что, если у вас быстро расходуется заряд батареи, лучше пользоваться этой функцией как можно реже.
'''Примечание:''' Сканирование рассылаемых BLE-данных – очень энергоёмкий процесс, т.к. из-за этого Bluetooth-компоненту [[Puck.js]] нужно всегда оставаться включённым. Так что, если у вас быстро расходуется заряд батареи, лучше пользоваться этой функцией как можно реже.


== Node.js ==
== Node.js ==


В [https://nodejs.org/en/ Node.js] есть отличный модуль под названием [https://www.npmjs.com/package/noble Noble], работающий на Windows, Mac OS и Linux.
В [https://nodejs.org/en/ Node.js] есть отличный модуль под названием [https://www.npmjs.com/package/noble Noble], работающий на [[Windows]], [[Mac OS]] и [[Linux]].
* '''В данный момент в Mac OS Mojave [https://github.com/noble/noble/issues/834 в Noble сломана поддержка BLE]''', так что лучше воспользоваться вместо него библиотекой [https://github.com/Timeular/noble-mac noble-mac].
* '''В данный момент в Mac OS Mojave [https://github.com/noble/noble/issues/834 в Noble сломана поддержка BLE]''', так что лучше воспользоваться вместо него библиотекой [https://github.com/Timeular/noble-mac noble-mac].
* Пользователи '''Windows 10 вместо Noble могут воспользоваться noble-uwp''' – там поддержка Bluetooth есть по умолчанию.
* Пользователи '''[[Windows 10]] вместо [[Noble]] могут воспользоваться noble-uwp''' – там поддержка Bluetooth есть по умолчанию.
* '''При использовании Windows вместе с [https://www.espruino.com/Quick+Start+BLE#puckjs USB-адаптером с BLE-функционалом]''' не нужно устанавливать драйвер, идущий в комплекте с этим адаптером. Это значит, что вам необязательно иметь Windows 10, но если у вас есть Windows 10 и нет поддержки BLE, то вам нужно будет дополнительно подключить USB-адаптер с BLE-функционалом.
* '''При использовании [[Windows]] вместе с [https://www.espruino.com/Quick+Start+BLE#puckjs USB-адаптером с BLE-функционалом]''' не нужно устанавливать драйвер, идущий в комплекте с этим адаптером. Это значит, что вам необязательно иметь [[Windows 10]], но если у вас есть [[Windows 10]] и нет поддержки [[BLE]], то вам нужно будет дополнительно подключить [[USB-адаптер]] с BLE-функционалом.
* Убедитесь, что у вас установлен [https://nodejs.org/en/ Node.js].
* Убедитесь, что у вас установлен [https://nodejs.org/en/ Node.js].
* Затем установите noble при помощи npm.
* Затем установите '''noble''' при помощи [[npm]].


<syntaxhighlight lang="ssh" enclose="div">
<syntaxhighlight lang="ssh" enclose="div">
Строка 90: Строка 88:
</syntaxhighlight>
</syntaxhighlight>


Теперь добавляем в advertising_nodejs.js код ниже:
Теперь добавляем в '''advertising_nodejs.js''' код ниже:


<syntaxhighlight lang="javascript" enclose="div">
<syntaxhighlight lang="javascript" enclose="div">
Строка 147: Строка 145:
</syntaxhighlight>
</syntaxhighlight>


Вы можете прочесть строчки и от других устройств, у которых есть данные производителя. Как видите, третий элемент в буфере увеличивается при каждом нажатии на кнопку Puck.js.   
Вы можете прочесть строчки и от других устройств, у которых есть данные производителя. Как видите, третий элемент в буфере увеличивается при каждом нажатии на кнопку [[Puck.js]].   


Это можно улучшить:
Это можно улучшить:
Строка 153: Строка 151:
* Чтобы нам всегда присылали обратно рассылаемые данные – даже если они не изменились.
* Чтобы нам всегда присылали обратно рассылаемые данные – даже если они не изменились.


Теперь попробуем новый код. Обязательно скопируйте адрес Puck.js из кода выше в константу devices:
Теперь попробуем новый код. Обязательно скопируйте адрес [[Puck.js]] из кода выше в константу devices:


<syntaxhighlight lang="javascript" enclose="div">
<syntaxhighlight lang="javascript" enclose="div">
Строка 208: Строка 206:
</syntaxhighlight>
</syntaxhighlight>


Теперь вы можете написать собственный обработчик для onDeviceChanged, который делал бы то, что вам нужно, когда что-то происходит на Puck.js.
Теперь вы можете написать собственный обработчик для '''onDeviceChanged''', который делал бы то, что вам нужно, когда что-то происходит на [[Puck.js]].


== Python ==
== Python ==


Вы можете сделать то же самое на Linux (включая Raspberry Pi) при помощи Python и [http://ianharvey.github.io/bluepy-doc/ библиотеки bluepy]. На данный момент на Windows и Mac OS библиотека bluepy не поддерживается.
Вы можете сделать то же самое на [[Linux]] (включая [[Raspberry Pi]]) при помощи [[Python]] и [http://ianharvey.github.io/bluepy-doc/ библиотеки bluepy]. На данный момент на [[Windows]] и [[Mac OS]] библиотека bluepy не поддерживается.


* Python почти всегда установлен на Linux.
* Python почти всегда установлен на [[Linux]].
* Сначала устанавливаем библиотеку bluepy:
* Сначала устанавливаем библиотеку bluepy:


Строка 222: Строка 220:
</syntaxhighlight>
</syntaxhighlight>


Затем используем код ниже – обработка рассылаемых данных почти такая же, как и на Node.js, за исключением того, что в этом случае тип сервиса (ffff) находится в той же переменной value, что и сами данные.
Затем используем код ниже – обработка рассылаемых данных почти такая же, как и на [[Node.js]], за исключением того, что в этом случае тип сервиса (''ffff'') находится в той же переменной '''value''', что и сами данные.


* Добавляем в advertising_python.py код ниже:
* Добавляем в '''advertising_python.py''' код ниже:


<syntaxhighlight lang="python" enclose="div">
<syntaxhighlight lang="python" enclose="div">
Строка 262: Строка 260:
</syntaxhighlight>
</syntaxhighlight>


* Затем запускаем Python-файл. Чтобы получить доступ к Bluetooth-устройству, этот файл нужно запускать с правами администратора.
* Затем запускаем [[Python]]-файл. Чтобы получить доступ к Bluetooth-устройству, этот файл нужно запускать с правами администратора.


<syntaxhighlight lang="ssh" enclose="div">
<syntaxhighlight lang="ssh" enclose="div">
Строка 280: Строка 278:
</syntaxhighlight>
</syntaxhighlight>


Обратите внимание, что data в onDeviceChanged – это шестнадцатеричная строка. Чтобы преобразовать её в целое число, воспользуйтесь int(data, 16).
Обратите внимание, что '''data''' в '''onDeviceChanged''' – это шестнадцатеричная строка. Чтобы преобразовать её в целое число, воспользуйтесь '''int(data, 16)'''.


== Универсальная платформа Windows (UWP) – C#/JS/VB ==
== Универсальная платформа Windows (UWP) – C#/JS/VB ==


Пример для Node.js выше будет работать и на Windows, но вы, возможно, захотите использовать какой-то другой язык программирования. Поддержка BLE есть только в Windows 10, так что ваше приложение будет ограничено только Windows 10 и новее.
Пример для [[Node.js]] выше будет работать и на Windows, но вы, возможно, захотите использовать какой-то другой язык программирования. Поддержка BLE есть только в [[Windows 10]], так что ваше приложение будет ограничено только [[Windows 10]] и новее.


В документации Microsoft есть пример кода для отслеживания Bluetooth-объявлений при помощи класса [https://docs.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.advertisement.bluetoothleadvertisementwatcher?view=winrt-19041 BluetoothLEAdvertisementWatcher] – посмотреть его можно [https://docs.microsoft.com/en-us/windows/uwp/devices-sensors/ble-beacon тут].
В документации [[Microsoft]] есть пример кода для отслеживания Bluetooth-объявлений при помощи класса [https://docs.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.advertisement.bluetoothleadvertisementwatcher?view=winrt-19041 BluetoothLEAdvertisementWatcher] – посмотреть его можно [https://docs.microsoft.com/en-us/windows/uwp/devices-sensors/ble-beacon тут].


Кроме того, есть [https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/BluetoothAdvertisement примеры, полностью написанные] на C#, JavaScript и Visual Basic.
Кроме того, есть [https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/BluetoothAdvertisement примеры, полностью написанные] на C#, [[JavaScript]] и [[Visual Basic]].


== Android ==
== Android ==


Для Android есть [https://developer.android.com/guide/topics/connectivity/bluetooth-le.html хорошая документация по BLE] – посмотрите раздел Find BLE Devices («Поиск BLE-устройств»).
Для [[Android]] есть [https://developer.android.com/guide/topics/connectivity/bluetooth-le.html хорошая документация по BLE] – посмотрите раздел '''Find BLE Devices («Поиск BLE-устройств»)'''.


Кроме того, по этой ссылке можно найти [https://github.com/googlearchive/android-BluetoothAdvertisements приложение-пример].
Кроме того, по этой ссылке можно найти [https://github.com/googlearchive/android-BluetoothAdvertisements приложение-пример].

Версия от 22:13, 4 марта 2021

Перевод: Максим Кузьмин
Проверка/Оформление/Редактирование: Мякишев Е.А.


Рассылка BLE-объявлений при помощи Node.js/Python/C#/Android[1]

Коммуницировать с Puck.js через BLE можно тремя разными способами:

  • Подключитесь к Puck.js с другого устройства и отправьте данные на сервис Nordic UART (или сервис, который вы создали сами) – большинство устройств (ПК, Mac, Linux, Android) одновременно могут быть подключены максимум к 5-6 устройствам.
  • Подключите Puck.js к устройству и коммуницируйте с сервисами этого устройства – большинство устройств поддерживают только одно одновременное подключение.
  • Рассылайте с помощью Puck.js объявления для устройств, находящихся в пределах BLE-диапазона – это работает только в одном направлении (от Puck.js к прослушивающему устройству), но так вы можете отправлять данные от какого угодно количества Puck.js.

Более подробно о том, что всё это значит, можно прочесть тут, а здесь мы сосредоточимся на способе с рассылкой BLE-объявлений.

Советы по использованию Bluetooth-соединения читайте тут:

Чтобы преобразовать данные объявления в MQTT, можно воспользоваться программой EspruinoHub (причём её также можно использовать вместе с Node-RED), но в этом руководстве мы сосредоточимся на написании собственного приложения-хоста.

Сначала нам нужно разослать BLE-объявления с данными. Это можно сделать при помощи метода NRF.setAdvertising().

Есть два главных типа рассылаемых данных:

  • Сервисы – У каждого сервиса есть свой UUID. Он может быть 16-битным или 128-битным. 16-битные UUID присваиваются Bluetooth SIG, так что будьте внимательны и используйте правильные UUID. Вы можете задать собственные 128-битные UUID, но они, в-первых, должны быть случайными, и во-вторых, BLE-объявление очень невелико, так что после использования 128-битного UUID у вас останется мало свободного места. Например, можно воспользоваться UUID сервиса «0xFFFF» (для серийных устройств его использовать не стоит) с помощью команды NRF.setAdvertising({0xFFFF:"Hello"});.
  • Данные производителя – Прошивка Espruino/Puck.js 1v95 и новее позволяет задать данные производителя. Это почти то же самое, как использовать сервисы с 16-битными UUID, однако для Espruino/Puck.js зарезервирован собственный 16-битный UUID (0x0590), который можно использовать для чего угодно.

Ниже мы воспользуемся данными производителя. Подключитесь к Puck.js с помощью IDE и загрузите на него следующий код:

var presses = 0;
NRF.setAdvertising({},{manufacturer: 0x0590, manufacturerData:[presses]});

setWatch(function() {                                                          
  presses++;                                                                   
  NRF.setAdvertising({},{manufacturer: 0x0590, manufacturerData:[presses]});   
}, BTN, {edge:"rising", repeat:1, debounce:20})

Этот код рассылает в BLE-объявлениях один байт («0»), но с каждым нажатием на кнопку это значение будет увеличиваться.

Теперь вам надо отключить онлайн-IDE от Puck.js, потому что Puck.js рассылает данные, только когда к нему не подключено никаких устройств.

Примечание: manufacturerData – это массив байтов (значений в диапазоне между 0 и 255). Более крупные значения будут обрезаны. Вы также можете задать строку – например, NRF.setAdvertising({},{manufacturer: 0x0590, manufacturerData:"Hello"});. Если указать слишком много данных (больше 21 байта), это может обернуться исключением DATA_SIZE.

Puck.js/Espruino

Кроме того, Puck.js умеет прослушивать BLE-объявления других устройств при помощи NRF.setScan() (для непрерывного прослушивания) или NRF.findDevices() (для прослушивания в пределах заданного периода времени и агрегации всех ответов). К примеру, вы можете запустить на другом Puck.js вот такой код...

NRF.findDevices(print)

…и в итоге получите примерно следующее:

[
  BluetoothDevice {
    "id": "de:70:d9:0c:eb:86 random",
    "rssi": -44,
    "data": new Uint8Array([2, 1, 5, 4, 255, 144, 5, 11, 20, 9, 69, 115, 112, 114, 117, 105, 110, 111, 32, 78, 82, 70, 53, 50, 56, 51, 50, 68, 75]).buffer,
    "manufacturer": 1424,
    "manufacturerData": new Uint8Array([0]).buffer,
    "name": "Puck.js eb86"
   }
 ]

Как и все прочие устройстве в пределах BLE-диапазона. После этого можно выполнить поиск manufacturer==0x0590 и извлечь передаваемые данные, прочитав поле manufacturerData.

Примечание: Сканирование рассылаемых BLE-данных – очень энергоёмкий процесс, т.к. из-за этого Bluetooth-компоненту Puck.js нужно всегда оставаться включённым. Так что, если у вас быстро расходуется заряд батареи, лучше пользоваться этой функцией как можно реже.

Node.js

В Node.js есть отличный модуль под названием Noble, работающий на Windows, Mac OS и Linux.

  • В данный момент в Mac OS Mojave в Noble сломана поддержка BLE, так что лучше воспользоваться вместо него библиотекой noble-mac.
  • Пользователи Windows 10 вместо Noble могут воспользоваться noble-uwp – там поддержка Bluetooth есть по умолчанию.
  • При использовании Windows вместе с USB-адаптером с BLE-функционалом не нужно устанавливать драйвер, идущий в комплекте с этим адаптером. Это значит, что вам необязательно иметь Windows 10, но если у вас есть Windows 10 и нет поддержки BLE, то вам нужно будет дополнительно подключить USB-адаптер с BLE-функционалом.
  • Убедитесь, что у вас установлен Node.js.
  • Затем установите noble при помощи npm.
# Устанавливаем Noble, чтобы получить поддержку BLE для Node.js:
npm install noble
# ТОЛЬКО ДЛЯ LINUX 
# Разрешаем Node.js получить доступ к BLE
# даже без запуска при помощи «sudo»:
sudo setcap cap_net_raw+eip $(eval readlink -f `which node`))

Теперь добавляем в advertising_nodejs.js код ниже:

var noble = require('noble');

function onDiscovery(peripheral) {
  // peripheral.rssi                             - мощность сигнала
  // peripheral.address                          - MAC-адрес
  // peripheral.advertisement.localName          - название устройства
  // peripheral.advertisement.manufacturerData   - данные 
                                                 - производителя 
  // peripheral.advertisement.serviceData        - обычные 
                                                 - данные сервиса, 
                                                 - рассылаемые 
                                                 - в объявлении
  // Игнорируем устройства без данных производителя:
  if (!peripheral.advertisement.manufacturerData) return;
  // Печатаем в консоли всё, что прочли:
  console.log(
    peripheral.address,
    JSON.stringify(peripheral.advertisement.localName),
    JSON.stringify(peripheral.advertisement.manufacturerData)
  );
}

noble.on('stateChange',  function(state) {
  if (state!="poweredOn") return;
  console.log("Начинаем сканирование...");
  noble.startScanning([], true);
});
noble.on('discover', onDiscovery);
noble.on('scanStart', function() { console.log("Сканирование началось."); });
noble.on('scanStop', function() { console.log("Сканирование завершилось.");})
  • И запускаем его при помощи node advertising_nodejs.js

У вас должно получиться примерно следующее:

Начинаем сканирование...
Сканирование началось.
de:70:d9:0c:eb:86 "Puck.js eb86" {"type":"Buffer","data":[144,5,0]}
de:70:d9:0c:eb:86 "Puck.js eb86" {"type":"Buffer","data":[144,5,0]}
de:70:d9:0c:eb:86 "Puck.js eb86" {"type":"Buffer","data":[144,5,0]}
de:70:d9:0c:eb:86 "Puck.js eb86" {"type":"Buffer","data":[144,5,0]}
de:70:d9:0c:eb:86 "Puck.js eb86" {"type":"Buffer","data":[144,5,1]}
de:70:d9:0c:eb:86 "Puck.js eb86" {"type":"Buffer","data":[144,5,1]}
de:70:d9:0c:eb:86 "Puck.js eb86" {"type":"Buffer","data":[144,5,2]}
de:70:d9:0c:eb:86 "Puck.js eb86" {"type":"Buffer","data":[144,5,2]}
de:70:d9:0c:eb:86 "Puck.js eb86" {"type":"Buffer","data":[144,5,3]}
de:70:d9:0c:eb:86 "Puck.js eb86" {"type":"Buffer","data":[144,5,4]}
de:70:d9:0c:eb:86 "Puck.js eb86" {"type":"Buffer","data":[144,5,5]}
de:70:d9:0c:eb:86 "Puck.js eb86" {"type":"Buffer","data":[144,5,5]}
de:70:d9:0c:eb:86 "Puck.js eb86" {"type":"Buffer","data":[144,5,5]}

Вы можете прочесть строчки и от других устройств, у которых есть данные производителя. Как видите, третий элемент в буфере увеличивается при каждом нажатии на кнопку Puck.js.

Это можно улучшить:

  • Чтобы нам сообщали обо всех устройствах с данными производителя.
  • Чтобы нам всегда присылали обратно рассылаемые данные – даже если они не изменились.

Теперь попробуем новый код. Обязательно скопируйте адрес Puck.js из кода выше в константу devices:

var noble = require('noble');

// Список разрешённых устройств:
const devices = [
  "de:70:d9:0c:eb:86"
];
// Рассылаемые BLE-данные, полученные в прошлый раз:
var lastAdvertising = {
};

function onDeviceChanged(addr, data) {
  console.log("Device ",addr,"changed data",JSON.stringify(data));
}

function onDiscovery(peripheral) {
  // Мы знаем это устройство?
  if (devices.indexOf(peripheral.address)<0) return;
  // У него есть данные производителя с UUID Espruino/Puck.js's?
  if (!peripheral.advertisement.manufacturerData ||
      peripheral.advertisement.manufacturerData[0]!=0x90 ||
      peripheral.advertisement.manufacturerData[1]!=0x05) return;
  // Считываем только наши данные:
  var data = peripheral.advertisement.manufacturerData.slice(2);
  // Проверяем на предмет изменившихся сервисов:
  if (lastAdvertising[peripheral.address] != data.toString())
    onDeviceChanged(peripheral.address, data);
  lastAdvertising[peripheral.address] = data;
}

noble.on('stateChange',  function(state) {
  if (state!="poweredOn") return;
  console.log("Начинаем  сканирование...");
  noble.startScanning([], true);
});
noble.on('discover', onDiscovery);
noble.on('scanStart', function() { console.log("Сканирование началось."); });
noble.on('scanStop', function() { console.log("Сканирование завершилось.");});

В итоге получаем:

Начинаем сканирование...
Сканирование началось.
Device  de:70:d9:0c:eb:86 changed data {"type":"Buffer","data":[5]}
Device  de:70:d9:0c:eb:86 changed data {"type":"Buffer","data":[6]}
Device  de:70:d9:0c:eb:86 changed data {"type":"Buffer","data":[7]}
Device  de:70:d9:0c:eb:86 changed data {"type":"Buffer","data":[8]}
Device  de:70:d9:0c:eb:86 changed data {"type":"Buffer","data":[9]}
Device  de:70:d9:0c:eb:86 changed data {"type":"Buffer","data":[10]}

Теперь вы можете написать собственный обработчик для onDeviceChanged, который делал бы то, что вам нужно, когда что-то происходит на Puck.js.

Python

Вы можете сделать то же самое на Linux (включая Raspberry Pi) при помощи Python и библиотеки bluepy. На данный момент на Windows и Mac OS библиотека bluepy не поддерживается.

  • Python почти всегда установлен на Linux.
  • Сначала устанавливаем библиотеку bluepy:
sudo apt-get install python-pip libglib2.0-dev
sudo pip install bluepy

Затем используем код ниже – обработка рассылаемых данных почти такая же, как и на Node.js, за исключением того, что в этом случае тип сервиса (ffff) находится в той же переменной value, что и сами данные.

  • Добавляем в advertising_python.py код ниже:
from bluepy.btle import Scanner, DefaultDelegate

def onDeviceChanged(addr, data):
  print "Device %s, value %s" % (addr,data)

# Устройства, которые мы ищем:
devices = [
  "de:70:d9:0c:eb:86"
];
# Данные, которые были получены в прошлый раз:
lastAdvertising = {}

# Считываем данные сканирования:
class ScanDelegate(DefaultDelegate):
  def __init__(self):
    DefaultDelegate.__init__(self)
  def handleDiscovery(self, dev, isNewDev, isNewData):
    if not dev.addr in devices: return
    for (adtype, desc, value) in dev.getScanData():
      if adtype==255 and value[:4]=="9005": # Данные производителя
        data = value[4:]
        if not dev.addr in lastAdvertising or lastAdvertising[dev.addr] != data:
          onDeviceChanged(dev.addr, data)
        lastAdvertising[dev.addr] = data

# Начинаем сканирование:
scanner = Scanner().withDelegate(ScanDelegate())
scanner.clear()
scanner.start()
# Продолжаем сканировать 10-секундными отрезками:
while True: scanner.process(10)
# Если хотим закончить, нужно вызвать stop():
scanner.stop()
  • Затем запускаем Python-файл. Чтобы получить доступ к Bluetooth-устройству, этот файл нужно запускать с правами администратора.
sudo python advertising_python.py

И вы получите примерно следующее:

Device de:70:d9:0c:eb:86, value 35
Device de:70:d9:0c:eb:86, value 37
Device de:70:d9:0c:eb:86, value 39
Device de:70:d9:0c:eb:86, value 3a
Device de:70:d9:0c:eb:86, value 3b
Device de:70:d9:0c:eb:86, value 3c
Device de:70:d9:0c:eb:86, value 3d

Обратите внимание, что data в onDeviceChanged – это шестнадцатеричная строка. Чтобы преобразовать её в целое число, воспользуйтесь int(data, 16).

Универсальная платформа Windows (UWP) – C#/JS/VB

Пример для Node.js выше будет работать и на Windows, но вы, возможно, захотите использовать какой-то другой язык программирования. Поддержка BLE есть только в Windows 10, так что ваше приложение будет ограничено только Windows 10 и новее.

В документации Microsoft есть пример кода для отслеживания Bluetooth-объявлений при помощи класса BluetoothLEAdvertisementWatcher – посмотреть его можно тут.

Кроме того, есть примеры, полностью написанные на C#, JavaScript и Visual Basic.

Android

Для Android есть хорошая документация по BLE – посмотрите раздел Find BLE Devices («Поиск BLE-устройств»).

Кроме того, по этой ссылке можно найти приложение-пример.

См.также

Внешние ссылки