.NET Micro Framework

Создание IoT-устройства, используя Gadgeteer в сочетании с Azure Blob Storage

Benjamin Perkins

Исходный код можно скачать по ссылке

Продукты и технологии:

Gadgeteer, .NET Micro Framework, Microsoft Azure, Visual Studio

В статье рассматриваются:

  • конфигурирование IoT-устройства с помощью Gadgeteer;
  • подключение устройства к Интернету;
  • загрузка изображения в контейнер Azure Blob в облаке.

В следующие пять лет количество подключенных к Интернету устройств в три раза превысит население всей Земли. Эти устройства не будут ограничиваться смартфонами и планшетами, используемыми сегодня, а будут включать дополнительные устройства, встраиваемые в бытовую технику, лифты, автомобили, бизнес-среды, повязки (arm bands), одежду и многое другое. Эти устройства будут захватывать информацию об энергопотреблении, скорости ветра, температурах, присутствии различных газов, кровяном давлении, пульсе, программных и аппаратных исключениях, да и просто обо всем, что только можно представить.

Данные, захватываемые этими устройствами, нужно хранить в надежной удобной среде с высокой масштабируемостью. Под «удобной» я имею в виду вот что: как только данные сохранены, платформа, на которой они существуют, должна предоставлять сервисы, средства и вычислительные мощности для анализа собранных данных и операций над ними. В этой статье я намерен показать, как использовать Gadgeteer (платформу быстрой разработки аппаратного обеспечения, основанную на Microsoft .NET Micro Framework), чтобы создать устройство для захвата данных. Кроме того, я поясню, как сохранять данные в Microsoft Azure Storage и анализировать/использовать данные на платформе Azure. Следуя за мной, вы начнете путешествие в поколение Интернета вещей (Internet of Things, IoT).

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

Gadgeteer

Gadgeteer от GHI Electronics LLC (bit.ly/11ko85B) включает наборы, модули и системные платы (например, FEZ Raptor, FEZ Hydra и FEZ Spider, используемые в этом проекте) для создания устройств множества разных типов. Эти устройства можно применять для захвата самых разнообразных данных. Так, они могут использовать модуль газовых датчиков (gas-sensing module) для обнаружения газов в воздухе, детектор движения или модуль для измерения относительной температуры и влажности. Модули, совместимые с FEZ Spider, которые понадобятся в проекте, обсуждаемом в этой статье: камера, Ethernet-разъем и модуль питания. В первом разделе я покажу, как конфигурировать модули и разрабатывать код, необходимый для подготовки захваченного изображения к вставке в контейнер Azure Blob Storage.

На рис. 1 приведена конфигурация проекта. Помимо камеры, Ethernet-разъема и блока питания, в нем задействован буквенно-цифровой дисплей для отображения IP-адреса, а также даты и времени на устройстве, LED-индикатор для визуального уведомления и кнопка, инициирующая захват картинки и процесс ее загрузки в облако.

Конфигурация FEZ Spider для захвата картинки и ее сохранения в контейнере Azure Blob
Рис. 1. Конфигурация FEZ Spider для захвата картинки и ее сохранения в контейнере Azure Blob

camera камера
button кнопка

 

После установки .NET Micro Framework, двоичных файлов GHI (Package 2014 R5) и .NET Gadgeteer SDK на компьютер для разработки начните с создания нового проекта в Visual Studio 2012 (Visual Studio 2013 тоже поддерживается, хотя полное тестирование не проводилось) и выбора шаблона Gadgeteer. Как только вы присвоите имя проекту, мастер проведет вас по процедуре выбора системной планы и версии Micro Framework. Затем, используя Toolbox, добавьте модули для создания своего устройства по аналогии с тем, что показано на рис. 1.

Когда все модули физически подключены к сокетам на системной плате, приступайте к внесению изменений в код, чтобы достичь цели проекта — подключения к сети и захвата снимка. Модуль, используемый для сетевого соединения, — ethernetJ11D, который поддерживает стандартный сетевой адаптер RJ-45. Вот кое-какой код, заставляющий модуль ethernetJ11D выполнить соединение и получить IP-адрес:

ethernetJ11D.NetworkInterface.Open();
ethernetJ11D.NetworkSettings.EnableDhcp();
ethernetJ11D.NetworkSettings.EnableDynamicDns();
ethernetJ11D.UseDHCP();

Конечно, это не единственный способ добиться соединения; однако этот вариант работал лучше всего и был самым простым в данном контексте.

После подключения вы, возможно, захотите выполнить просто запрос System.Net.HttpWebRequest, аналогичный показанному на рис. 2, чтобы убедиться в том, что соединение с Интернетом работает, как ожидалось.

Рис. 2. Проверка соединения с Интернетом

void makeGenericHTTPRequest()
{
  try
  {
    string url = "https://www.contoso.com/";
    using (var req = System.Net.HttpWebRequest.Create(url))
    {
      using (var res = req.GetResponse())
      {
        Debug.Print("HTTP Response length: " 
          + res.ContentLength.ToString());  }
    }   
  }
  catch (Exception ex)
  {
    Debug.Print(ex.Message);
  }
}

Заметьте, что протокол HTTPS не будет здесь работать без определенной настройки. Если вы получили исключение вроде «A first chance exception of type System.NotSupportedException occurred in Microsoft.SPOT.Net.Security.dll», то должны обновить SSL Seed на устройстве. Для этого используйте .NET Micro Framework Deployment Tool (MFDeploy.exe), находящуюся в каталоге C:\Program Files (x86)\Microsoft .NET Micro Framework\v4.3\Tools. Когда устройство подключено к компьютеру для разработки, перейдите в Target | Manage Device Keys и щелкните Update SSL Seed (рис. 3). После этого HTTPS должен работать нормально.

.NET Micro Framework Deployment Tool (MFDeploy)
Рис. 3. .NET Micro Framework Deployment Tool (MFDeploy)

После подключения к сети, конфигурирования соединения с Интернетом и проверки работы важно задать дату и время на устройстве. Как будет обсуждаться позже, дата и время — обязательные части PUT Blob REST API (bit.ly/1BTiIu9), который вы будете использовать для вставки изображения в контейнер Azure Blob. Чтобы установить дату и время, используйте класс TimeServiceSettings из пространства имен Microsoft.SPOT.Time:

TimeServiceSettings time = new TimeServiceSettings()
{
  ForceSyncAtWakeUp = true
};
IPAddress[] address = Dns.GetHostEntry("time.windows.com").AddressList;
time.PrimaryServer = address[0].GetAddressBytes();
TimeService.Settings = time;
TimeService.SetTimeZoneOffset(0);
TimeService.Start();

После запуска TimeService вы можете получать текущую временную метку через стандартное свойство DateTime.UtcNow или DateTime.Now.

Захват изображения с помощью камеры, совместимой с GHI FEZ Spider, требует всего одной строки кода:

camera.TakePicture()

Вспомните, что я добавил модуль Button в устройство. Метод TakePicture вызывается из обработчика события нажатия кнопки. Когда делается снимок, инициируется событие camera.PictureCaptured, что в свою очередь вызывает метод camera_PictureCaptured(Camera sender, GT.Picture e). Обработчик события и метод для связывания событий Pressed и Captured с соответствующими методами я подключаю с помощью стандартного кода на C#:

button.ButtonPressed += button_ButtonPressed;
camera.PictureCaptured += camera_PictureCaptured;

Метод camera_PictureCaptured принимает GT.Picture как параметр. После преобразования в массив byte[], используя свойство e.PictureData, данные изображения передаются в пользовательский метод для вставки в контейнер Azure Blob. Этот процесс может показаться сложным, но на деле он весьма прост, как показано на рис. 4. Кроме того, вы можете скачать пример кода, сопутствующий этой статье, чтобы увидеть проект в целом.

Поток управления в процессе захвата снимка в Gadgeteer
Рис. 4. Поток управления в процессе захвата снимка в Gadgeteer

Press the button Нажатие кнопки
GT.Picture GT.Picture
TakePicture() TakePicture()
GT.Picture.Data GT.Picture.Data
Account Учетная запись
Container Контейнер
Blob Blob

На рис. 5 представлен код для использования класса AzureBlob, который будет рассматриваться в следующем разделе, где я создам заголовок Authorization (bit.ly/1z0gThK) и вызову REST API, который вставит изображение в контейнер Azure Blob.

Рис. 5. Вставка изображения в Azure Blob Storage

void insertImageintoAzureBlob(GT.Picture picture)
{
  AzureBlob storage = new AzureBlob()
  {
    Account = "ACCOUNT-NAME",
    BlobEndPoint = "https://ACCOUNT-NAME.blob.core.windows.net/",
    Key = "CONTAINER PRIVATE KEY"
  };
  if (ethernetJ11D.IsNetworkUp)
  {
    storage.PutBlob("CONTAINER-NAME", picture.PictureData);
  }
  else
  {
    characterDisplay.Print("NO NETWORK CONNECTION");
  }
}

Со стороны устройства, на этом все. Теперь устройство собрано и подключено к Интернету, а также написана логика захвата изображения и его отправки в корректном формате в PUT Blob REST API. Далее я создам учетную запись и контейнер Azure Blob Storage и настрою код, необходимый для вставки изображения.

Azure Blob Storage

Azure Blob Storage — полезный сервис, который откуда угодно обеспечивает доступ к изображениям, документам, видеозаписям и т. д., используя HTTP или HTTPS. Например, если у вас есть изображение home.bmp, общедоступная учетная запись Azure Storage под именем contosox и контейнер с именем blob, для доступа к файлу .bmp из браузера достаточно ввести http://contosox.blob.core.windows.net/blob/home.bmp или сослаться на URL из HTML или из исходного кода.

Вставка, перечисление, скачивание и удаление больших двоичных объектов (blobs) из стандартного .NET-приложения в контейнере Azure Blob выполняется с помощью библиотеки Azure .NET Storage Client посредством сборки Microsoft.WindowsAzure.Storage. К сожалению, эта сборка недоступна или несовместима с .NET Micro Framework или устройством Gadgeteer. Однако это не проблема, так как сервис Azure Blob Storage предоставляет общедоступные REST API, которые поддерживают те же возможности вставки, перечисления, скачивания и удаления (подробнее см. по ссылке bit.ly/1xPN55v). Поэтому использование этих средств с IoT-устройства заключается в вызове стандартного REST API.

Я покажу, как создать учетную запись и контейнер Azure Blob Storage, как создать заголовок REST API Authorization, используя .NET Micro Framework 4.3 и как загрузить изображение, захваченное в предыдущем разделе, в контейнер Azure Blob.

Создайте учетную запись Azure Storage из Azure Management Console, а затем щелкните кнопку +Add, чтобы добавить контейнер. В этом примере учетная запись имеет имя contosox, а контейнер — blob (рис. 6).

Создание контейнера Azure Storage для хранения изображения, снятого с IoT-устройства
Рис. 6. Создание контейнера Azure Storage для хранения изображения, снятого с IoT-устройства

Пример на рис. 7 демонстрирует, что необходимо для использования PUT Blob REST API. Добавив имя изображения в URL (рис. 6) и вызвав метод GetRequestStream класса System.Net.HttpWebRequest, вы получите объект System.IO.Stream. Вызов метода Write класса System.IO.Stream успешно сохраняет изображение в контейнере Azure Blob. Заметьте, что параметр blobContent метода Write содержит массив byte[] из свойства GT.Picture.PictureData.

Рис. 7. Использование PUT Blob REST API

Uri uri = new Uri("ACCOUNT-URL\CONTAINER\" + "IMAGE-NAME");
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
try
{
  using (Stream requestStream = request.GetRequestStream())
  {
    requestStream.Write(blobContent, 0, blobLength);
  }
}
catch (WebException ex)
{
  Debug.Print(ex.Message);
}

Это не слишком сложно и очень похоже на вызов REST API из стандартного приложения ASP.NET или Microsoft .NET Framework. Отличие лишь в создании заголовка Authorization, определенного здесь:

Authorization="[SharedKey|SharedKeyLite] <AccountName>:<Signature>"

При создании контейнер Azure Blob делается общедоступным, т. е. кто угодно может считывать из него по ранее упомянутому URL. Однако добавление или удаление Blob требует наличия заголовка Authorization в запросе. Значение SharedKey в заголовке уведомляет сервер о том, что ключ общего доступа (shared access key) существует и должен использоваться при аутентификации запроса. SharedKey связан с учетной записью Azure Storage (в этом примере с contosox) и запрашивается щелчком Manage Access Keys для данной учетной записи хранилища. Значение, содержащееся в поле Primary Access Key (рис. 8), — это SharedKey, применяемый для доступа к контейнеру.

Получение SharedKey, необходимого для аутентификации в Azure Storage
Рис. 8. Получение SharedKey, необходимого для аутентификации в Azure Storage

Azure Blob Storage — полезный сервис, который откуда угодно обеспечивает доступ к изображениям, документам, видеозаписям и т. д., используя HTTP или HTTPS.

Кроме того, часть Signature заголовка Authorization должна представлять собой Hash-based Message Authentication Code (HMAC), сконструированный из набора атрибутов запросов, вычисленный с применением метода System.Security.Cryptography.HashAlgorithm.ComputeHash и закодированный методом System.Convert.ToBase64String.

Расскажу об этом немного подробнее и начну с компонентов, необходимых для конструирования заголовка Authorization. К ним относятся такие атрибуты, как x-ms-version, content-length, content-type, общий ключ доступа и многие другие значения, детально описанные по ссылке bit.ly/1BTiIu9. Один из более важных атрибутов — x-ms-date, из-за которого вы должны были устанавливать дату и время при инициализации устройства. Атрибут x-ms-date должен содержать временную метку в формате UTC. Временная метка на устройстве должна иметь разницу менее 15 минут в сравнении с временной меткой на сервере, где размещен сервис хранилища. Сервис хранилища гарантирует, что запрос не старше 15 минут; если временные рамки оказываются больше, сервис возвращает код 403 (Forbidden). Другие атрибуты не изменяются и могут быть «зашиты» в код или получены из какого-то другого источника, например из конфигурационного файла.

После того как заголовок Authorization правильно отформатирован (это около 35 строк кода), его нужно хешировать и закодировать в соответствии с требованиями. При использовании полной версии .NET Framework необходимый код выглядит примерно так:

using (HashAlgorithm hashSHA256 = 
  new HashAlgorithm(HashAlgorithmType.SHA256))
{
  Byte[] dataToHmac = 
    System.Text.Encoding.UTF8.GetBytes(canonicalizedstring);
  signature = 
    Convert.ToBase64String(hashSHA256.ComputeHash(dataToHmac));
}

Метод System.Security.Cryptography.HashAlgorithm.ComputeHash, нужный для хеширования заголовка Authorization, имеется в .NET Micro Framework версии 4.3 (bit.ly/1wIl77O) и является допустимым вариантом для хеширования Signature. Однако я предпочел создать WebAPI, который принимает сконструированный заголовок как параметр, кодирует его, хеширует и возвращает в Gadgeteer для использования в вызове PUT Blob REST API. Я выбрал этот подход в основном потому, что хотел проверить вызов WebAPI из Gadgeteer и счел его логичным местом для выполнения этих операций. Следующий код показывает, как WebAPI вызывался с Gadgeteer-устройства:

string queryString = "constructedHeader=" + constructedHeader;
Uri uri = new Uri("https://*??.azurewebsites.net/api/HMACSHA256?" + queryString);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
string responseFromServer = reader.ReadToEnd();
reader.Close();
response.Close();

Ответ от WebAPI, как вы, вероятно, знаете, представляет собой JSON-объект с содержимым строки responseFromServer. Для разбора результатов вызова WebAPI и получения хешированного и закодированного значения заголовка Authorization удобна библиотека MicroJSON с открытым исходным кодом (microjson.codeplex.com):

var jdom = (JObject)JsonHelpers.Parse(responseFromServer);
var hashedvalue = jdom["HashedValue"];
StringBuilder authorizationHeader = new StringBuilder("{0} {1}:{2}")
  .Replace("{0}", SharedKeyAuthorizationScheme)
  .Replace("{1}", "contosox")
  .Replace("{2}", hashedValue);

В качестве альтернативы тех же результатов можно добиться применением метода string.IndexOf в сочетании с методом string.Substring.

Метод string.Format в настоящее время не поддерживает в .NET Micro Framework, поэтому я использовал StringBuilder.Replace для конструирования authorizationHeader. Как отмечалось ранее, заголовок Authorization состоит из SharedKeyAuthorizationScheme (комбинации либо SharedKey, либо SharedKeyLite), имени Azure Blog Storage (contosox) и закодированного и хешированного Signature. Когда заголовок Authorization правильно сформирован, добавьте его в объект запроса PUT Blob REST API и выполните его. После аутентификации изображение будет добавлено в контейнер Blob:

request.Headers.Add("Authorization", authorizationHeader);

В этом примере событие, которое инициирует вставку изображения в контейнер Azure Blob, — нажатие кнопки. Я выбрал этот подход просто для того, чтобы создать этот концептуальный проект. В настоящей реализации вместо этого следовало бы использовать показания от газоанализатора, датчика движения, атмосферного давления, температуры или влажности. На самом деле событие может инициироваться любым превышением заданного порога. Во многих случаях требования к IoT-устройству не включают создание снимка — только сохранение захваченных данных вроде температуры, скорости, уровня газа, времени и т. д. Такие данные можно сохранять в базе данных простым вызовом WebAPI, аналогичным показанному ранее, но без необходимости использовать заголовок Authorization, так как никакого Blob или изображения нет.

Теперь, когда данные захвачены и сохранены на платформе Azure, возникает вопрос: что делать с ними, как их анализировать и что можно извлечь из них. В следующем разделе я представлю некоторые идеи и заключительные соображения. В мои намерения не входит показать все детали комплексного IoT-решения, я просто хочу дать пищу для размышлений и способствовать продвижению соответствующих концепций.

Microsoft Azure

Большинство IT-специалистов хорошо представляют, что означает термин «большие данные» (Big Data). Однако, как их использовать и извлекать из них полезную информацию, скорее всего не столь понятно. Когда я впервые начал изучать концепцию больших данных, я сразу же споткнулся о проблему нахождения источника данных, который можно было бы использовать для работы с такими инструментами, как HDInsight, Power BI, Event Hubs, Machine Learning или Stream Analytics. Тем не менее, я стал пользоваться этими сервисами, изучая их возможности и средства, но в отсутствие крупного источника данных, на котором можно было бы проверить свои алгоритмы, быстро потерял к ним интерес. В конце концов до меня дошло, что IoT — все эти устройства, подключенные к Интернету, — можно было бы применить для сбора данных и создания больших источников информации с целью последующей обработки этими сервисами Azure.

Ясно, что каждый из этих сервисов спроектирован с учетом IoT, принимая во внимание Event Hubs и Stream Analytics для принятия решений в реальном времени, а также HDInsight и Machine Learning для анализа огромных массивов данных в поисках долгосрочных тенденций. Например, Event Hubs, который специально рассчитан на прием миллионов инициируемых устройствами событий в секунду, обеспечивает необходимые масштабы для крупных решений в области IoT. Для компаний и предприятий, уже реализовавших какое-то IoT-решение или только начинающих вырабатывать свою стратегию в области IoT, Event Hubs станет отличной отправной точкой в управлении долгосрочным ростом и масштабированием. Кроме того, Stream Analytics интегрируется с Event Hubs и может обеспечить анализ в реальном времени данных, передаваемых устройствами в Event Hubs. Stream Analytics способен сравнивать данные, отправляемые в Event Hubs, с историческими данными и посылать упреждающее оповещение, если текущие закономерности не совпадают с таковыми в исторических данных.

Организации и даже индивидуальные лица, располагающие большими пулами данных (не обязательно собранных IoT-устройствами), могут использовать сервисы HDInsight или Machine Learning для анализа этих данных. HDInsight — это решение на основе Hadoop, которое можно масштабировать по требованию до терабайтов или петабайтов данных, а платформа Azure предоставляет почти бесконечный объем хранилищ и вычислительных ресурсов. Используйте HDInsight для поиска скрытых возможностей для бизнеса совместно с Machine Learning (или независимо от него) для просеивания данных, помогающего предсказывать будущие тенденции и поведение различных систем. Эти сервисы переводят в новую эпоху Интернета вещей, выявляя ранее незаметную информацию инновационными способами и открывая колоссальные возможности, причем все это может предоставляться в дружественном к пользователю стиле с помощью Power BI.

Заключение

Целью этой статьи было объяснение того, как сконфигурировать IoT-устройство, используя Gadgeteer, подключить его к Интернету и загрузить снятое изображение в облачный контейнер Azure Blob. Вставка данных с устройства в любой источник данных, доступный через Интернет, требует лишь простого вызова WebAPI, а конфигурирование самого аппаратного устройства осуществляется простым перетаскиванием модулей из меню Toolbox в проектировочный шаблон. Единственная реальная сложность в этом примере заключалась в создании заголовка Authorization для PUT Blob REST API, так как он должен быть в специфическом формате и его нужно кодировать и хешировать с помощью метода System.Security.Cryptography.HashAlgorithm.ComputeHash через WebAPI или класс в .NET Micro Framework.

Я также кратко рассказал о некоторых сервисах на платформе Azure и их масштабируемых возможностях в хранении и анализе данных, захваченных IoT-устройствами. Как только ваши устройства начинают захватывать существенные объемы данных, вы можете задействовать такие сервисы Azure, как Event Hubs и Stream Analytics для анализа в реальном времени, а также HDInsight и Machine Learning для более долгосрочных исследований. Выявленные секреты, скрытые в больших массивах данных, можно потом использовать для принятия бизнес-решений, прогнозирования и помощи в выработке успешной корпоративной стратегии.


Benjamin Perkins - старший инженер-эксперт техподдержки в Microsoft и автор трех книг по IIS, NHibernate и Microsoft Azure. В настоящее время пишет книгу по C#, которая будет опубликована параллельно с выпуском C# 6.0. С ним можно связаться по адресу benperk@microsoft.com.

Выражаю благодарность за рецензирование статьи экспертам Мартину Грасруку (Martin Grasruck) и Колину Миллеру (Colin Miller).