Enviar mensajes cloud-to-device a Raspberry con Docker, .NET Core y Web App On Linux (parte III - Azure IoT Hub cloud-to-device API)


image

Nota:

Este post es la continuación de la guía: “Enviar mensajes device-to-cloud a Azure IoT Hub desde Raspberry usando Node.js y Docker (parte II - envío de mensajes) , favor de realizar primero los paso del post antes de seguir con esta publicación.

Azure IoT Hub nos frece mensajería confiable device-to-cloud y cloud-to-device a gran escala, lo cual nos permite medir de manera inmediata mensajes de telemetría o mensajes personalizados de cada uno de nuestros dispositivos en el mundo, seguro y con alta disponibilidad.

Para enviar mensajes cloud to device desde Azure IoT Hub, es necesario instalar el SDK de Azure y luego desarrollar un programa para enviar mensajes a nuestros dispositivos. En nuestro caso vamos a desarrollar nuestro programa de mensajería en .NET Core (podemos usar también Node.js, Java o Python) y luego lo compilaremos dentro de un contenedor de Docker y expondremos una API en Azure Web App On Linux
 

Pre Requisitos

  1. Raspberry Pi2+
  2. Raspbian OS
  3. Conexión a Internet
  4. NPM
  5. Tener una suscripción de Azure
  6. Visual Studio 2017, obtenerlo gratis aquí.
  7. Docker para Windows, obtenerlo aquí.

Arquitectura de envío y procesamiento de mensajes Azure IoT Hub:

Azure IoT Hub as cloud gateway in internet of things solution

Fuente: https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-what-is-iot-hub


Descargar código de GitHub:

https://github.com/Kodran/RPi-Docker-Azure-IoTHub


Crear .NET Core Web API con soporte de Docker en Visual Studio

En Visual Studio creamos un nuevo proyecto .NET Core llamado: Azure.IoTHub.CloudToDevice.API.

Templates –> Visual C# –> .NET Core –> ASP.NET Core Web Application (.NET Core)

Luego vamos a elegir la opción de Web API con soporte a Docker activado:

5

6

image


Probar contenedor Docker de .NET Core localmente

Nota: antes de correr un contenedor localmente, aseguremos que “Docker for Windows” se encuentre corriendo y que nuestras particiones se encuentre compartidas. Para esto podemos ir a “Inicio –> búsqueda –> Docker for Windows:

9

11

Para crear y desplegar un contenedor localmente solo damos clic en el botón “Docker” en Visual Studio, esto disparará una tarea de compilación automática de Docker para crear y desplegar el contenedor en una maquina virtual de Hyper-V:

image

image

Una vez que termine de crear el contenedor, podemos abrir nuestra consola para verificar que efectivamente nuestro contenedor fue creado y desplegado correctamente.

Ingresamos los comandos:

docker images

docker ps

14


Desplegar contenedor Docker de .NET Core a Web App On Linux

Damos clic derecho en nuestro proyecto “Azure.IoTHub.CloudToDevice.API” y seleccionamos “Publish”, luego elegimos App Service Web App On Linux y desplegamos nuestro contenedor:

15

image

image

18

Probar endpoint  de contenedor de Azure Web App On Linux

Para comprobar que nuestro contenedor fue desplegado correctamente en Azure, ingresamos a https://portal.azure.com y vamos a la sección de App Service:

19


Ahora hacemos una petición a nuestra Web API con endpoint de Azure:

21

Crear API para envío de mensajes cloud-to-device

En nuestro proyecto agregamos un nuevo controlador llamado: CloudToDeviceController

23

24


Ahora creamos el modelo de entrada de datos a nuestra API: “CloudToDeviceMessage.cs”:

25

26

27

Agregar dependencias de Azure IoT Hub

En nuestro proyecto damos clic derecho en dependencias y luego agregamos la librería de NuGet: “Microsoft.Azure.Devices”:

 31

32


Codificar método POST de envío de mensajes device-to-cloud

Agregar siguiente código en nuestro controlador CloudToDeviceController.cs y la cadena de conexión de IoT Hub:

34

CloudToDeviceController.cs

using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Azure.IoTHub.CloudToDevice.API.Model; using Microsoft.Azure.Devices; using System.Text; namespace Azure.IoTHub.CloudToDevice.API.Controllers { [Produces("application/json")] [Route("api/CloudToDevice")] public class CloudToDeviceController : Controller { private static string connectionString = "your-azureiothub-primaryKey-connectionString"; [HttpPost] public async Task Post([FromBody]CloudToDeviceMessage message) { try { var serviceClient = ServiceClient.CreateFromConnectionString(connectionString); var commandMessage = new Message(Encoding.ASCII.GetBytes(message.Message)); await serviceClient.SendAsync(message.DeviceId, commandMessage); return new OkObjectResult(message); } catch (Exception ex) { Response.StatusCode = 500; return new ObjectResult(new Exception(ex.Message)); } } } }

Lo que hace él código es recibir un mensaje por POST y tomar el deviceId y mensaje para luego enviarlos a un dispositivo registrado en IoT Hub.

Publicar contenedor en Azure Web App On Linux

Damos clic derecho en nuestro proyecto y volvemos a publicar nuestro contenedor en Azure:

15

36

18

Crear recibidor de mensajes cloud-to-device IoT Hub

Una vez que hemos logrado publicar nuestro contenedor que envía mensajes a nuestros dispositivos, vamos de vuelta a la Raspberry para crear un contenedor que se va a encargar de recibir los mensajes de Azure IoT Hub.

Para dar orden a nuestro entorno, vamos a crear una carpeta llamada “cloudToDeviceReader” dentro de nuestro proyecto :

$ cd reader

$ sudo mkdir cloudToDeviceReader

$ cd cloudToDeviceReader

Creamos los archivos:
  1. package.json
  2. readCloudToDeviceMessage.js
  3. Dockerfile
  4. .dockerignore
package.json
{
  "name": "azure-iothub-cloudToDevice-reader",
  "version": "1.0.0",
  "description": "docker nodejs azure iot hub cloud to device reader",
  "main": "readCloudToDeviceMessage.js",
  "scripts": {
    "start": "node readCloudToDeviceMessage.js"
  },
  "author": "Jorge Castro",
  "license": "ISC",
  "dependencies": {
    "azure-event-hubs": "0.0.8",
    "azure-iot-device": "^1.1.14",
    "azure-iot-device-mqtt": "^1.1.14",
    "azure-iothub": "^1.1.11"    
  }
}

readCloudToDeviceMessage.js
'use strict';

var iothub = require('azure-iothub');
var connectionString = 'your-azure-iothub-primaryKey-connectionString';
var registry = iothub.Registry.fromConnectionString(connectionString);
var device = new iothub.Device(null);

this.init = function(){
	
	device.deviceId = 'dockerNodejsDevice';
	registry.create(device, function(err, deviceInfo, res) {
	  if (err) {
		registry.get(device.deviceId, printDeviceInfo);
	  }
	  if (deviceInfo) {
		printDeviceInfo(err, deviceInfo, res)
	  }
	});

	function printDeviceInfo(err, deviceInfo, res) {
	  if (deviceInfo) {
		console.log('Device ID: ' + deviceInfo.deviceId);
		console.log('Device key: ' + deviceInfo.authentication.symmetricKey.primaryKey);
		console.log('Waiting for cloud message...');
		
	  }
	}
}

this.readCloudToDeviceMessage = function(){
	var clientFromConnectionString = require('azure-iot-device-mqtt').clientFromConnectionString;
	var Message = require('azure-iot-device').Message;	
	var deviceConnectionString = 'your-iothub-deviceId-primaryKey-connectionString';
	var client = clientFromConnectionString(deviceConnectionString);
	
	function printResultFor(op) {
	  return function printResult(err, res) {
		if (err) console.log(op + ' error: ' + err.toString());
		if (res) console.log(op + ' status: ' + res.constructor.name);
	  };
	}
	var connectCallback = function (err) {
	  if (err) {
		console.log('Could not connect: ' + err);
	  } else {		
		client.on('message', function (msg) {
		  console.log('Id: ' + msg.messageId + ' Body: ' + msg.data);
		  client.complete(msg, printResultFor('completed'));
		});
		
	  }
	};
	client.open(connectCallback);
}

this.init();
this.readCloudToDeviceMessage();


Dockerfile

FROM robotany/raspberrypi-nodejs

# Create app directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

# Install app dependencies
COPY package.json /usr/src/app/
RUN npm install

# Bundle app source
COPY . /usr/src/app

EXPOSE 8080
CMD [ "npm", "start" ]



.dockerignore
node_modules
npm-debug.log



Crear y correr contenedor para recibir mensajes cloud to device

Vamos a la ruta de nuestro programa que recibe los mensajes cloud-to-device en consola y ejecutamos los siguientes comandos de Docker:

$ cd projects/azure-iothub-demo/reader/cloudToDeviceReader

$ sudo docker build –t yourUser/rpi-azure-iothub-cloud-reader .

image

$ sudo docker run yourUser/rpi-azure-iothub-cloud-reader

image

image


Probar envío de mensajes cloud to device

Para enviar un mensajes a nuestra Raspberry, vamos a realizar una petición POST a nuestra API.

Puedes utilizar Postman para realizar peticiones a Azure. La manera en que vamos a realizar la petición a Azure es enviando un mensaje JSON con la estructura del modelo: “CloudToDeviceMessage.cs”.

Ingresamos el endpoint de nuestra API y la petición en el cuerpo del mensaje:

image


Consola de contenedor de Raspberry:

image

Enviar otro mensaje a dispositivo:

image

image


Muchas felicidades!! haz logrado programar un flujo completo de envío de mensajes device-to-cloud y cloud-to-device usando Azure IoT Hub, Docker y Raspberry.

Azure nos ofrece una gran variedad de servicios que nos permite extender la funcionalidad de IoT Hub, entre ellas podremos encontrar procesamiento de mensajes para diversos propósitos. Les dejo algunos articulos de la documentación oficial de Microsoft donde explica como lidiar con diferentes tipos de escenarios de IoT:


Descargar código de GitHub:

https://github.com/Kodran/RPi-Docker-Azure-IoTHub

Artículos relacionados:


Saludos!


Comments

Popular posts from this blog

Configurar y desplegar una Web API en Azure App Service Environment

Despliegue de contenedores Docker a Azure Web Apps

Patrones de diseño para aplicaciones de alta disponibilidad en Azure - Resilient Applications (Parte I: Retry Policy)

Conectar .NET Web API con Azure API Management

Configurar trigger de Integración Continua en VSTS para ejecutar una tarea de compilación al subir cambios en Source Control