Вы когда-нибудь были в Лувре? Добрались до Мона-Лизы? Если да, то наверняка вы увидели лишь большую очередь перед ней, а саму картину лишь издалека и не в полный размер. Люди хотят изучить подробнее полотно, запомнить каждую его деталь, узнать о нем все подробности, поэтому они надолго остаются рядом с ним. Но что, если всю эту информацию перенести прямо в смартфон? Сделать так, чтобы картина сама рассказала устройству о себе, а оно передало информацию вам?


Статья автора Алексея Набережного, в рамках проекта «Devces Lab от Google».

В этой статье мы опишем технологии iBeacon и Eddystone, которые вполне могут решить нашу проблему. Эти технологии используют маленькие Bluetooth Low Energy устройства – так называемые маячки. Мы расскажем, что такое маячки, как они устроены и как с ними работать.

Маячок для инженера-программиста


Посмотрим, что из себя представляет маячок. На обзор habrahabr.ru предоставил модель iBKS105, произведённую Accent Systems. Маячок представляет из себя небольшую круглую коробочку с наклеенным двусторонним скотчем с одной стороны для удобного закрепления на любых поверхностях, например, на стекле магазина.



Вот так он выглядит:



Маячок может работать от одной батарейки CR2477 целых 40 месяцев благодаря BLE модулю NRF51822, произведённому компанией Nordic Semiconductors. При этом iBKS105 поддерживает протоколы iBeacon и Eddystone, посылая максимум 5 Advertisment-пакетов (1 для iBeacon и 4 для Eddystone).

iBeacon, закрытая технология, представленная Apple в 2013 году, предусматривает трансляцию одного пакета, содержащего UUID (16 байт), Major и Minor (ещё по 2 байта), а также TX Power (1 байт): итого 21 байт. UUID обычно используется для определения приложения, работающего с маячком, Major – для определения группы маячков, а Minor – для определения номера маячка в группе. Apple предлагает использовать утилиту UUIDGEN для генерации этой информации и приводит следующий пример определения маячка в магазине.



Apple предлагает закрытый стандарт настройки маячков. Однако для получения информации о нем необходимо получить лицензию iBeakon License.

Технологию Eddystone придумала Google в июле 2015. В отличие от iBeacon, стандарт Eddystone является открытым и поэтому поддерживается устройствами на базе любых операционных систем. Eddystone может куда больше, чем его конкурент: он транслирует до 4-х пакетов даных – Eddystone-UID (20 байт), Eddystone-URL (до 20 байт), Eddystone-TLM (14 или 18 байт) и, с 14 марта 2016, Eddystone-EID (10 байт). Eddysone-UID – это аналог пакета, используемого в iBeacon, в то время как Eddystone-URL передает какой-либо URL адрес, который может быть открыт на устройстве, принимающем пакет. Eddystone-TLM пакет содержит телеметрическую информацию, такую как напряжение батареи передатчика, температура окружающей среды, время с момента включения и др. Eddystone-EID (Ephemeral IDs) является зашифрованным идентификатором, позволяющим регистрировать маячок в WEB сервисах. Он поддерживает AES-шифрование, равно как Eddystone-TLM последней версии. В целях безопасности при установлении связи устройства обмениваются открытыми ключами, а маячок меняет идентификатор псевдо-случайно (с промежутком от 1 секунды до 9 часов). Для настройки Eddystone маячков Google изобрела открытый стандарт GATT Configuration Service. Подробнее про протокол Eddystone можно узнать по ссылке на Github.

Настройка маячка


Как уже было сказано, наш маячок умеет работать как с iBeacon, так и с Eddystone. Accent Systems выпустила приложения iBKS Config Tool для iOS и Android, позволяющие настраивать их маячки. По умолчанию маячок может войти в режим настройки только в первые 30 секунд после включения, так что, приобретая маячок, не спешите вытягивать защитный язычок! В противном случае маячок придется открыть и извлечь батарейку, а после вставить её обратно.

Приложение для Android имеет больше преимуществ, так как позволяет видеть телеметрическую информацию. При попытке подключения к маячку будет запрошен пароль, записанный в энергонезависимую память, если он был установлен.



Затем можно выбрать режим, в котором работает маячок – iBeacon, Eddystone UID, Eddystone URL или смесь этих режимов. Eddystone-EID пакеты рассылаются, если включен один из режимов Eddystone.



Дальше уже можно попробовать и иные виды настроек:

  • выбрать силу сигнала, частоту рассылки пакетов (0.1 – 10 секунд);
  • установить пароль, выбрать URL и UID;
  • активировать режим разработчика, позволяющий подключаться к маячку в любое время и передавать телеметрические пакеты в режиме iBeacon;
  • выполнить калибровку для передачи параметра силы сигнала. Такая настройка желательна для новых маячков. Чтобы её выполнить, нужно замерить силу на определенном расстоянии от маячка и вписать её в нужное поле конфигуратора.

Обратите внимание, что, если на устройстве не установлено никаких приложений, работающих с маячками, iOS никак не отреагирует на их появление, в то время как Android должен показать уведомление (используя Google Play Services). Мы проверяли маячки с помощью iPhone. Как выяснилось, сделать это проще всего, воспользовавшись Google Chrome.



Inside Android SDK


Попробуем посмотреть на то, что посылает нам маячок.

Создадим тестовый проект BeaconNotifier и добавим permissions BLUETOOTH и BLUETOOTH_ADMIN. Также разметим наши будущие Reciever и Service: Reciever будет отлавливать изменение состояния Bluetooth, а Service – искать наши маячки.

   <<b>uses-permission android:name="android.permission.BLUETOOTH"</b> />
   <<b>uses-permission android:name="android.permission.BLUETOOTH_ADMIN"</b> />

   <<b>uses-feature android:name="android.hardware.bluetooth_le" android:required="true"</b> />
   <<b>application …</b>>
       <<b>activity android:name=".MainActivity"</b>>
           <<b>intent-filter</b>>
               <<b>action android:name="android.intent.action.MAIN"</b> />
               <<b>category android:name="android.intent.category.LAUNCHER"</b> />
           </<b>intent-filter</b>>
       </<b>activity</b>>

       <<b>receiver android:name=".BTReceiver"</b>>
           <<b>intent-filter</b>>
               <<b>action android:name="android.bluetooth.adapter.action.STATE_CHANGED"</b> />
               <<b>action android:name="ru.racoondeveloper.beaconnotifyer.WAKE_RECEIVER"</b>/>
           </<b>intent-filter</b>>
       </<b>receiver</b>>
       <<b>service android:name=".BService"</b> />
   </<b>application</b>>

Reciever отлавливает два Action – включение, выключение Bluetooth, а также интент, который мы сами будем отсылать при открытии приложения, чтобы в первый раз оживить наш сервис.

<b>public class</b> BTReceiver <b>extends</b> BroadcastReceiver {
   <b>private</b> Intent <b>BServiceIntent</b>;

   @Override
   <b>public void</b> onReceive(Context context, Intent intent) {
       <b>final</b> String action = intent.getAction();
       <b>if</b> (action.equals(BluetoothAdapter.<i><b>ACTION_STATE_CHANGED</i></b>)) {
           <b>final int</b> state = intent.getIntExtra(BluetoothAdapter.<i><b>EXTRA_STATE</i></b>, BluetoothAdapter.<i><b>ERROR</i></b>);
          
 <b>if</b> (state == BluetoothAdapter.<i><b>STATE_TURNING_OFF</i></b>) {
               <i>// Bluetooth выключился — убиваем сервис</i>
               <b>if</b> (<b>BServiceIntent</b> != <b>null</b>) {
                   context.stopService(<b>BServiceIntent</b>);
                   <b>BServiceIntent</b> = <b>null</b>;
               }
           }
           <b>if</b> (state == BluetoothAdapter.<i><b>STATE_ON</i></b>) {
               <i>// Bluetooth включился — запускаем сервис</i>
               <b>if</b> (<b>BServiceIntent</b> == <b>null</b>) {
                   <b>BServiceIntent</b> = <b>new</b> Intent(context, BService.<b>class</b>);
                   context.startService(<b>BServiceIntent</b>);
               }
           }
       }
       <b>if</b> (action.equals(<b>"ru.racoondeveloper.beaconnotifyer.WAKE_RECEIVER"</b>)) {
           <i>// Поймали событие запуска приложения — запускаем сервис</i>
           <b>if</b> (<b>BServiceIntent</b> == <b>null</b>) {
               <b>BServiceIntent</b> = <b>new</b> Intent(context, BService.<b>class</b>);
               context.startService(<b>BServiceIntent</b>);
           }
       }
   }
}

Service будет содержать поток, который ищет устройства Bluetooth Low Energy. Когда находим устройство, выдаем уведомление и продолжаем поиск.

<b>public class</b> BService <b>extends</b> Service {
   BeaconFinderThread <b>thread</b>;
   <b>boolean live </b>= <b>true</b>;

   @Override
   <b>public</b> IBinder onBind(Intent arg0) {
       <b>return null</b>;
   }

   @Override
   <b>public int</b> onStartCommand(Intent intent, <b>int</b> flags, <b>int</b> startId) {
       <i>// создаем экземпляр потока и запускаем его</i>
       <b>thread </b>= <b>new</b> BeaconFinderThread();
       <b>thread</b>.start();
       <b>return <i>START_STICKY</i></b>;
   }

   @Override
   <b>public void</b> onDestroy() {
       <i>// останавливаем поток</i>
       <b>live </b>= <b>false</b>;
       <b>thread </b>= <b>null</b>;
       <b>super</b>.onDestroy();
   }

   <b>private class</b> BeaconFinderThread <b>extends</b> Thread{
       @Override
       <b>public void</b> run() {
           <i>// создаем экземпляры BluetoothAdapter и BluetoothLeScanner</i>
           <b>final</b> BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.<i>getDefaultAdapter</i>();
           <b>final</b> BluetoothLeScanner mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();

           <i>// когда устройство будет обнаружено, будет вызван колбек</i>
           ScanCallback mScanCallback = <b>new</b> ScanCallback() {
               @Override
               <b>public void</b> onScanResult(<b>int</b> callbackType, ScanResult result) {
                   <i>// собираем данные о результате поиска</i>
                   ScanRecord mScanRecord = result.getScanRecord();
                   mScanRecord.

                   String resulty = result.getDevice().getAddress() + <b>" — "</b>
                           + result.getRssi() + <b>" — "</b>
                           + mScanRecord.getDeviceName();

                   <i>// показываем уведомление!</i>
                   showNotification(resulty);

                   <i>// повторяем поиск, пока не указано, что поток остановлен</i>
                   <b>if</b> (mBluetoothAdapter.getState() == BluetoothAdapter.<i><b>STATE_ON </i></b>&& <b>live</b>)
                       mBluetoothLeScanner.startScan(<b>this</b>);
               }
           };
           <b>if</b> (mBluetoothAdapter.getState() == BluetoothAdapter.<i><b>STATE_ON </i></b>&& <b>live</b>)
               mBluetoothLeScanner.startScan(mScanCallback);
           <b>super</b>.run();
       }
   }

   <b>private void</b> showNotification(String name) {
       <i>// отправляем уведомление</i>
       Context context = getApplicationContext();
       Intent notificationIntent = <b>new</b> Intent(context, MainActivity.<b>class</b>);
       PendingIntent contentIntent = PendingIntent.<i>getActivity</i>(context,
               0, notificationIntent,
               PendingIntent.<i><b>FLAG_CANCEL_CURRENT</i></b>);
       Notification.Builder builder = <b>new</b> Notification.Builder(context);

       builder.setContentIntent(contentIntent)
               .setSmallIcon(R.mipmap.<i><b>ic_launcher</i></b>)
               .setContentTitle(<b>"Device found"</b>)
               .setContentText(name);
       Notification notification = builder.build();

       NotificationManager notificationManager = (NotificationManager) context
               .getSystemService(Context.<i><b>NOTIFICATION_SERVICE</i></b>);
       notificationManager.notify(0, notification);
   }

}

Это все, что нужно сделать, чтобы получить данные с маячка. Вот что у нас получилось:


Исходный код приложения доступен на Github.

К сожалению, нам придется установить специальное приложение для получения информации от маячков. Но ведь не у всех пользователей оно установлено. Гораздо проще включить Bluetooth на телефоне и сразу получать нужную информацию, не устанавливая приложение. В этом нам поможет Google.

Google


Нужно признать, что Google вторгся в наш мир. ОС Android, которая занимает 82.8% рынка смартфонов, давно уже потеснила iOS. Многие пользователи iOS предпочитают устанавливать браузер Google Chrome на свой смартфон. Неудивительно, что Google стала компанией, чье имя тесно связано с такой перспективной разработкой, как маячки. Существуют несколько интернет-сервисов, помогающих дополнять тот малый объем информации, который способны передавать эти BLE девайсы, например, pubnub, но Google внедрил поддержку своего облачного сервиса прямо в Google Play Services, которые можно найти практически на любом Android устройстве. Поэтому можно сказать, что Google является монополистом в этой области. Поэтому в нашей статье мы будем рассматривать именно сервисы Google.



Настройка маячка


Как известно, Google в своём арсенале имеет огромное количество сервисов для разработчиков.

Сервис Google, работающий с маячками, доступен по следующей ссылке: https://developers.google.com/beacons/dashboard. Google нас тепло встречает таким уведомлением:





Для использования сервиса необходимо перевести маячок в режим передачи Eddystone – UID или URL. Для этого действия нам пришлось обновить iBKS105, используя приложение nRF Connect.

Подключаем маячок к сервису Google Beacons


Скачаем приложение Beacon Tools (оно доступно для iOS и для Android). Входим туда под своим Google аккаунтом и выбираем наш проект. Маячок появится во вкладке «Unregistered». Выберем его и нажмем «Register Beacon». Готово, маячок добавлен в наш проект.


Теперь мы увидели маячок на сайте. Это хороший знак.



Выберем его для настройки.

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



Параметр стабильности определяет, стационарен маячок или движется. Если маячок лежит в магазине, логично определить место на карте и этаж, а также указать, что он стационарен. А если приклеить маячок на лобовое стекло автобуса, то стоит указать, что он портативный, а также не указывать место и этаж (только если мы не в Лондоне).

Теперь нужно заставить маячок передавать действительно нужную нам информацию. Откроем выпадающий список «View beacon details» и выберем «Nearby Notifications».



Сначала мы видим всего лишь 4 текстовых поля, но не стоит недооценивать возможности маячков! Итак, что может нам рассказать маячок, подключенный к Google Cloud? Он может:

  • передать URL адрес;
  • предложить установить на устройство приложение;
  • отправить интент в систему, открывая приложение, если оно установлено.

Зададим имя уведомления в поле Title, а его описание – в поле Description. Поле language служит для определения языка уведомления, чтобы пользователи могли видеть контент на их родном языке. Язык задает ISO 639-1 код (чаще всего 2 строчные буквы, например, ru).

Дальше мы видим выпадающий список.



  • Web URL выбираем, если хотим, чтобы маячок передавал какой-либо сетевой адрес. Для настройки предлагается всего одно поле – сам адрес. В отличие от обычного Eddystone-URL мачка, маячок, использующий сервис Google, также передаст свое описание. Еще одним плюсом является передача ссылок любой длины, в отличие от 16 символов Eddystone-URL протокола.

  • Если хотим, чтобы маячок рекламировал пользователям какое-либо приложение, выбираем App intent with install fallback. Там есть 3 поля – 2 используем для выбора интента, а в одно пишем имя пакета желаемого приложения. Если приложение не установлено, нас перебросит в Google Play. В противном случае приложению будет отправлен интент.

  • Еще один вариант — App intent with web URL fallback. Он аналогичен предыдущему, но, если приложение не установлено на устройстве пользователя, нас отправят на указанный URL адрес.

Когда мы закончим с этими настройками, надо нажать на кнопку Create. Это сохранит наши труды.

Теперь мы можем проверить результат. Для этого надо на устройстве Android выбрать в настройках Google -> Nearby Notifications -> Scan. Мы должны увидеть данные, которые мы настраивали в конфигураторе на сайте.



Трудна ли настройка Eddystone


Сразу становится очевидно, что маячки – технология для программистов. Нам пришлось 4 часа сидеть за столом и пытаться все оптимизировать. Мы перепрошили Beacon, разбирались с локализацией, подбирали различные Property. Это при условии, что мы сильны в понимании Package, Exported, Action, Intent, Binder и многих других Android-терминов.

Хочется, чтобы у пользователя все работало, не надо было ничего устанавливать, чтобы действия по настройке смартфона были очень простыми.

Возникает мысль о создании Market Place — сервиса, связывающего людей, которые хотят организовать IT-мероприятие (заказчиков), и людей, которые готовы настроить маячки (исполнителей). Это будет самая обычная доска объявлений о предложениях по организации IT-мероприятий с маячками.

Например, однажды исполнителю придет уведомление:


Исполнитель вспомнит, что на нашем сервисе он взял заказ на замену автомобильных номеров Eddystone-маячками. Это поможет дорожным службам идентифицировать автомобили и уменьшить количество угнанных машин. Исполнив его, руководствуясь нашей статьей, он получит вознаграждение, а мир – технологию.

Свою машину мы уже зарегистрировали, осталось всего 7 миллионов.

Заключение


Надеемся, что после прочтения данной статьи вы заинтересуетесь новыми технологиями. Мы уверены, что через несколько лет маячки станут частью повседневной жизни наравне со смартфонами.
Поделиться с друзьями
-->

Комментарии (7)


  1. EminH
    14.11.2016 15:32

    замену автомобильных номеров Eddystone-маячками

    с таким же уровнем безопасности? я так понимаю подделать маячок даже легче чем госномер?


    1. inwady
      15.11.2016 23:41

      Мы рассказали немного в статье о безопасности. Кстати, Eddystone отличается от других продуктов как раз своим применением шифров. Нельзя будет просто взять и подделать маячок, так как он для других передает кучу «кракозябр».


  1. site6893
    14.11.2016 16:50

    все єта техническая «крутота» легко заменяется QR кодом на входе в музей, в зал с картиной (ну елси к картине недоступится) и на самой картине, и довольно простым софтварным решением.

    это в разы проще, разрабатывать, обслужывать и пользоватся.


    1. inwady
      15.11.2016 23:45

      QR код имеет ряд недостатков. Например, 50% людей просто не увидят QR. А многим и просто будет лень открывать приложение (устанавливать его).


  1. Sway
    15.11.2016 13:38

    Для некоторых Питерских музеев уже есть приложение с навигацией и экскурсиями на основе bluetooth маячков — IndoorGuide называется. Довольно хорошо работает, надо сказать.


    1. inwady
      15.11.2016 23:48

      Сам хотел реализовать подобную идею. Спасибо, что показали. :)
      А так, очень достойная реализация идеи с маячками.


  1. madkite
    24.11.2016 17:13

    > заказ на замену автомобильных номеров Eddystone-маячками
    Это помимо видеорегистратора все в России дружно будут рядом ставить какой-нибудь маячкорегистратор? ИМХО, в видео есть куча шума, что делает подделку сложнее, чем запись маячкорегистратора, в итоге при разборе ДТП вряд ли это будут считать доказательством.