Началась новая золотая лихорадка, и она никак не связана с драгоценными металлами. Ее суть в создании инновационных устройств для потребителей и подключении этих устройств к облаку. Новый генеральный директор Microsoft Сатья Наделла (Satya Nadella) заявил в марте, что устройства «на самом деле не интересны без облака».
Это имеет смысл. Если устройство собирает информацию с помощью датчиков или камер, как и где вы будете анализировать эти данные? В конце концов, такие низкоуровневые устройства, как Raspberry Pi, имеют ограниченные вычислительные ресурсы и пространство для хранения. Облако восполняет этот пробел и, кроме того, помогает обеспечить безопасность, управление устройствами и т. д. Поэтому на этот раз мы хотим взяться за дело как со стороны аппаратного, так и со стороны программного обеспечения и изучить, что реально нужно для использования этой новой парадигмы вычислений.
SmartDoor — продукт Интернета вещей (Internet of Things, IoT), который мы создадим с нуля. В конечном счете мы соединим дверной звонок, камеру и устройство Raspberry Pi (рис. 1). Идея в том, что, когда кто-то подходит к вашей двери и нажимает на звонок, устройство автоматически делает снимок. Затем этот снимок пересылается на мобильное устройство как сообщение с всплывающим уведомлением (push notification) (рис. 2). В сообщении есть гиперссылка на изображение персоны, стоящей у вашей двери. На это изобретение нас вдохновила необходимость знать, кто звонит в дверь, даже когда дома никого нет.
Рис. 1. В этом проекте комбинируются дверной звонок, камера и устройство Raspberry Pi
Рис. 2. Windows Phone получает всплывающее уведомление
Мы начнем с иллюстрации того, как именно приобрести и собрать «голое железо». Создав аппаратное обеспечение, мы займемся программным обеспечением, которое будет выполняться на самом устройстве, а также программным обеспечением, которое будет работать в Microsoft Azure. Однако эта и последующие статьи будут сфокусированы в основном на обязательном программном обеспечении.
Нам потребуется код, способный сделать снимок и загрузить его в Azure. Оттуда понадобится отправить всплывающее уведомление соответствующим мобильным устройствам. Такое уведомление сообщит, что некто нажал дверной звонок и что можно посмотреть снимок этого человека. Из-за весьма амбициозной природы этого проекта мы будем писать ряд статей в блоге для поддержки его работы и рассказывать о любых подробностях.
Просто, как число «пи»
Мы займемся кодом, выполняемым на самом устройстве Raspberry Pi, и некоторым кодом, выполняемым в облаке, в частности внутри Azure Mobile Services. На Raspberry Pi мы установим среду Mono — бесплатный проект с открытым исходным кодом, который ведется Xamarin и предоставляет совместимый с Microsoft .NET Framework набор средств, в том числе компилятор C# и CLR.
Изящество Mono заключается в том, что она позволяет писать .NET-код, компилируемый в Windows и выполняемый в неизменном виде на Raspberry Pi. В данном случае мы делаем снимок и загружаем его в хранилище Azure. В следующих статьях мы расширим кодовую базу для поддержки возможности отправлять уведомления в Windows Phone. Для этого нам придется задействовать Push Notifications в Azure Service Bus и написать приложение Windows Store или Windows Phone.
Сборка оборудования достаточно прямолинейна, поскольку почти все доступно в наборе Raspberry Pi под названием «Canakit». За подробностями обращайтесь на сайт canakit.com. Этот набор содержит несколько полезных вещей, позволяющих создать наше IoT-устройство, включая системную плату, внешний блок питания, универсальный разъем ввода-вывода (general purpose input/output, GPIO), монтажную плату (breadboard), провода монтажной платы, сопротивления разного номинала и LED-индикаторы. Кроме того, для конфигурирования и тестирования Raspberry Pi понадобятся внешние монитор, клавиатура и мышь. Помимо Canakit, нужны еще две вещи: обыкновенный дверной звонок и камера, совместимая с Raspberry Pi; все эти вещи легко найти и приобрести.
Хотя набор разного оборудования на рис. 3 может показаться устрашающим, на самом деле его довольно легко соединить в одно целое. Если вы умеете собирать составные картинки (паззлы), то сможете собрать и устройство вроде SmartDoor. Сначала подключите модуль камеры к плате Raspberry Pi. Вытащите камеру из коробки и подключите ее кабель к этой плате. Детальное описание того, как отправлять снимки в облако, вы найдете по ссылке bit.ly/1rk3vzk.
Рис. 3. Raspberry Pi Canakit (не включает камеру)
Мы представим полную установку самого дверного звонка в следующей статье, где мы подключим его к Raspberry Pi. А пока мы подсоединим монтажную плату, которая будет тестовой версией электрической цепи, подключаемой к Raspberry Pi. С помощью соединительных кабелей и монтажной платы можно сымитировать дверной звонок.
Один из основных компонентов — монтажная плата GPIO. GPIO — это аппаратная цепь с 26 раздельными коннекторами (пронумерованными слева направо), которые позволяют расширять систему для взаимодействия с другими устройствами. В принципе, эти коннекторы (pins) дают возможность подключать такие вещи, как датчики, исполнительные механизмы, LED-индикаторы и т. д. Однако коннекторы имеют разные типы. Например, есть два штырька для подачи электропитания на подключенные устройства, а именно 3,3 и 5 В. Также имеется коннектор для напряжения на 0 В, действующий как земля, что необходимо для определения цепи. Коннекторы, помеченные как GPIO, работают по принципу простого включателя/выключателя. Если вам требуется последовательная связь, вы найдете коннекторы TX и RX (RS-232) для передачи и приема данных. Программному обеспечению, выполняемому на устройстве, понадобится взаимодействовать с этими коннекторами.
Одна из трудностей с этими коннекторами — несовпадение физических коннекторов с логическими, с которыми взаимодействует ПО. Это связано с чипами Broadcom в устройстве Raspberry Pi. Если сигнал идет на коннектор GPIO 0, ваше ПО на самом деле должно читать коннектор GPIO 17. Это может оказаться нелогичным, поэтому будьте внимательны.
Имеются и другие крайне важные аппаратные компоненты. Сопротивления (резисторы) играют ключевую роль в управлении текущим током и понижении уровней напряжения, поэтому вы не поджарите Raspberry Pi или любые другие устройства, подключенные к нему. Вам также понадобится одножильный кабель для подключения блока GPIO к Raspberry PI.
Тестирование
В связи с этим мы должны убедиться, что правильно собрали оборудование. Самый простой способ проверить Raspberry Pi — просто подключить внешние монитор, клавиатуру, мышь (не обязательно) и блок питания. Сделав это, включите электропитание, после чего на монитора должна отобразиться последовательность начальной загрузки для Linux. Именем пользователя по умолчанию будет «pi», а паролем — «raspberry». За подробностями о настройке Raspberry Pi обращайтесь по ссылке bit.ly/1k8xBFn.
Raspberry Pi требуется дополнительное ПО, такое как Mono, чтобы получить возможность выполнять код, написанный на C#. Прежде чем мы сможем что-то делать на устройстве, нам нужно обновить его операционную систему Raspbian. К счастью, Pi поставляется с предустановленной версией этой ОС. Поэтому для обновления ОС достаточно ввести пару команд в консольном окне. Затем можно установить исполняющую среду Mono от Xamarin и несколько доверяемых корневых сертификатов. Это позволит устройству выдавать HTTPS-запросы. Все эти операции объясняются в статье в блоге bit.ly/Unehrr.
Программная часть
Кодировать потребуется применительно к двум уровням: клиентскому (самому устройству Raspberry Pi) и уровню сервисов (Azure Storage и Azure Mobile Services). Существуют разнообразные языки и сервисы на серверной стороне, из которых есть что выбрать. Мы будет работать с C# на клиенте и с Node.js/JavaScript на сервере. Такой выбор может понравиться не всем, так как некоторые считают, что применение двух языков усложняет реализацию.
Наша цель заключалась в том, чтобы показать разнообразие. В контексте Node.js предлагается множество библиотек и пакетов на npmjs.org, которые потенциально способны значительно упростить код на серверной стороне. Node.js зачастую дает гораздо более компактную кодовую базу, поскольку библиотеки очень мощные. Меньше кода на втором языке лучше, чем масса кода на одном языке. Схема на рис. 4 иллюстрирует ожидаемый рабочий процесс, который сводится к трем этапам.
- Клиент запрашивает маркер Shared Access Signature (SAS), представляемый как URL.
- Приложение Node.js, выполняемое в Azure Mobile Services, возвращает SAS URL.
- Клиент использует SAS URL для загрузки снимка в Azure Storage как двоичный объект (blob).
Увеличить
Рис. 4. Схема высокоуровневой архитектуры проекта SmartDoor
Azure Mobile Services | Azure Mobile Services |
API | API |
Request SAS Key | Запрос ключа SAS |
Receive SAS Key | Получение ключа SAS |
Send SAS Key and Photo to Azure Storage | Отправка ключа SAS и снимка в Azure Storage |
Camera | Камера |
Doorbell | Дверной звонок |
Raspberry PI | Raspberry PI |
Linux and Mono | Linux и Mono |
Azure Storage | Azure Storage |
Uploaded Images | Загруженные изображения |
Мы разместили свое приложение Node.js в Azure Mobile Services. Это обеспечивает широкую поддержку клиентов мобильных устройств, такую как всплывающие уведомления, интеграция с CRUD-хранилищем, идентификация и возможность создания собственного API.
Фокус на сервисе
Начнем с создания сервиса, потому что разработка для клиента проблематична в отсутствие уровня сервисов. Без него нет реальной возможности запускать и тестировать клиент — требуется полнофункциональный сервис на сервере. API нашего сервис будет размещен в Azure Mobile Services.
Этот API будет основан на Node.js и инфраструктуре Express Web. Наше клиент (Raspberry Pi) будет использовать эти сервисы для запроса SAS. Затем сервис задействует полученный маркер для загрузки снимка в Azure Storage. Использование SaS URL помогает защитить нашу учетную запись Azure Storage, так как нам не потребуется хранить удостоверения для этой учетной записи на устройстве Raspberry Pi.
Дополнительные вопросы безопасности мы рассматривали в прошлой статье (msdn.microsoft.com/magazine/dn574801). SAS-маркеры также хороши по другой причине: они освобождают промежуточный уровень (Node.js API) от необходимости выступать в роли посредника при передаче файлов от клиента в хранилище.
Подготовка Azure Mobile Services и Azure Storage
Подготовка Azure Mobile Services требует всего нескольких щелчков на портале Azure. То же самое верно и в отношении подготовки Azure Storage. Как всегда, вам понадобится продумать URL и соглашения по именованию, которые вы хотите задействовать для своих облачных сервисов. Кроме того, вы должны решить, какие из нескольких глобальных информационных центров вы предпочли бы использовать, убедившись, что ваша учетная запись хранилища находится в том же информационном центре, что и Azure Mobile Services; это нужно для минимизации задержек и исключения расходов на передачу данных. Подробнее о подготовке Azure Mobile Services и учетной записи Azure Storage см. по ссылке bit.ly/WyQird.
Shared Access Signatures (SAS)
Как показано на рис. 4, клиент Raspberry Pi будет запрашивать SAS-маркер от Azure Mobile Services. Для этого он выдаст запрос get из API, который мы определим в Azure Mobile Services.
На рис. 5 показан фрагмент кода Node.js, выполняемого в Azure Mobile Services как конечная точка API-сервиса. Его предназначение — отвечать на запросы от клиентов Raspberry Pi, требующих SAS. Raspberry Pi выдает запрос get к этой конечной точке, размещенной в Azure Mobile Services, передавая ключ приложения, который является идентификатором, уникально представляющим наш мобильный сервис.
Рис. 5. Код Node.js для Microsoft Azure Mobile Services API
exports.get = function(request, response) {
// Это часть "App Settings" в разделе configuration вашего
// сервиса. Не "зашивайте" ее в этот скрипт Node.js.
containerName = request.service.config.appSettings.PhotoContainerName;
accountName = request.service.config.appSettings.AccountName;
accountKey = request.service.config.appSettings.AccountKey;
// Подключение к сервису Blob
blobService = azure.createBlobService(
accountName,accountKey,accountName + '.blob.core.windows.net');
createContainer();
createPolicies();
var sasResponse = GetSAS();
return request.respond(201, sasResponse);
}
Ключ приложения предоставляет безопасный способ взаимодействия с конкретным сервисом в Azure Mobile Services. Сервис получит этот ключ с портала, и его будет использовать код, выполняемый на Raspberry Pi, поэтому вы должны хранить его под рукой. Вы можете вставить его в клиентский код. Клиент принимает SAS, инкапсулированный в URL и впоследствии применяемый клиентом для загрузки снимка.
Теперь мы сосредоточимся на некотором коде, который представляет серверную часть приложения Node.js. По ссылке bit.ly/Unnikj можно скачать мощный Node.js SDK, адаптированный под Azure. Эта кодовая база обеспечивает широкую поддержку и других частей платформы Azure, например для работы с таблицами, очередями, темами (topics), узлами уведомлений (notification hubs), управлением основными компонентами и т. д. Учебное пособие по интеграции Node.js и Azure Blob Storage можно найти по ссылке bit.ly/1nBEvBa.
Для наших целей SAS, возвращаемый приложением Node.JS клиенту, связывается с учетной запись хранилища, которую мы подготовили ранее. Как таковому, приложению Node.js понадобятся имя этой учетной записи и ключ управления (management key).
Azure Mobile Services позволяет выносить конфигурационные параметры из вашего приложения Node.js. «Зашивать» непосредственно в код параметры ключа учетной записи в целом считается плохой практикой программирования. С помощью параметров приложения можно задавать пары «ключ-значение», которые сможет считывать исполняющая среда сервиса. Узнать больше можно по ссылке bit.ly/1pwGFRN.
В конечном счете код на основе Node.js будет возвращать URL с SAS, используемым клиентом для загрузки снимков. Наряду с SAS-маркером приложение Node.js вернет код состояния HTTP, равный 201. Он уведомляет о том, что приложение выполнило запрос и создало новый ресурс (SAS-маркер).
Более подробное пошаговое описание соответствующих операций с Node.js, SAS URL и параметрами приложения вы найдете по ссылке bit.ly/WyQird.
Код, выполняемый на Raspberry Pi
Аппаратно-программный интерфейс на самом деле довольно прямолинеен. Вы можете рассматривать код на клиентской стороне как гигантский конечный автомат. Он «крутится» в постоянном цикле, проверяя состояние коннекторов GPIO. Как видно из рис. 6, мы просто проверяем, включен (true) или выключен (false) коннектор.
Рис. 6. Цикл длительного опроса, взаимодействующий с Raspberry Pi GPIO для управления поведением
while (true)
{
// Если коннектор 17 выключен, мы готовы
if (!s_Gpio.InputPin(FileGPIO.FileGPIO.enumPIN.gpio17))
{
showReady(true);
// Если коннектор 22 равен true, указываем пользователю,
// что система занята, делаем снимок
// и загружаем его в облако
if (s_Gpio.InputPin(FileGPIO.FileGPIO.enumPIN.gpio22))
{
showReady(false);
TakeAndSendPicture();
}
}
else
{
// Пока не готовы сделать снимок
showReady(false);
break;
}
// Пауза на одну десятую секунды
System.Threading.Thread.Sleep(100);
}
Проверить состояние коннектора можно двумя способами. Первый подход (которым мы и воспользовались) — взаимодействие с файловой системой. Проверяя наличие специфических файлов со специфическими значениями, можно определить, включен или выключен коннектор. Другой подход, обычно обеспечивающий более высокую производительность, — проверка специфических участков памяти на наличие специфических значений. Хотя работа с файловой системой медленнее, этот вариант считается безопаснее. При этом подходе используется встроенный драйвер, предоставляемый Linux.
Рассмотрим некоторый код, будет работать поверх Mono на Raspberry Pi, используя C#. Raspberry Pi будет выполнять четыре основных этапа. Во-первых, он будет реагировать на нажатие кнопки дверного звонка. Во-вторых, при нажатии этой кнопки он будет делать снимок и сохранять его в локальном хранилище. В-третьих, он будет запрашивать SAS-маркер, который потом будет задействован при загрузке снимка. В-четвертых, он будет загружать снимок в Azure Storage как двоичный объект (blob). Хотя этот код пишется на C#, он целиком основан на REST. То есть эти четыре этапа могут быть выполнены любым языком или средой с поддержкой HTTP.
Мы может управлять Raspberry Pi через GPIO. Наше приложение использует всего четыре точки для обращения к GPIO 2 (ввод) и GPIO 1 (вывод). Давайте ознакомимся с кодом на C#, который взаимодействует с этими коннекторами. Взгляните на основной цикл в C#-коде для Raspberry Pi на рис. 6. Коннекторы 17 и 22 служат для проверки готовности устройства и создания снимка с последующей загрузкой при нажатии дверного звонка.
Это бесконечный цикл длительного опроса (long-polling) постоянно проверяет напряжения на коннекторах. Поэтому программное обеспечение узнает, когда нужно что-то выполнить, например сделать снимок. Этот цикл работает с частотой 10 Гц, опрашивая состояния коннекторов. Если вас интересуют подробности, см. bit.ly/1trFzt9.
Различные языки работают с разной скоростью. Например, Python довольно медленный и неприменим в сценария, где скорость является критичным фактором. В данном случае 10 Гц — это достаточно быстро для проверки того, что дверной звонок перевел коннектор 22 в состояние Power, когда кто-то нажал этот звонок.
Каждый из трех коннекторов выполняет разные функции. Первый вход, коннектор 17, должен быть подключен к коннектору Ground (земля) (что интерпретируется C#-кодом как false). Если конфигурация отличается, программа сразу же завершится. Коннектор 22 должен быть установлен в Power (что интерпретируется как true). Когда коннектор 22 соответствует true, в TakeAndSendPicture начинается процесс получения снимка. Метод showReady использует коннектор 4 (выходной), чтобы показать, что программа готова делать снимки и загружать их, активируя LED.
В решении используются символы условной компиляции, чтобы соответствующий код выполнялся не только в Windows, но и в Raspbian. Код в решении должен быть разным потому, что получение снимка под управлением операционной системы Raspbian не является API-вызовом. Этот процесс включает запуск исполняемого файла в собственном процессе. С другой стороны, в Windows 8 вы используете CaptureFileAsync API из CameraCaptureUI.
Чтобы получить снимок, мы вызываем встроенный исполняемый файл raspistill, как показано на рис. 7. Он уже сконфигурирован на создание снимка и сохранение его в формате JPEG. Это позволяет вам указать имя файла, качество снимка и размер изображения. Raspistill запускается как дочерний процесс. Пока создается снимок, код запрашивает SAS URL от сервиса в Azure Mobile Services. Затем он загружает картинку в Azure Blob Storage.
Рис. 7. Получение снимка и его загрузка в облако
static void TakeAndSendPicture()
{
#if LINUX
// Начинаем процесс создания снимка. Для этого запускается
// процесс raspistill. Мы будем ждать его завершения после
// того, как получим URL снимка.
Process raspistill = new Process();
raspistill.StartInfo = new ProcessStartInfo("/usr/bin/raspistill",
"-n -q " + photoQuality +
" -o /home/pi/Desktop/me.jpg -h 200 -w 200 -t 500")
{
UseShellExecute = false
};
raspistill.Start();
#endif
// Получаем URL снимка, пока идет создание картинки
WebRequest photoRequest = WebRequest.Create(
"https://raspberrypiservice.azure-mobile.net/api/getuploadblobsas?");
photoRequest.Method = "GET";
photoRequest.Headers.Add("X-ZUMO-APPLICATION",
"AIzNtpTdQLjORKJJhTrQWWRSHSnXcN78");
PhotoResponse photoResp = null;
using (var sbPhotoResponseStream =
photoRequest.GetResponse().GetResponseStream())
{
StreamReader sr = new StreamReader(sbPhotoResponseStream);
string data = sr.ReadToEnd();
photoResp = JsonConvert.DeserializeObject<PhotoResponse>(data);
}
Console.WriteLine("Pushing photo to SAS Url: " + photoResp.sasUrl);
WebRequest putPhotoRequest = WebRequest.Create(photoResp.sasUrl);
putPhotoRequest.Method = "PUT";
putPhotoRequest.Headers.Add("x-ms-blob-type", "BlockBlob");
#if LINUX
// Ждем, пока не будет сделан снимок
raspistill.WaitForExit();
FileStream fs = new FileStream(@"/home/pi/Desktop/me.jpg",
FileMode.Open);
#else
FileStream fs = new FileStream(@"testPhoto.jpg", FileMode.Open);
#endif
using (fs)
using (var reqStream = putPhotoRequest.GetRequestStream())
{
Console.WriteLine("Writing photo to blob...");
fs.CopyTo(reqStream);
}
using (putPhotoRequest.GetResponse())
{
}
}
Решение Visual Studio компилируется для выполнения на Raspberry Pi, а также в традиционной Windows. Оно использует символы условной компиляции, чтобы соответствующий код выполнялся в Raspbian и обычной Windows. Код в решении должен быть разным из-за того, что получение снимка в Raspbian специфично для этой платформы. Чтобы не усложнять код, при компиляции под Windows 8 мы не делаем снимок. Вместо этого мы загружаем в облако существующее изображение (testPhoto.jpg).
Хорошая новость в том, что вы можете сделать общим между Windows и Raspbian большое количество кода. Идентично все от получения SAS до загрузки снимка. Поэтому, если это работает в Windows, то скорее всего будет работать и в Raspbian. Это радикально упрощает разработку и тестирование клиентского кода. Raspberry Pi — ограниченное устройство, поэтому лучше всего минимизировать работу, выполняемую на самом устройстве.
Как только устройство захватило снимок, вы должны увидеть его в двух местах. Первое — на самом устройстве, а точнее в файле /home/pi/Desktop/me.jpg, как было указано в командной строке. И конечно, в контейнере Azure Storage под вашей учетной записью после загрузки.
Заключение
Это хорошая отправная точка для создания вашего собственного устройства для Интернета вещей. Мы попытались охватить все от приобретения оборудования, его сборки, установки программного обеспечения, написания необходимой программы до проверки функциональности. Мы также предоставили множество ссылок на публикации в блоге, где оказывается техническая поддержка. Но это решение еще не закончено.
В следующей статье мы рассмотрим, как отправлять всплывающие уведомления на телефоны, чтобы вы могли видеть на мобильном устройстве снимок того, кто звонит вам в дверь. Мы познакомим вас сервисом уведомления, который является частью Azure Service Bus. Мы также создадим приложение Windows Phone, способное принимать всплывающие уведомления от Azure. Наконец, мы обсудим дополнительные механизмы хранения, такие как база данных MongoDB NoSQL, и взаимодействие с серверной частью, позволяющей распознавать лица. Оставайтесь с ними и вы узнаете больше об Интернете вещей и Azure.