Апрель 2016

Том 31 номер 4

Современные приложения - Написание UWP-приложений для Интернета вещей

Фрэнк Ла-Вине | Апрель 2016

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

Одно из наиболее часто употребляемых сегодня словосочетаний в технологической индустрии — «Интернет вещей» (Internet of Things, IoT). IoT обещает превратить каждое устройство в интеллектуальное за счет подключения к облаку. Из облака устройство может предоставлять поверхность управления (control surface) и исходные данные. Камерами можно управлять удаленно. Данные можно собирать и анализировать для выявления важной информации и закономерностей.

Хотя в журнале «MSDN Magazine» было много статей о том, как собирать и анализировать данные от этих устройств, пока что никто еще не рассматривал эту тематику с точки зрения оборудования и соединений. Однако, прежде чем с головой погрузиться в IoT, разработчикам, возможно, придется обрести новые навыки в таких областях, как проектирование электроники, электрика, а в некоторых случаях и в пайке. Разработчики по своей натуре весьма комфортно чувствуют себя при написании кода, но вовсе не испытывают комфорта в обращении с электронными схемами и потоками электронов, лежащими в основе всего, что есть в виртуальном мире. Многие разработчики ПО могут остаться в недоумении по поводу того, что делать с платами для макетирования без пайки (solderless breadboards), соединительными кабелями и сопротивлениями (резисторами). В этой статье я поясню их предназначение.

Конечно, программируемые устройства существуют уже многие годы. Но написание кода для этих устройств зачастую требовало глубокого знания фирменных инструментальных наборов и дорогостоящего оборудования для создания прототипов. Raspberry Pi 2 Model B может работать под управлением Windows 10 IoT Core, особой версии Windows 10. Windows 10 IoT Core бесплатно скачивается с веб-сайта Windows Dev Center IoT (dev.windows.com/iot). Теперь, когда Windows 10 IoT Core работает на Raspberry Pi 2, разработчики UWP-приложений могут задействовать свои существующие навыки и код.

В этой статье я создам UWP-приложение, которое выполняется на Raspberry Pi 2 и будет заставлять мигать светодиод (LED) на основе данных от API метеоусловий. Я дам введение в концепции IoT, аппаратное обеспечение Raspberry Pi 2 Model B, и расскажу, как управлять им из кода на C#.

Проект: мониторинг заморозков

Когда весной возвращается теплая погода, многие с нетерпением ждут возможности снова заняться садоводством. Однако ранняя весна во многих регионах также приносит несколько волн похолоданий. Заморозки могут серьезно повредить растения, поэтому как садовод я хочу знать, прогнозируется ли похолодание. Для этого я вывожу сообщение на экран, если по прогнозу температура опустится ниже 38 градусов по Фаренгейту (или 3,3 градусов по Цельсию). Приложение также будет заставлять быстро мигать LED в качестве дополнительного предупреждения.

Помимо программного обеспечения, обычно необходимого для написания UWP-приложений, мне понадобится некоторое дополнительное аппаратное обеспечение. Естественно, мне нужен Raspberry Pi 2 Model B, на котором я буду развертывать свое решение. Мне также потребуются карта памяти MicroSD, LED-индикатор, сопротивление на 220 Ом, плата для макетирования без пайки, соединительные кабели, USB-мышь и клавиатура, а также HDMI-монитор.

Raspberry Pi 2 Model B Это компьютер, на который я разверну свое UWP-приложение. Raspberry Pi 2 содержит разъем с 40 контактами (рис. 1), некоторые из которых являются контактами ввода-вывода универсального предназначения (General Purpose Input/Output, GPIO). Используя код, я смогу манипулировать состоянием этих контактов или считывать его. Каждый контакт имеет два значения: high (высокое) или low (низкое), где high соответствует более высокому напряжению, а low — более низкому. Это позволяет мне включать или выключать LED-индикатор.

Схема расположения контактов Raspberry Pi 2 Model B
Рис. 1. Схема расположения контактов Raspberry Pi 2 Model B

Карта памяти MicroSD Эта карта действует как жесткий диск для Raspberry Pi 2. Именно там устройство найдет свои загрузочные файлы и ОС. Кроме того, там же будет находиться UWP-приложение после развертывания. Я мог бы обойтись картой памяти SD на 4 Гб, но рекомендуется иметь 8 Гб. Естественно, размер карты памяти определяют требования проекта. Если бы, например, мне было нужно хранить большие объемы данных от датчика локально до их загрузки в облако, тогда мне понадобилась бы более емкая карта SD для поддержки локального файлового хранилища большего размера.

Плата для макетирования без пайки и соединительные кабели Чтобы соединить компоненты с Raspberry Pi 2, нужно создать путь для потока электронов, текущий с Raspberry Pi 2 через мои компоненты и обратно на Raspberry Pi 2. Такой путь называется электрической цепью (circuit). Хотя я мог бы использовать любое количество способов для соединения деталей, самый быстрый и простой — плата для макетирования без пайки (solderless breadboard). Как и подразумевает ее название, мне не потребуется распаивать компоненты для реализации электрической цепи. Для подключений я буду использовать соединительные кабели. Тип платы макетирования без пайки, задействованный мной в этом проекте, имеет набор гнезд, расположенных в 30 рядов и 10 столбцов. Заметьте, что столбцы имеют две группы по пять гнезд: a–e и f–j. Каждое гнездо электрически соединяется с каждым другим гнездом в своем ряду и группе в столбце. Причина этого вскоре станет очевидной.

LED-индикатор и сопротивление В этом проекте я подключу LED-индикатор к плате Raspberry Pi 2. Контакты в Raspberry Pi 2 оперируют при 5 В. Но LED-индикатор при таком напряжении просто сгорит. Сопротивление уменьшит напряжение и сделает электрическую цепь безопасной для LED-индикатора.

Ethernet-кабель, USB-мышь и клавиатура, а также HDMI-монитор Raspberry Pi 2 Model B имеет, помимо прочих разъемов, четыре USB-порта, Ethernet-разъем и HDMI-вывод. Как только UWP-приложение запустится на устройстве, я смогу взаимодействовать с ним во многом аналогично тому, как это происходило бы на ПК или планшете, поскольку у меня есть дисплей и возможность ввода ZIP-кода для получения прогноза для данного региона.

Установка Windows на Raspberry Pi 2

Чтобы приступить к работе с Windows 10 IoT Core, я следовал инструкциям с bit.ly/1O25Vxl. Первый шаг — скачивание Windows 10 IoT Core Tools с bit.ly/1GBq9XR. Windows 10 IoT Core Tools содержат утилиты, WindowsIoTImageHelper и WindowsIoTWatcher, для работы с IoT-устройствами. WindowsIoTImageHelper предоставляет GUI для форматирования карты памяти SD с записью на нее загрузочных файлов Windows IoT Core. WindowsIoTWatcher — это утилита, которая периодически сканирует локальную сеть в поисках устройств Windows IoT Core. Вскоре я задействую их.

Подключение оборудования

Чтобы приступить к созданию решения для IoT, нужно было сделать «вещь», с которой я мог бы работать. Это та часть проекта IoT, которую многие разработчики находят самой пугающей. Большинство разработчиков привыкло к передаче битов с помощью кода, а не к соединению деталей, по которым смогли бы путешествовать электроны. Чтобы не усложнять, я возьму за основу самый базовый проект мигающего LED-индикатора (bit.ly/1O25Vxl), но расширю его данными реального времени из Интернета. Базовое аппаратное обеспечение то же самое: LED-индикатор, плата для макетирования без пайки, соединительные кабели и сопротивление на 220 Ом.

Raspberry Pi 2 Model B имеет ряд GPIO-контактов. Состоянием многих контактов можно манипулировать из кода. Однако некоторые из этих контактов имеют зарезервированные функции, и ими нельзя управлять из кода. К счастью, существуют удобные схемы назначения каждого контакта. Эта схема, показанная на рис. 1, известна как разводка выводов (pinout) и предоставляет схему интерфейса электронной платы.

Проектирование электрической цепи

Суть того, что мне нужно создать, — электрическая цепь для протекания электронов, как на рис. 2. Электроны начинают свое путешествие с контакта 1, помеченного 3.3V PWR на рис. 1. Этот контакт предоставляет питание 3,3 В для электрической цепи, и именно это напряжение будет использоваться для мигания LED-индикатора. Но 3,3 В — слишком большое напряжение для LED-индикатора. Чтобы он не сгорел, я помещаю сопротивление в электрическую цепь для поглощения какой-то части электроэнергии. Следующим в цепи является GPIO 5, который, согласно схеме разводки выводов, соответствует физическому контакту 29. Этот контакт, которым можно управлять из кода, делает LED-индикатор «умнее». Я могу установить выходное напряжение этого контакта либо высоким (3,3 В), либо низким (0 В), и LED-индикатор либо включится, либо выключится.

Схема электрической цепи
Рис. 2. Схема электрической цепи

Формирование электрической цепи

Теперь пора сформировать электрическую цепь, как на рис. 2. Для этого мне понадобится взять приемный контакт одного из соединительных кабелей и подключить его к штырьку 29 на Raspberry Pi 2. Затем я вставляю другой его конец, штырьковый контакт, в отверстие на плате для макетирования без пайки. Я выбираю ряд 7, столбец e. Далее беру LED-индикатор и вставляю его более короткую ножку в отверстие в ряду 7, столбце a, а другую, более длинную ножку LED-индикатора — в отверстие в ряду 8, столбце a. Теперь берем сопротивление и вставляем его одним концом в ряд 8, столбец c, а другим — в ряд 15, столбец c. Наконец, вставляем штырьковый контакт второго соединительного кабеля в отверстие в ряду 15, столбце a, и его приемный контакт подключаем к штырьку 1 на Raspberry Pi 2. Проделав все это, я получаю нечто вроде того, что показано на рис. 3.

Законченные монтажные соединения с Raspberry Pi 2 в прозрачном пластиковом корпусе
Рис. 3. Законченные монтажные соединения с Raspberry Pi 2 в прозрачном пластиковом корпусе

Загрузка устройства

После установки Windows IoT Core на карту MicroSD я вставил карту SD в Raspberry Pi 2. Затем подключил сетевой кабель, USB-мышь и HDMI-монитор. Устройство загрузится и в конечном счете появится экран, как на рис. 4 (я взял на заметку имя устройства и IP-адрес).

Информационный экран по умолчанию в Windows IoT Core для Raspberry Pi 2
Рис. 4. Информационный экран по умолчанию в Windows IoT Core для Raspberry Pi 2

Написание программного обеспечения

Закончив с подготовкой аппаратного обеспечения, можно заняться программной частью IoT-проекта. Создать IoT-проект в Visual Studio весьма легко. По своей сути, он такой же, как и любой другой UWP-проект. Как обычно, я создаю проект, открывая File | New Project в Visual Studio 2015 и выбирая Blank App (Universal Windows) в качестве шаблона. Я предпочел назвать свой проект «WeatherBlink». После загрузки проекта нужно добавить ссылку на Windows IoT Extensions for the UWP. Для этого я щелкаю правой кнопкой мыши References в своем решении в Solution Explorer и в появившемся диалоговом окне ставлю галочку рядом с Windows IoT Extensions for the UWP в узле Extensions дерева Universal Windows (рис. 5). Наконец, я щелкаю OK.

Добавление ссылки на Windows IoT Extensions for the UWP в Visual Studio 2015
Рис. 5. Добавление ссылки на Windows IoT Extensions for the UWP в Visual Studio 2015

Теперь, когда у меня есть правильная ссылка в проекте, я добавлю в начало файла MainPage.xaml.cs следующее выражение using:

using Windows.Devices.Gpio;

Пространство имен Windows.Devices.Gpio содержит всю функциональность, которая потребуется мне для доступа к GPIO-контактам в Raspberry Pi 2. Задать состояние конкретного контакта весьма легко. Так, ниже код присваивает контакту 5 значение High:

var gpioController = GpioController.GetDefault();

gpioPin = gpioController.OpenPin(5);
  gpioPin.Write(GpioPinValue.High);

Считать значение контакта так же просто:

var currentPinValue = gpioPin.Read();

Поскольку GPIO-контакты — ресурсы, которые должны быть общими в рамках приложения, ими легче управлять через переменные уровня класса:

private GpioPin gpioPin;
private GpioPinValue gpioPinValue;

А инициализировать их в каком-то общем методе:

private void InitializeGPIO()
{
  var gpioController = GpioController.GetDefault();

  gpioPin = gpioController.OpenPin(5);
  gpioPinValue = GpioPinValue.High;
  gpioPin.Write(gpioPinValue);
  gpioPin.SetDriveMode(GpioPinDriveMode.Output);
}

Создание простого UI

Поскольку это UWP-приложение, у меня есть доступ ко всему арсеналу интерфейсных UWP-элементов управления в Windows 10. То есть мое IoT-решение может получить полностью интерактивный интерфейс без дополнительных усилий с моей стороны. Многие IoT-реализации являются «безголовыми» (без экрана), а значит, у них вообще нет UI.

У этого проекта будет простой UI для отображения сообщения на основе прогноза погоды. Если клавиатура и мышь подключены к Raspberry Pi 2, конечные пользователи смогут вводить ZIP-код и соответственно обновлять прогноз погоды, как показано на рис. 6.

UI UWP-приложения WeatherBlink
Рис. 6. UI UWP-приложения WeatherBlink

Делаем устройство интеллектуальнее

Чтобы мое IoT-устройство было осведомлено о прогнозах погоды, следует извлекать эти данные из Интернета. Так как это UWP-приложения, у меня есть все необходимые библиотеки и инструменты. Я предпочел получать метеоданные с openweathermap.org/api, который передает такие данные для данного месторасположения в формате JSON. Все температуры определены в градусах Кельвина. На рис. 7 показан мой код для проверки прогноза и изменения скорости мигания на основе полученных результатов. Как правило, предупреждения о заморозках выдаются, как только температура воздуха опускается примерно до 38 градусов по Фаренгейту (3,3 градуса по Цельсию). Если есть вероятность заморозков, я хочу, чтобы LED-индикатор быстро мигал, оповещая меня о том, что моему саду грозит опасность. В ином случае LED-индикатор должен мигать медленно, просто давая мне знать, что у моего устройства еще есть электропитание. Поскольку вызовы REST API и разбор JSON-ответов в UWP — широко освещенная тематика, я опущу здесь соответствующий код для краткости.

Рис. 7. Проверка погоды и частота мигания

private async void LoadWeatherData()
{
  double minTempDouble = await GetMinTempForecast();

  // 38 градусов по Фаренгейту или 3.3 градуса по Цельсию =
  // 276.483 градуса по Кельвину
  if (minTempDouble <= 276.483)
  {
    Blink(500);
    txtStatus.Text = "Freeze Warning!"
  }
  else
  {
    Blink(2000);
    txtStatus.Text = "No freezing weather in forecast."
  }

Метод Blink прост: он задает интервал таймера диспетчеризации на основе переданного ему параметра:

private void Blink(int interval)
{
  blinkingTimer = new DispatcherTimer();
  blinkingTimer.Interval =
    TimeSpan.FromMilliseconds(interval);
  blinkingTimer.Tick += BlinkingTimer_Tick;
}

BlinkingTimer_Tick — это метод, где находится код, включающий или выключающий LED. Он считывает состояние контакта, а затем присваивает ему противоположное значение:

private void BlinkingTimer_Tick(
  object sender, object e)
{
  var currentPinValue = gpioPin.Read();

  if (currentPinValue == GpioPinValue.High)
  {
    gpioPin.Write(GpioPinValue.Low);
  }
  else
  {
    gpioPin.Write(GpioPinValue.High);
  }
}

Полный исходный код находится в пакете, сопутствующем этой статье.

Развертывание приложения

Развертывание приложения на Raspberry Pi 2 требует начальной подготовки на ПК. Сначала мне нужно сменить архитектуру на ARM, а затем под раскрывающимся списком рядом со значком воспроизведения выбрать Remote Machine. Появится диалог Remote Connections (рис. 8), где можно либо вручную ввести IP-адрес устройства, либо выбрать нужное из списка автоматически обнаруженных устройств. В любом случае включать аутентификацию не требуется. После этого я щелкаю Select и теперь могу развернуть свое решение на устройстве.

Диалог Remote Connections
Рис. 8. Диалог Remote Connections

Некоторые соображения по дизайну

Мир IoT открывает новые возможности и ставит трудные задачи перед разработчиками. При создании прототипа IoT-решения важно учитывать исполняющую среду, где это решение будет развернуто. Есть ли у данного устройства доступ к электропитанию и сети? Домашний холодильник определенно будет иметь такой доступ, но у метеостанции в далеком лесу может и не быть его. Очевидно, что большая часть этих вопросов будет диктовать то, как должно создаваться устройство, в частности для уличного варианта размещения устройства следует добавить герметический контейнер. Будет решение обходиться без дисплея или потребует UI? Некоторые из подобных вопросов будут определять, то как будет написан код. Например, если устройство передает данные по сети 4G, надо учесть стоимость передачи данных. В таком случае определенно следует оптимизировать объем данных, отправляемых устройством. И, как в случае любого чисто программного проекта, крайне важно помнить о требованиях конечного пользователя.

Заключение

Хотя управление LED-индикатором вряд ли изменит этот мир, есть много других применений IoT, способных на это. Вместо того чтобы полагаться на API прогноза погода, я мог бы подключить датчик температуры к Raspberry Pi 2 и поместить его в моем саду или где-то рядом. А как насчет устройства, которое могло бы отправлять оповещение по электронной почте, если оно обнаруживает повышение влажности в конкретной части моего дома? Вообразите установку датчиков для наблюдения за качеством воздуха по всему городу или в его окрестностях. Представьте, что на крышах размещены датчики веса, определяющие, сколько снега копилось на крыше, чтобы вовремя предупредить о риске обрушения крыши. Возможности просто безграничны.

Возьмите и создайте нечто потрясающее!


Фрэнк Ла-Вине (Frank La Vigne) — идеолог технологий в группе Microsoft Technology and Civic Engagement, где он помогает пользователям применять технологии и формировать соответствующие сообщества. Регулярно ведет блог на FranksWorld.com и имеет канал на YouTube под названием «Frank’s World TV» (youtube.com/FranksWorldTV).

Выражаю благодарность за рецензирование статьи экспертам Рэчел Аппель (Rachel Appel), Роберту Бернштейну (Robert Bernstein) и Эндрю Эрнандесу (Andrew Hernandez).


Discuss this article in the MSDN Magazine forum