Отправляем данные с Arduino в Azure IoT Hub

d2691e42d3c3470e90bbfa4e37cd30a9.png

Не так давно я стал счастливым обладателем Genuino MKR1000. Ресурс Hackster.io совместно с Microsoft проводил конкурс на лучшую идею. Пусть я не успел воплотить свою идею в жизнь и принять участие во второй части конкурса, но я могу поделится с вами информацией, которая поможет вам осуществить свои задумки. Под катом о том, как отправить данные с Arduino в облако и как их считать, если у вас есть WiFi шилд или MKR1000.

Настройка Azure


Заходим на portal.azure.com, нажимаем »+», выбираем «Интернет вещей» — «IoT Hub» и придумываем название нашему хабу. Я решил назвать хаб просто и скромно — alexey. Ценовую категорию я выбрал бесплатную S1 (на одно устройство).

9477b149c013427e8cc8e5fb43fe3042.PNG

Собственно, на этом конфигурация хаба завершена. Необходимо будет еще получить первичный ключ, но это можно сделать позднее.

Настройка Arduino


Установим необходимую библиотеку WiFi101:

aca9ebe9239a434f884079b8560573d5.PNG

Нам необходима версия выше чем 0.8, так что если у вас уже установлена старая библиотека, то обновите ее.

884517d42fc84e2c9df22139af8e8600.PNG

Azure IoT Hub использует SSL для безопасности подключения. Но так как у Arduino недостаточно памяти для того чтобы хранить в ней сертификат SSL, то нам необходимо записать его в чип WiFi. Для этого нужно обновить Firmware версию WiFi101. Скачиваем по ссылке файл Wifi101_FirmwareUpdater_windows.zip

В Arduino IDE открываем скетч Файл — Примеры — WiFi101 — FirmwareUpdater. Подключаем MRK1000 и загружаем скетч. Теперь плата Arduino готова к получению прошивки с сертификатом.
Распаковываем zip архив Wifi101_FirmwareUpdater_windows, который мы недавно скачали и запускаем winc1500-uploader-gui.exe. Вводим адрес узла нашего хаба.

ccc6cda947de4c98be131215a56ba566.PNG

Кликаем и выделяем COM порт, после чего нажимаем «Upload certificate»

3de889a541644c958d40e46b4e9e0ad9.PNG

Остается дождаться загрузки сертификата

8c3a1b77e72041318f09af910273de62.PNG

Microsoft Azure IoT Hub использует Shared Access Signatures.
Это сигнатуры доступа, которые могут быть использованы для работы с очередью сообщений IoT Hub-а без пароля. Нам необходимо создать SAS token. Для того чтобы не делать это в коде Arduino можно использовать утилиту Device Explorer
Скачиваем по ссылке файл SetupDeviceExplorer.msi
Устанавливаем и запускаем. Заходим на портал Azure в IoT Hub и нажимаем на ключик в правом верхнем углу:

e35f43a181ce42ce81fe320697a2e4c6.PNG

Выбираем из списка iothubowner и копируем «Строка подключения — первичный ключ»

1675d8e5829f4138bd0ce8d2e47f06f5.PNG

Эту строку вводим в окно закладки Configuration приложения Device Explorer и нажимаем кнопку Update

ff75a92c64124b0a812ff6ed5cec8606.PNG

Переходим на закладку Management. Здесь мы можем добавить новое устройство. Кнопка Create, придумываем ID нашему девайсу (я назвал свое устройство myDevice) и нажимаем Create.

cb0925f595704a0c8248db2a3c526b29.PNG

В списке появится наше устройство. Выделяем строку с ним и нажимаем SAS Token…
Вводим промежуток дней и нажимаем Generate. Из получившегося токена нам нужна только часть начинающаяся с «SharedAccessSignature sr=» (копируйте аккуратно, так как текст SharedAccessSignature встречается в строке 2 раза)

74307a25c447409baaaf1a2f710d1355.PNG

Англоязычный мануал о том как пользоваться Device Explorer находится здесь:
How to use Device Explorer for IoT Hub devices

Код Arduino


Рассмотрим код Arduino. Заголовок у нас такой:

#include
#include

char hostname[] = «alexey.azure-devices.net»; // имя узла Azure IoT Hub
char authSAS[] = «SharedAccessSignature sr=alexey.azure-devices.net%2fdevices%2fmyDevice&sig=D7OxGEm98bqAQDYk33d0DzPB92EuGMkjkzKBCsBBksc%3d&se=1493799405»; // SAS token, который был сгенерирован Device Explorer
String deviceName = «myDevice»; // ID нашего девайса
char ssid[] = «myhomenet»; // имя вашей точки доступа wi-fi
char pass[] = «password123»; // пароль от точки доступа
String uri = »/devices/myDevice/messages/events? api-version=2016–02–03»;
int status = WL_IDLE_STATUS; // статус доступности интернета
WiFiSSLClient client;
Строка uri будет различна для отправки и для получения данных.
Если бы мы получали данные, то строка была бы
/devices/myDevice/messages/devicebound? api-version=2016–02–03
Кроме отправки и получения существует возможность завершить/отклонить или сбросить сообщение.
В setup мы только делаем стандартное подключение к сети Wi-Fi

void setup() {
Serial.begin(9600);
Serial.println("Setup begin");
// check for the presence of the shield:
if (WiFi.status() == WL_NO_SHIELD) {
Serial.println("У Arduino отсутствует WiFi шилд");
while (true); // не продолжаем выполнение кода дальше
}
// пытаемся подключится к сети Wifi:
while ( status != WL_CONNECTED) {
Serial.print("Попытка подключения к точке доступа ");
Serial.println(ssid);
status = WiFi.begin(ssid, pass);
delay(10000); // ждем 10 секунд чтобы подключение завершилось
}
Serial.println("Connected to Wi-Fi");
}

Нам нужен метод, который будет отправлять строку текста запросом POST по протоколу HTTP на наш узел. Я не заморачиваюсь и отправляю строку текста, хотя обычно в примерах генерируют и отправляют json.

void httpPost(String content)
{
client.stop(); // закрываем подключение, если вдруг оно открыто
if (client.connectSSL(hostname, 443)) {
client.print("POST ");
client.print(uri);
client.println(" HTTP/1.1");
client.print("Host: ");
client.println(hostname);
client.print("Authorization: ");
client.println(authSAS);
client.println("Connection: close");
client.print("Content-Type: ");
client.println("text/plain");
client.print("Content-Length: ");
client.println(content.length());
client.println();
client.println(content);
delay(200);
} else {
Serial.println("HTTP POST отправка неудачна");
}
}

Теперь для того чтобы отправить строку текста достаточно вызвать метод

httpPost("Some message from Arduino");

Но мы еще и считаем ответ, чтобы убедится в том, что данные благополучно получены

httpPost("Some message from Arduino");
String response = "";
char c;
while (client.available()) {
c = client.read();
response.concat(c);
}
if (!response.equals(""))
{
if (response.startsWith("HTTP/1.1 204")) {
Serial.println("Строка была отправлена в Azure");
} else {
Serial.println("Ошибка");
Serial.println(response);
}
}

Весь код вы можете скачать с github

Консольное приложение, считывающее данные с очереди сообщений IoT Hub


Создаем консольное приложение.
Открываем NuGet Package Manager, ищем WindowsAzure.ServiceBus и устанавливаем.
Добавляем пару namespace:

using Microsoft.ServiceBus.Messaging;
using System.Threading;


И объявлений:

static string connectionString = "HostName=alexey.azure-devices.net;SharedAccessKeyName=iothubowner;SharedAccessKey=xrzUfBj8gaq2i310MhRCcSEs08t3lk7zbCNI4Tltqp4=";
static string iotHubD2cEndpoint = "messages/events";
static EventHubClient eventHubClient;


Здесь вы можете заметить, что значением connectionString я ввел значение, полученное с портала Azure — это «Строка подключения — первичный ключ». Добавляем следующий метод:

private static async Task ReceiveMessagesFromDeviceAsync(string partition, CancellationToken ct)
{
    var eventHubReceiver = eventHubClient.GetDefaultConsumerGroup().CreateReceiver(partition, DateTime.UtcNow);
    while (true)
    {
        if (ct.IsCancellationRequested) break;
        EventData eventData = await eventHubReceiver.ReceiveAsync();
        if (eventData == null) continue;

        string data = Encoding.UTF8.GetString(eventData.GetBytes());
        Console.WriteLine("Message received. Partition: {0} Data: '{1}'", partition, data);
    }
}


и, наконец, в Main добавляем код:

Console.WriteLine("Получение сообщений. Ctrl-C для выхода.\n");
eventHubClient = EventHubClient.CreateFromConnectionString(connectionString, iotHubD2cEndpoint);

var d2cPartitions = eventHubClient.GetRuntimeInformation().PartitionIds;

CancellationTokenSource cts = new CancellationTokenSource();

System.Console.CancelKeyPress += (s, e) =>
{
  e.Cancel = true;
  cts.Cancel();
  Console.WriteLine("Выходим...");
};

var tasks = new List();
foreach (string partition in d2cPartitions)
{
   tasks.Add(ReceiveMessagesFromDeviceAsync(partition, cts.Token));
}  
Task.WaitAll(tasks.ToArray());


Если вы запустите это консольное приложение, то сможете считать сообщения, отправляемые включеной платой Arduino.

Полезные ссылки:


Приступая к работе с центром Azure IoT с использованием .NET
MKR1000 Azure IoT Hub Interface Using HTTP
MKR1000 Temp and Humidity Sensor

© Habrahabr.ru