Маяки Bluetooth — это невероятно ценный способ настройки триггеров на основе местоположения для приложений. Estimote имеет ряд Bluetooth-маяков, которые довольно легко установить и поэкспериментировать.
Одной из трудных частей тестирования маяков Bluetooth является то, что имитаторы устройств не могут получить доступ к устройствам Bluetooth, поэтому для тестирования необходимо использовать физические смартфоны. Вот где Evothings очень пригодится! Evothings — это простой и удобный способ создания прототипов мобильных веб-приложений с использованием HTML5 и JavaScript. В Evothings вы можете вносить изменения в свой код и автоматически отображать их на своем смартфоне с доступом к вашим маякам Bluetooth.
В этой статье мы рассмотрим объединение возможностей Evothings с маяками Estimote для создания прототипа мобильного приложения с поддержкой маяков. В частности, мы будем создавать приложение, которое включает и выключает свет LIFX через IFTTT, если вы приближаетесь к маяку. Нет света LIFX? Не проблема! Вы можете заменить эту функцию на любые другие HTTP-запросы, которые вы хотите переключать, когда находитесь поблизости.
Что вам нужно
- Estimote Beacon
- Evothings Studio — это нужно будет установить и запустить на вашем компьютере. Он доступен для Windows, Mac OSX и Linux!
- Приложение Evothings Viewer — оно должно быть установлено на устройстве iPhone или Android, на котором вы будете тестировать.
- IFTTT и знание того, как использовать их канал Maker — у меня есть руководство по этому вопросу здесь!
- Некоторые базовые знания HTML и JavaScript.
Код
Весь код для этого доступен на GitHub для использования по вашему желанию!
Настройка ваших маяков Estimote
Перейдите в Estimote Cloud и войдите в свою учетную запись (или зарегистрируйтесь, если у вас еще нет маяков!).
Оттуда ваш раздел «Маяки» уже должен быть загружен. Если у вас еще нет привязанных к вашей учетной записи маяков, вам необходимо либо купить некоторые с помощью кнопки «Купить маяки», либо перенести их с другого счета с помощью кнопки «Передать маяки», либо активировать свой комплект разработчика, если он появился. с кодом активации:
Если у вас есть маяки, они появятся в списке. Выберите тот, который вы хотите использовать в этой демонстрации, и нажмите кнопку «Настройки»:
Здесь вы захотите принять к сведению MAC-адрес маяка, так как мы будем использовать его позже:
Это должно быть все, что вам нужно с точки зрения настройки маяка Estimote — это довольно просто на уровне прототипирования.
Запуск Evothings
Чтобы настроить рабочий процесс Evothings, готовый для нашего кодирования, перейдите на страницу загрузки Evothings и загрузите мобильное приложение Evothings Studio и Evothings Viewer. Это дает нам действительно простой способ создать наше приложение и мгновенно проверить изменения на смартфоне.
Когда вы впервые открываете Evothings Studio, вам будет предложено подключиться, получив ключ подключения. Нажмите «Получить ключ», чтобы создать ключ, который вы будете использовать для сопряжения своего рабочего места с мобильным приложением:
Затем откройте Evothings на своем смартфоне, и вас встретит экран, который запрашивает эту кнопку подключения. Введите его и нажмите «Подключиться»:
Когда вы подключены и готовы к работе, вы увидите этот экран:
Теперь вы готовы заняться кодированием приложения.
Наш HTML
HTML-код для этого приложения в основном взят из шаблонов Evothings, которые они предоставили публично, только с измененным заголовком и заголовками, а также добавлением <div id="in-room"></div>
для некоторых основных сообщений о состоянии появляются на экране.
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, user-scalable=no initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0" /> <title>Magical room light automation</title> <style> @import 'ui/css/evothings-app.css'; @import 'ui/css/patcat.css'; </style> <script> // Redirect console.log to Evothings Workbench. if (window.hyper && window.hyper.log) { console.log = hyper.log } </script> <script src="cordova.js"></script> <script src="libs/jquery/jquery.js"></script> <script src="libs/evothings/evothings.js"></script> <script src="libs/evothings/ui/ui.js"></script> <script src="app.js"></script> </head> <body> <header> <button class="back" onclick="history.back()"> <img src="ui/images/arrow-left.svg" /> </button> <img class="logotype" src="ui/images/logo.svg" alt="Evothings" /> </header> <h1>Magical room light automation</h1> <div id="in-room"></div> </body> </html>
Я также поместил свой собственный CSS в ui/css/patcat.css
:
html, body, section, main footer { background: #390066; color: #fff; text-align: center; } header { background: #EACFF3; } .in-room, .in-room body, .in-room section, .in-room main footer { background: #F3EC97; color: #333; } .in-room h1 { color: #333; } .in-room header { background: #F3EDE6; } h1 { padding: 0 0 1em; }
Наш код JavaScript
Наш файл app.js
выглядит так:
var app = (function() { var app = {}, roomBeacon, updateTimer = null, inRoom = false; app.initialize = function() { document.addEventListener("deviceready", function() { evothings.scriptsLoaded(onDeviceReady); }, false); }; function onDeviceReady() { startScan(); $("#in-room").html("Out of room!"); updateTimer = setInterval(checkForBeacon, 1000); } function startScan() { function onBeaconsRanged(beaconInfo) { for (var i in beaconInfo.beacons) { var beacon = beaconInfo.beacons[i]; if (beacon.rssi = 2 && inRoom) { console.log("Exited the room"); inRoom = false; $("html").removeClass("in-room"); $("#in-room").html("Out of room!"); turnOffBulb(); setTimeout(turnOnBulb, 1000); } } } function turnOnBulb() { $.getJSON("https://maker.ifttt.com/trigger/entered_room/with/key/{YOURKEYHERE}?jsoncallback=?", { format: "json" }, function() { console.log("Entered room and told IFTTT about it!"); }) .done(function(data) { console.log("Done"); }) .fail(function(data) { console.log(JSON.stringify(data)); }) .always(function(data) { console.log("Finished"); }); console.log("Turn on bulb"); } function turnOffBulb() { $.getJSON("https://maker.ifttt.com/trigger/left_room/with/key/{YOURKEYHERE}?jsoncallback=?", { format: "json" }, function() { console.log("Left room and told IFTTT about it!"); }) .done(function(data) { console.log("Done"); }) .fail(function(data) { console.log(JSON.stringify(data)); }) .always(function(data) { console.log("Finished"); }); console.log("Turn off bulb"); } return app; })(); app.initialize();
Наш код JavaScript объяснил
Давайте упростим это немного, чтобы шагнуть через. Наш начальный скелет для кода выглядит так:
var app = (function() { var app = {}, roomBeacon, updateTimer = null, inRoom = false; app.initialize = function() { document.addEventListener("deviceready", function() { // What we'll want to do when our app is ready! }, false); }; // Other code will be here! return app; })(); app.initialize();
В приведенном выше коде мы именуем все внутри app
. Переменная roomBeacon
хранит наш маяк, как только мы его updateTimer
, updateTimer
будет хранить наш регулярный интервал JavaScript для проверки маяков, а inRoom
запомнит, считает ли приложение, что мы находимся в комнате (в зависимости от того, видит ли маяк в радиусе действия или нет). ).
Когда наш JavaScript запускается, мы направляем его в app.initialize()
. Однако мы не выполняем никаких функций, пока не deviceReady
событие evothings.scriptsLoaded
событие evothings.scriptsLoaded
. Таким образом, мы знаем, что приложение загрузилось, и Evothings готова наблюдать и перезагружать любые изменения.
function onDeviceReady() { startScan(); $("#in-room").html("Out of room!"); updateTimer = setInterval(checkForBeacon, 1000); }
В onDeviceReady()
мы начинаем сканирование на наличие маяков (скоро мы рассмотрим startScan()
). Затем мы устанавливаем наш элемент #in-room
в нашем HTML, чтобы сказать «Out of room!» По умолчанию.
Затем мы запускаем checkForBeacon()
каждую секунду, который оценивает, как далеко находится наш маяк, и решает, находимся ли мы в комнате или нет.
Наша startScan()
выглядит так:
function startScan() { function onBeaconsRanged(beaconInfo) { // Will explain this soon! } function onError(errorMessage) { console.log("Ranging beacons did fail: " + errorMessage); } estimote.beacons.requestAlwaysAuthorization(); estimote.beacons.startRangingBeaconsInRegion( {}, onBeaconsRanged, onError); }
Все функции функции startScan()
начинаются с estimote.beacons.startRangingBeaconsInRegion()
. Запустится наше приложение для сканирования маяков Estimote. Мы проходим три вещи:
- Пустой объект (
{}
) для представления того, что нам нужны все маяки. Вместо этого мы можем передать регион, который мы определили в опциях маяка Estimote, например:{identifier:'MyRegion'}
. - Наша функция успеха, которую мы хотим запустить, когда мы успешно искали маяки в диапазоне (
onBeaconsRanged()
). - Наша функция сбоя, если что-то идет не так (
onError()
— относительно простая функция, которая регистрирует ошибку).
Внутренняя часть нашей функции onBeaconsRanged()
выглядит так:
function onBeaconsRanged(beaconInfo) { for (var i in beaconInfo.beacons) { var beacon = beaconInfo.beacons[i]; if (beacon.rssi < 0 && beacon.macAddress == "CE:95:71:43:C9:DD") { console.log("Found room beacon"); roomBeacon = beacon; } } }
Это получает массив с именем beaconInfo
с подробной информацией обо всех маяках, которые видны для устройства. Наши маяки находятся в beaconInfo.beacons
, поэтому мы перебираем их все и проверяем их RSSI (индикацию уровня принимаемого сигнала) и MAC-адрес. Если их RSSI имеет отрицательное значение, наше приложение обнаружило маяк. Затем мы проверяем, совпадает ли MAC-адрес нашего маяка с тем маяком, который мы ищем. Если это так, мы регистрируем событие в нашей консоли и устанавливаем нашу переменную roomBeacon
в этот маяк.
Для iOS 8 ваше приложение должно запрашивать разрешение на использование служб определения местоположения (на других платформах эта функция будет постепенно ухудшаться и ничего не делать):
estimote.beacons.requestAlwaysAuthorization();
Вы помните, что мы запускали функцию checkForBeacon()
каждую секунду. Эта функция выглядит так:
function checkForBeacon() { if (roomBeacon) { console.log("Checking beacon distance"); if (roomBeacon.distance < 2 && !inRoom) { console.log("Entered the room"); inRoom = true; $("html").addClass("in-room"); $("#in-room").html("In room!"); turnOnBulb(); setTimeout(turnOnBulb, 1000); } else if (roomBeacon.distance >= 2 && inRoom) { console.log("Exited the room"); inRoom = false; $("html").removeClass("in-room"); $("#in-room").html("Out of room!"); turnOffBulb(); setTimeout(turnOnBulb, 1000); } } }
Если у нас есть номер roomBeacon
, то мы проводим наши тесты того, как далеко находится этот маяк. Если вы находитесь в двух метрах от маяка, и мы не установили для inRoom
значение true, то мы только что вошли в комнату. Мы устанавливаем для inRoom
значение true
, регистрируем сообщение в консоли, показываем сообщение «In room!» В нашем приложении и меняем класс в нашем <html>
чтобы мы могли переустанавливать наше приложение в зависимости от того, находимся ли мы в комнате или не. Мы также запускаем turnOnBulb()
которая будет делать это — включите лампу LIFX с помощью IFTTT.
Если мы находимся на расстоянии более двух метров от маяка, но приложение все еще думает, что мы находимся в комнате, мы устанавливаем inRoom
в false
и устанавливаем все наоборот. Мы запускаем turnOffBulb()
чтобы выключить лампочку LIFX.
Одна вещь, которая может вас удивить — почему у нас есть setTimeout()
повторно запускающий turnOnBulb()
и turnoffBulb()
? Иногда я обнаружил, что с IFTTT (или, возможно, с возможностью подключения LIFX в моем доме) он не всегда получает запрос в первый раз. Запуск его дважды, кажется, исправляет это!
Чтобы действительно включать и выключать лампы LIFX, мы отправляем запрос JSON на действие IFTTT через https://maker.ifttt.com/trigger/entered_room/with/key/{YOURKEYHERE}?jsoncallback=?
, Отключение их — та же идея, только с left_room
качестве имени триггера вместо entered_room
. Если для вас все это звучит как бред, прочитайте сначала мой учебник «Подключение IoT и Node.js к IFTTT»!
function turnOnBulb() { $.getJSON("https://maker.ifttt.com/trigger/entered_room/with/key/{YOURKEYHERE}?jsoncallback=?", { format: "json" }, function() { console.log("Entered room and told IFTTT about it!"); }) .done(function(data) { console.log("Done"); }) .fail(function(data) { console.log(JSON.stringify(data)); }) .always(function(data) { console.log("Finished"); }); console.log("Turn on bulb"); }
Тестирование на вашем устройстве
Чтобы протестировать приложение, перейдите на вкладку «Проекты» и перетащите свой index.html
в Evothings Studio, чтобы добавить его в проекты для просмотра. Затем нажмите «Выполнить», чтобы запустить его:
Если на вашем смартфоне открыто приложение Evothings Viewer, приложение должно появиться и работать так, как задумано! Если вы входите в комнату с маяком, ваш свет должен включиться (и приложение должно визуально показать, что вы вошли в комнату), а если вы выходите из комнаты, свет должен выключиться (и приложение должно показать, что вы ушли) ,
Вывод
Создание прототипов с помощью маяков Estimote и Evothings — это только начало, отсюда вы можете создать приложение Cordova или Phonegap, скопировать файлы из этого и экспортировать его в приложение, которое вы можете отправить в магазины приложений. Вам просто нужно добавить способ добавления пользовательских маяков в настройки (так как вы не захотите, чтобы все полагались на ваш маяк, если это не для общественных мест, таких как кафе).
Если вы создаете прототип Bluetooth-маяка с использованием маяков Estimote и Evothings, поделитесь им в комментариях или свяжитесь со мной в Twitter ( @thatpatrickguy ). Мне бы очень хотелось увидеть, что вы придумали и поделиться этим вокруг!