Робимо стартап просто і технологічно. Маячки Eddystone

Ви коли-небудь були в Луврі? Добралися до Мона-Лізи? Якщо так, то напевно ви побачили лише велику чергу перед нею, а саму картину лише здалеку і не у повний розмір. Люди хочуть вивчити детальніше полотно, запам'ятати кожну його деталь, дізнатися про нього всі подробиці, тому вони надовго залишаються поруч з ним. Але що, якщо всю цю інформацію перенести прямо в смартфон? Зробити так, щоб картина сама розповіла пристрою про себе, а воно передало інформацію вам?


Стаття автора Олексія Набережного, в рамках проекту «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) є зашифрованим ідентифікатором, що дозволяє реєструвати маячок у ВЕБ-сервісах. Він підтримує AES-шифрування, так само як Eddystone-TLM останньої версії. В цілях безпеки при встановленні зв'язку пристрої обмінюються відкритими ключами, а маячок змінює ідентифікатор псевдо-випадково (з проміжком від 1 секунди до 9 годин). Для налаштування Eddystone маячків Google винайшла відкритий стандарт GATT Service Configuration. Докладніше про протокол 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 with intent install fallback. Там є 3 поля – 2 використовуємо для вибору интента, а в одне пишемо ім'я пакета бажаного програми. Якщо додаток не встановлено, нас перекине в Google Play. В іншому випадку з додатком буде відправлений интент.

  • Ще один варіант — App with intent 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 мільйонів.

Висновок
Сподіваємося, що після прочитання цієї статті ви зацікавитесь новими технологіями. Ми впевнені, що через кілька років маячки стануть частиною повсякденного життя нарівні зі смартфонами.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.