Latch y el Internet de las Cosas: Integración con Arduino (V)

ElevenPaths  26 octubre, 2015

En la entrada anterior estudiamos cómo cargar el firmware necesario en el módulo WiFi para que satisfaga nuestras necesidades. Ahora veremos cómo funciona la API de Latch, y cómo realizar un Sketch de Arduino que la implemente.

La API de Latch

A estas alturas ya sabéis que Latch pone a nuestra disposición una API estándar y abierta que podemos utilizar mediante peticiones HTTP convencionales de tipo GET. Teneís toda la información en https://latch.elevenpaths.com. Aquí resumiremos algunas partes importantes.

Según indica la documentación de Latch: “todas las solicitudes a la API de Latch deben estar firmadas. El proceso de firma es una versión simplificada del protocolo Oauth de dos vías”. Cada petición debe ir acompañada de dos encabezados (HTTP headers) de autenticación: “X-11Paths-Date” y “Authorization” con los siguientes formatos:

X-11Paths-Date: yyyy-MM-dd HH:mm:ss

El encabezado X-11Paths-Date contiene la fecha y hora UTC en el momento de realización de la petición, cuyo formato y valor debe ser exactamente igual al utilizado en el proceso de creación de la petición.

Authorization: 11PATHS applicationId requestSignature

Donde:

  • 11PATHS es una constante que determina el método de autenticación. 
  • applicationId es un identificador alfanumérico que se obtiene al crear la aplicación u operación. 
  • requestSignature es una firma derivada de la url, parámetros, encabezados personalizados y fecha de la solicitud, firmada mediante el algoritmo HMAC-SHA1 con el secreto obtenido al crear la aplicación, y codificada en Base64.

El applicationId y el secreto se obtienen en el momento de crear la aplicación desde el Panel de Control de la web de desarrolladores de Latch.

Panel de control de la web de desarrolladores de Latch

La operación para obtener el estado del latch que el usuario tiene establecido para la aplicación definida en la cabecera Authorization, es una petición GET a la URL:

https://latch.elevenpaths.com/api/1.0/status/{accountId}

La API de Latch devolverá un json donde se indica el estado correspondiente:

{“data”:{“operations”:{“WFqXXXXXXXXXXXXXXXXXZORO”:{“status”:”on”}}}}

El accountId del usuario se obtiene como resultado de la operación de pareado o emparejamiento. Esta puede ser realizada mediante un simple shell script en Bash como este:

#!/bin/bash

if [ -z "$1" ]; then
 echo -e "nUsage: $0 n"
 exit 0
fi

ApplicationId="WFqXXXXXXXXXXXXXXXXXZORO"
SecretKey="I8QsZCXXXXXXXXXXXXXXXXXXXXXXXXXXXXHml"

Server="https://latch.elevenpaths.com"
URL="/api/1.0/pair/$1"

requestSignature+="GETn"
date=`date -u '+%Y-%m-%d %H:%M:%S'`
requestSignature+="$datenn$URL"
signed=`echo -en "$requestSignature" | openssl dgst -sha1 -hmac "$SecretKey" -binary`
b64signed=`echo -n "$signed"|base64`

auth_header="Authorization:11PATHS $ApplicationId $b64signed"
date_header="X-11Paths-Date: $date"

response=`curl -q -s -N --header "$auth_header" --header "$date_header" "$Server$URL"`

echo $response

Si el proceso de emparejamiento resulta con éxito, la API de Latch devuelve un json que contiene el accountId del usuario, tal y como se muestra a continuación:

{“data”:{“accountId”:”3d86bXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX65dea”}}

Disponiendo de esta información es posible consultar la API de Latch para obtener el estado que el usuario establece desde la App en su Smartphone o Tablet.

Date:   2015-08-31 13:55:54
URL:    /api/1.0/status/3d86bXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX65dea
Request: GETn2015-08-31 13:55:54nn/api/1.0/status/3d86bXXXXXXXXXXXXXXXXXXX65dea
Request Signature: aPVc83HlPE0CPQz4jR5HJrU3Zyc=
Header:  Authorization:11PATHS WFqRXXXXXXXXXXXXZORO aPVc83HlPE0CPQz4jR5HJrU3Zyc=
Header:  X-11Paths-Date: 2015-08-31 13:55:54

Una visto cómo funciona, la programación del sketch de Arduino comprende básicamente:

  • Conexión a la red Wifi
  • Obtención de la hora actual
  • Firma con HMAC-SHA1
  • Codificación en Base64
  • Petición HTTP GET

Sketch Arduino 

Pese a que puede parecer de escasa complejidad, la implementación requiere gran parte de los 2 Kbytes de memoria del Arduino UNO (Atmega328p), por lo que es necesario recurrir asiduamente a las facilidades PROGMEM, F(), strcpy_P(), etc. que proporciona la librería AVR libc (avr/pgmspace.h); imprescindible para economizar el uso de la memoria SRAM utilizando, cuando sea posible, la memoria Flash (memoria de programa 32Kbytes) para almacenar todo aquel dato susceptible de ello: por ejemplo, los arrays de caracteres que no varíen (constantes). De hecho, es inevitable el empleo de recursos poco ortodoxos pero necesarios para ahorrar memoria, prescindiendo de métodos elegantes pero de elevado consumo de memoria, como la librería aJson del Interactive Matter Lab para el parseo de la respuesta de Latch, optando por realizar una simple comparación de cadenas de caracteres. 


Espdunio 

La librería espduino.h aporta un sencillo interface de comunicación con el módulo ESP82688. Tan solo es necesario iniciar una instancia ESP con los valores del puerto serie hardware, el puerto serie software para la transmisión de mensajes de depuración, y la línea de conexión CH_PD para el arranque del módulo. Una vez instanciada se invoca función wifiConnect con el SSID y la contraseña de la red wifi a la que realizar la conexión. Los detalles sobre este proceso son enviados por el puerto de depuración con carácter informativo. 

La API RESTful se implementa en la librería rest.h, también fácil de usar. Solo hay que instanciar REST indicado el objeto ESP, e iniciarla con los valores del servidor de conexión (nombre FQDN o dirección IP), puerto TCP, y si hay cifrado SSL o no.

// github.com/tuanpmt/espduino (c) Tuan PM 
#include "espduino.h"         // Wifi library for ESP8266 using SLIP protocol via serial port
#include "rest.h"             // code for ESP8266 can found here github.com/tuanpmt/esp_bridge

// Setting ESP instance
ESP(Stream *serial, Stream* debug, int chip_pd); // esp(HardwareSerial, SoftwareSerial, CH_PD)
void wifiConnect(const char* ssid, const char* password);

// Setting REST instance
REST(ESP *e);
boolean begin(const char* host, uint16_t port, boolean security);

// Set Content-Type Header
void setHeader(const char* value);  //setHeaer("Header1:value1rnHeader2:value2rn");

// Get REST response
void get(const char* path);
uint16_t getResponse(char* data, uint16_t maxLen);

Tras su inicialización, es posible utilizar las funciones setHeader para establecer cabeceras HTTP personalizadas, get para realizar una solicitud GET, y getResponse para obtener la respuesta. El timeout configurable por defecto es de 5 segundos.

TIME

Para la obtención de la fecha actual se utiliza la librería time.h, estándar de Arduino que implementa un reloj RTC (Real Time Clock) por software con una precisión más que razonable. No obstante, al ser software es necesario establecer fecha y hora cada vez que el sistema se inicia. 

El establecimiento de la fecha y hora actual en sistemas aislados se suele realizar mediante un RTC hardware acompañado de una pequeña batería que lo mantiene en funcionamiento constante, o bien a través de receptores de radio DCF77 o incluso GPS, capaces de proporcionar el tiempo actual. 

Aunque cuando se dispone de conexión a Internet, lo normal es utilizar protocolos específicos para la sincronización del tiempo como NTP. Pero para evitar su implementación es posible usar la API REST y obtener la fecha y hora actual de un servicio web como el de este ejemplo date.jsontest.com, ya que no es imprescindible una sincronización exacta. 


Las funciones de tiempo utilizan el tipo de dato time_t definido en la biblioteca ISO-C para el almacenamiento de valores de tiempo, ampliamente utilizado en todo tipo de sistemas. Con un tamaño de 32 bits, almacena el valor del tiempo UNIX (POSIX); es decir, el número de segundos transcurridos desde la media noche UTC del 1 de enero de 1970. El último segundo representable con este formato será a las 03:14:07 UTC del 19 de enero de 2038, por lo que hay tiempo de sobra antes del “Y2K38“. 


HMAC-SHA1 

La función de firma HMAC-SHA1 se implementa en la librería publicada por Peter Knight “@Cathedrow” en su criptosuite para Arduino. Solo hay que tener en consideración que el tipo de dato con el trabaja es unit8_t. 
#include "sha1.h"         // github.com/Cathedrow/Cryptosuite   Cryptographic suite for Arduino
 
// HMAC-SHA1 environment
uint8_t *hash;

void initHmac(const uint8_t* secret, int secretLength); // key, and length of key in bytes
virtual void write(uint8_t);
using Print::write;

La función initHmac se inicializa con el secreto ubicado en un array de 40 elementos del tipo uint8_t, tras la carga de la request, el resultado de la firma HMAC-SHA1 se almacena en un array de 20 elementos, igualmente de tipo uint8_t.

Base64

La función de codificación en Base64 es un aporte de Adam Rudd publicada en su espacio de GitHub; su utilización es muy sencilla: 

#include "base64.h"         // github.com/adamvr/arduino-base64  Copyright (C) 2013 Adam Rudd
 
// Base64 environment
int base64_encode(char *output, char *input, int inputLen);
La función base64_encode solo requiere el array de caracteres destino, de 32 elementos, y el array origen, de 20 elementos uint8_t, al que hay que aplicar un molde de tipos a carácter (char*). 


Intermediación SSL 

La implementación SSL de espduino soporta un tamaño máximo de clave de 1024 bits, por lo no podrá realizar la negociación HTTPS con servidores web que presenten un certificado con una longitud de clave superior…. Como es el caso del servidor que aloja la API de Latch. Aunque poco ortodoxa, a modo de prueba de concepto, una forma de sortear esta incompatibilidad es intercalar un servidor web que presente un certificado SSL con un tamaño de clave de 1024 y que a su vez, transmita las peticiones hacia el servidor web final, como un proxy inverso. 

Para el caso de Latch esta intermediación SSL puede armarse fácilmente con un servidor NGINX. Una vez generado el certificado adecuado, se configura de la siguiente manera:

# nginx config site for SSL arrangement
server {
        listen YOUR TCP PORT;
        server_name YOUR IP OR SERVER NAME;
        ssl on;
        ssl_certificate sites-enabled/server.crt;
        ssl_certificate_key sites-enabled/server.key;
        error_page 497 https://$host:$server_port$request_uri;

        location  / {
                return 301 https://latch.elevenpaths.com:443/$request_uri;
        }
        location /api/ {
                proxy_set_header Content-Type "";
                proxy_pass https://latch.elevenpaths.com:443;
        }
        location = /X-11Paths-Date {
                proxy_http_version 1.0;
                proxy_pass http://localhost:9000;
        }
}

Aprovechando la flexibilidad que aporta disponer de un sistema intermedio, mediante el último bloque de configuración se reenvía la petición de /X-11Paths-Date a un discreto servidor local (thttpd) que ejecuta como CGI un script en perl que devuelve la fecha y hora actual en el formato requerido, evitando así tener que instanciar de nuevo REST, realizar otra petición y parsear la respuesta.

#!/usr/bin/perl -wT
use strict;
use warnings;

use POSIX qw(strftime);

my $date11paths;
my $dateRFC2616;

$date11paths = POSIX::strftime("%Y-%m-%d %H:%M:%S", gmtime);
$dateRFC2616 = POSIX::strftime("%a, %d %b %Y %H:%M:%S UTC", gmtime);

print "Server: SSLarrangement/0.1n";
print "Date: $dateRFC2616n";
print "Content-Length: 19n";
print "Content-type: text/plainrnrn";

print "$date11paths";

Todo este código quedará disponible en Github. Veremos ya por fin en la última entrega, cómo conectarlo todo en el mundo real.

* Latch y el Internet de las Cosas: Integración con Arduino (I)
* Latch y el Internet de las Cosas: Integración con Arduino (II)
Latch y el Internet de las Cosas: Integración con Arduino (III)
* Latch y el Internet de las Cosas: Integración con Arduino (IV)
* Latch y el Internet de las Cosas: Integración con Arduino (IV)
    

Jorge Rivera
jorge.rivera@11paths.com

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *