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

lunes, 26 de octubre de 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+="GET\n"
date=`date -u '+%Y-%m-%d %H:%M:%S'`
requestSignature+="$date\n\n$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: GET\n2015-08-31 13:55:54\n\n/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:value1\r\nHeader2:value2\r\n");

// 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



#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);




# 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.1\n";
print "Date: $dateRFC2616\n";
print "Content-Length: 19\n";
print "Content-type: text/plain\r\n\r\n";

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

No hay comentarios:

Publicar un comentario en la entrada