
Compartir:
Maria is a passionate maker currently working as IoT Developer focused on System Integration & Hardware Development. Also, she is an organizer of IoT Medellin - a tech community that brings together IoT enthusiasts to share knowledge in LATAM.
Rastrea los datos del dispositivo en tiempo real con Messages API de Vonage y Ubidots
Tiempo de lectura: 12 minutos
Considero que el Internet de las Cosas (IoT) un superhéroe: casi invisible, pero que nos mejora la vida laboral, social y personal. Los superhéroes tienen el tremendo poder de estar ahí donde los necesites, ya sea en ciudades, hospitales, instituciones educativas, plantas de fabricación, granjas o cualquier lugar que puedas tener en mente. Suena muy parecido al Internet de las Cosas, ¿no crees?
Pongámonos en la piel de Natalia. Natalia trabaja en el sector agrícola utilizando Pig Visionuna cámara inteligente que integra inteligencia artificial y redes neuronales. Con este dispositivo, ella puede obtener métricas en tiempo real sobre el proceso de pesaje en las granjas sin estresar a los cerdos. ¿Y si Natalia necesita acceder a los datos pero no tiene acceso a Internet en ese preciso momento? Aquí es donde la Mensajes API de Vonage ¿qué sucede si Natalia solicita los datos que necesita por SMS?
Hoy en día, existen muchos servicios de mensajería y plataformas de visualización que hacen que la tecnología sea más accesible para todos; no necesitamos ser ingenieros expertos para crear soluciones innovadoras. Además, estos servicios permiten desplegar soluciones completas en cuestión de horas. Tomando como referencia el caso de uso de Natalia, así como todas las necesidades basadas en datos que pueden existir en todos los sectores, pensé que sería genial disponer de un sistema capaz de realizar un seguimiento en tiempo real de los datos de los dispositivos independientemente del acceso a Internet.
En este tutorial, voy a compartir los pasos detallados para construir este sistema utilizando la Mensajes API de Vonage como servicio de mensajería y Ubidots como plataforma IoT. Como punto de partida, vamos a entender la arquitectura a implementar:
illustration of architecture
La integración de estos servicios se realiza a través de una UbiFunciónun entorno de computación sin servidor que nos permitirá recibir el mensaje enviado a nuestro número virtual a través de una petición HTTP. A continuación, somos capaces de analizarlo para identificar los dispositivos y las variables solicitadas con el fin de enviar el último valor recibido para cada variable solicitada como respuesta.
Sin duda, este sistema será útil para diferentes casos de uso. Sólo tienes que ser un poco creativo para identificar dónde puede ser útil para el proyecto en el que estás trabajando. Sin más preámbulos, ¡empecemos!
Requisitos previos
Cualquier dispositivo con acceso a Internet
Configuración de la plataforma IoT
Ubidots permite montar y lanzar rápidamente aplicaciones IoT sin tener que escribir muchas líneas de código: es sencillo pero potente. Para empezar a usarlo, sólo necesitamos una Account y cualquier dispositivo con conexión a Internet para transmitir datos a la API de Ubidots.
Configuración del dispositivo
Para este proyecto, utilicé un Pycon SiPy y PySense 1que nos permite monitorizar variables ambientales como la temperatura, la humedad, la intensidad de la luz y la presión. Sin embargo, si tienes cualquier otro hardware que soporte HTTP, MQTTo TCP/UDP como protocolo de comunicación también se puede integrar. Puede visitar el centro de ayuda de Ubidots para obtener tutoriales sobre cómo enviar y controlar datos hacia y desde la plataforma utilizando cualquier dispositivo IoT.
El equipo de Pycom está añadiendo características adicionales cada semana en sus productos, por lo que antes de empezar a desarrollar, asegúrese de que su placa está funcionando bajo la última actualización de firmware. Además, si estás usando Windows como sistema operativo, debes instalar los drivers necesarios.
*NOTA: Si es la primera vez que desarrolla con placas Pycom, le recomiendo encarecidamente que consulte la guía de inicio para familiarizarte con todos los detalles.
Instale el Pymakr, un plug-in disponible para Atom y Visual Studio Codepara ejecutar y sincronizar proyectos en cualquier placa Pycom. Pymakr también añade una consola REPL al terminal que se conecta a la placa.
A continuación, establece la comunicación entre Pymakr y tu placa vía Serial o Telnet, según prefieras. Consulta las guías de configuración basadas en tu editor de código:
Código
Este proyecto requiere un par de librerías externas que deben ser descargadas y centralizadas en un solo lugar para que funcione como debe. Si quieres descargarlas todas junto con el código principal, puedes descargar aquí.
Si quieres empezar desde cero, crea un nuevo proyecto con el nombre que prefieras. Yo decidí llamarlo **_pysense-ubidots-mqtt_**.
En el **_pysense-ubidots-mqtt_** proyecto, vamos a gestionar las librerías necesarias y a añadir el código principal. Para gestionar esto, crea una nueva carpeta llamada **_lib_**así como un nuevo archivo llamado **_main.py_**
Desde el repositorio de bibliotecas pycomdescarga las siguientes librerías y colócalas en la carpeta **_lib_** que acabamos de crear:
Después de descargar estas librerías, deberías tener la siguiente estructura en la carpeta del proyecto:
- lib
- LTR329ALS01.py
- MPL3115A2.py
- pycoproc.py
- pysense.py
- SI7006A20.py
- umqtt
- robust.py
- simple.py
- main.pyEstas librerías nos permiten comunicarnos con la placa base (en mi caso SiPy), con el PySense, y gestionar los datos con Ubidots a través de MQTT.
Copie el siguiente código en el archivo main.py archivo. Este código publica constantemente los valores de temperatura, humedad, presión y altitud a Ubidots:
#!/usr/bin/python
# Include Libraries
from umqtt.robust import MQTTClient
import machine
import time
import pycom
import json
import ubinascii
from network import WLAN
from pysense import Pysense
from LIS2HH12 import LIS2HH12
from SI7006A20 import SI7006A20
from LTR329ALS01 import LTR329ALS01
from MPL3115A2 import MPL3115A2,ALTITUDE,PRESSURE
import gc
gc.collect()
# Define network constants
wifi_ssid = "xxxx" # Set Network's SSID
wifi_password = "xxxx" # Set Network password
# Define Ubidots constants
mqtt_server = "industrial.api.ubidots.com" # 169.55.61.243
mqtt_clientID = ubinascii.hexlify(machine.unique_id(),'').decode()
mqtt_username = "BBFF-xxxx" # Set your Ubidots TOKEN
ubidots_dev_label = "weather-station" # ubinascii.hexlify(machine.unique_id(),':').decode() # Set a device labe
# Constants to manage data rate
last_message = 0
message_interval = 5
'''
Establishes connection with the MQTT server defined
'''
def connect_mqtt():
global mqtt_clientID, mqtt_server
client = MQTTClient(mqtt_clientID, mqtt_server, user=mqtt_username, password=mqtt_username)
client.connect()
print("\nConnected to {} MQTT broker".format(mqtt_server))
return client
'''
Reset the device to restore the connection with the MQTT Server
'''
def restart_and_reconnect():
print("\nFailed to connect to MQTT broker. Reconnecting...")
time.sleep(10)
machine.reset()
'''
Establish network connection
@arg ssid [Mandatory] Network SSID
@arg psw [Mandatory] Network Password
'''
def wifi_connect(ssid, psw):
attempts = 0
print("Starting attempt to connect to WiFi.", end="")
wlan.connect(ssid, auth=(WLAN.WPA2, psw), timeout=5000) # Connect to the WiFi AP provided
# Check network status
while not wlan.isconnected():
time.sleep(0.5)
print(".", end="")
attempts += 1
machine.idle() # Safe power while waiting
if attempts >= 10:
print("\nssid: {}, psw: {}".format(wifi_ssid, wifi_password))
print("\nCould not establish connection with the network provided. Please check the network crendentials or status, and try again.");
time.sleep(0.5)
attempts = 0
machine.reset()
# Network interface parameteres logs
network_settings = wlan.ifconfig()
print("\nWLAN connection succeeded!")
print("IP address: {}".format(network_settings[0]))
print("Subnet: {}".format(network_settings[1]))
print("Gateway: {}".format(network_settings[2]))
print("DNS: {}".format(network_settings[3]))
return True
'''
Reads temperature, humidity, pressure, altitude, and light sensors
@return data, JSON object with sensors readings
'''
def read_sensors():
# Barometric sensor constructor (Pressure (Pascals), Altitud (meters), Temperature (celsius ))
mpl_pressure = MPL3115A2(py, mode=PRESSURE)
mpl_altitude = MPL3115A2(py,mode=ALTITUDE)
# Humidity & Temperature sensor constructor (Humidity (relative humidity), Temperature (celsius))
si = SI7006A20(py)
# Ambient light sensor consturctor (Light levels(luxes))
ltr = LTR329ALS01(py)
# Sensors readings
pressure = mpl_pressure.pressure()
altitude = mpl_altitude.altitude()
temperature_mpl = mpl_altitude.temperature()
temperature_si = si.temperature()
relative_humidity = si.humidity()
ambient_humidty = si.humid_ambient(temperature_si)
dewpoint = si.dew_point()
light = ltr.light()
# Readings logs
print("\nMPL3115A2 | Pressure: {} Pa, Altitude: {} m, Temperature: {} ºC".format(pressure, altitude, temperature_mpl))
print("SI7006A20 | Temperature: {} ºC, Relative Humidity: {} %RH, Ambient Humidity: {} %RH, Dew point: {}".format(temperature_si, relative_humidity, ambient_humidty, dewpoint))
print("LTR329ALS01 | Light (channel Blue lux, channel Red lux): {}\n".format(light))
# JSON build
data = b'{ "pressure" : %s,"altitude" : %s, "temp_mpl" : %s, "temp_si" : %s, "rel_hum" : %s, "amb_hum" : %s, "dew_point" : %s, "lux_blue" : %s, "lux_red" : %s }' % (pressure, altitude, temperature_mpl, temperature_si, relative_humidity, ambient_humidty, dewpoint, light[0], light[1])
return data
# Network's inizalitation
wlan = WLAN(mode=WLAN.STA) # Set STA (Station Aka Client, connects to an AP) as WLAN network interface 'STA_IF' (Station aka client, connects to upstream WiFi Access points)
wlan.antenna(WLAN.EXT_ANT) # Set antenna type (INT_ANT: Internal, EXT_ANT: External)
wifi_connect(wifi_ssid, wifi_password)
# Sensors' inizalitation
py = Pysense()
# Establishes connection with the MQTT server
try:
client = connect_mqtt()
except OSError as e:
restart_and_reconnect()
# Main function
while True:
try:
# Network reconnection
if wlan.isconnected() != True:
wifi_connect(wifi_ssid, wifi_password)
# Publish sensor data every 5 seconds
if (time.time() - last_message) > message_interval:
data = read_sensors()
client.publish(b"/v1.6/devices/%s" % (ubidots_dev_label), data)
last_message = time.time()
except OSError as e:
restart_and_reconnect()
En lugar de limitarnos a copiar y pegar, también podemos ver cómo funciona el código. En primer lugar, hay que importar las bibliotecas necesarias:
from umqtt.robust import MQTTClient
import machine
import time
import pycom
import json
import ubinascii
from network import WLAN
from pysense import Pysense
from LIS2HH12 import LIS2HH12
from SI7006A20 import SI7006A20
from LTR329ALS01 import LTR329ALS01
from MPL3115A2 import MPL3115A2,ALTITUDE,PRESSURE
import gcA continuación, en las variables siguientes, asignamos las credenciales de red para establecer la conexión:
wifi_ssid = "xxxx"
wifi_password = "xxxx"Para establecer comunicación con una Account de Ubidots a través de MQTT, tenemos que definir la dirección del broker, así como del cliente, y el nombre de usuario para la autenticación de la comunicación:
Agente MQTT:
industrial.api.ubidots.como169.55.61.243.Cliente MQTTidentificador único para la comunicación cliente-servidor. Se recomienda utilizar la dirección MAC del dispositivo como identificador para el cliente, ya que es un valor único por dispositivo.
Nombre de usuario MQTT: Autentica la comunicación con el broker. En el caso de Ubidots, debemos asignar el token de cuenta como nombre de usuario.
mqtt_server = "industrial.api.ubidots.com" # 169.55.61.243
mqtt_clientID = ubinascii.hexlify(machine.unique_id(),'').decode()
mqtt_username = "BBFF-xxxx" # Set your Ubidots TOKENA continuación, asigne la etiqueta del dispositivo. Esta etiqueta es el identificador único que nos permitirá comunicarnos con Ubidots, ya sea para publicar o suscribir datos a/desde un tema. Puede ser un valor único de cadena o la dirección MAC del dispositivo. En mi caso, he asignado weather-station como etiqueta de dispositivo:
ubidots_dev_label = "weather-station"Para terminar con las declaraciones, asigne la velocidad de datos deseada como message_interval. Por defecto, la variable se establece en cinco segundos. La variable last_message guardará la última vez que se envió un mensaje.
last_message = 0
message_interval = 5Ahora, es el momento de conectar la placa a la red local. Primero, creamos un WLAN objeto de interfaz de red. Como puedes ver a continuación, el objeto se crea bajo la variable wlan y está configurado para utilizar la antena externa, ya que tengo el dispositivo desplegado un poco lejos del router. Si quieres utilizar la antena interna, sólo tienes que utilizar wlan.antenna(WLAN.INT_ANT).
wlan = WLAN(mode=WLAN.STA)
wlan.antenna(WLAN.EXT_ANT)A continuación, la función wifi_connect() establece la comunicación con la red especificada:
wifi_connect(wifi_ssid, wifi_password)Pero, ¿qué hace exactamente la función wifi_connect función? Como puedes ver a continuación, se encarga de establecer la conexión de red, y devuelve los parámetros de red sólo si la conexión se ha establecido correctamente. En caso de problema, se informará del mismo, y se reiniciará el dispositivo para reintentar la conexión.
def wifi_connect(ssid, psw):
attempts = 0
print("Starting attempt to connect to WiFi.", end="")
wlan.connect(ssid, auth=(WLAN.WPA2, psw), timeout=5000)
while not wlan.isconnected():
time.sleep(0.5)
print(".", end="")
attempts += 1
machine.idle()
if attempts >= 10:
print("\nssid: {}, psw: {}".format(wifi_ssid, wifi_password))
print("\nCould not establish connection with the network provided. Please check the network crendentials or status, and try again.");
time.sleep(0.5)
attempts = 0
machine.reset()
network_settings = wlan.ifconfig()
print("\nWLAN connection succeeded!")
print("IP address: {}".format(network_settings[0]))
print("Subnet: {}".format(network_settings[1]))
print("Gateway: {}".format(network_settings[2]))
print("DNS: {}".format(network_settings[3]))
return True
A continuación, inicialice la placa PySense como py
py = Pysense()Para evitar problemas de comunicación con el broker, la conexión se establecerá antes de entrar en el campo while. Sin embargo, en caso de cualquier problema de comunicación, la umqtt gestionará una reconexión automática. En caso de que la conexión no pueda establecerse por otro motivo, como que el broker esté caído, la placa se reiniciará para intentar establecer de nuevo la conexión.
try:
client = connect_mqtt()
except OSError as e:
restart_and_reconnect()La función connect_mqtt() abre una nueva conexión MQTT con el broker especificado:
def connect_mqtt():
global mqtt_clientID, mqtt_server
client = MQTTClient(mqtt_clientID, mqtt_server, user=mqtt_username, password=mqtt_username)
client.connect()
print("\nConnected to {} MQTT broker".format(mqtt_server))
return clientPara terminar, como puedes ver a continuación, el código principal se encarga en realidad de tres procesos.
En primer lugar, compruebe la conexión de red:
if wlan.isconnected() != True:
wifi_connect(wifi_ssid, wifi_password)Luego publica los datos de los sensores en Ubidots cada 5 segundos:
if (time.time() - last_message) > message_interval:
data = read_sensors()
client.publish(b"/v1.6/devices/%s" % (ubidots_dev_label), data)
last_message = time.time()
Aquí, la función read_sensors() se encarga de tomar las lecturas de todos los sensores y construir una carga útil JSON para enviarla a Ubidots:
def read_sensors():
mpl_pressure = MPL3115A2(py, mode=PRESSURE)
mpl_altitude = MPL3115A2(py,mode=ALTITUDE)
si = SI7006A20(py)
ltr = LTR329ALS01(py)
pressure = mpl_pressure.pressure()
altitude = mpl_altitude.altitude()
temperature_mpl = mpl_altitude.temperature()
temperature_si = si.temperature()
relative_humidity = si.humidity()
ambient_humidty = si.humid_ambient(temperature_si)
dewpoint = si.dew_point()
light = ltr.light()
print("\nMPL3115A2 | Pressure: {} Pa, Altitude: {} m, Temperature: {} ºC".format(pressure, altitude, temperature_mpl))
print("SI7006A20 | Temperature: {} ºC, Relative Humidity: {} %RH, Ambient Humidity: {} %RH, Dew point: {}".format(temperature_si, relative_humidity, ambient_humidty, dewpoint))
print("LTR329ALS01 | Light (channel Blue lux, channel Red lux): {}\n".format(light))
# JSON build
data = b'{ "pressure" : %s,"altitude" : %s, "temp_mpl" : %s, "temp_si" : %s, "rel_hum" : %s, "amb_hum" : %s, "dew_point" : %s, "lux_blue" : %s, "lux_red" : %s }' % (pressure, altitude, temperature_mpl, temperature_si, relative_humidity, ambient_humidty, dewpoint, light[0], light[1])
return dataPor último, reinicie la placa si se produce un error con el broker:
except OSError as e:
restart_and_reconnect()La función restart_and_reconnect() reinicia la placa para reconectar la conexión con el broker.
def restart_and_reconnect():
print("\nFailed to connect to MQTT broker. Reconnecting...")
time.sleep(10)
machine.reset()Una vez que tenga el código en Pymakr, puede cargar el código en el tablero pulsando el botón Subir . Espera un par de segundos hasta que el dispositivo termine su compilación.
Desde la cuenta de Ubidots, vaya a Dispositivos > Dispositivos y verás cómo se ha creado automáticamente un weather-station dispositivo se creó automáticamente una vez recibidos los datos del sensor:
Ubidots New Device
OPCIONAL Ubidots nos permite personalizar los dispositivos y variables con nombres, colores, iconos y descripciones amigables. Sólo ten en cuenta que las etiquetas de los dispositivos y variables no se pueden cambiar ya que la etiqueta es la que se encarga de la comunicación entre los dispositivos y la plataforma.
En mi caso, he personalizado la variable nombres, iconos, unidadesy colores.
Antes de la personalización:
Ubidots Generic Device
Después de la personalización:
Ubidots Custom Device
Configuración del salpicadero
Una de las cosas que más me gustan cuando trabajo con Ubidots son las atractivas visualizaciones que ofrecen. También tienen una gran variedad de widgets que te permiten personalizar completamente el aspecto que quieres que tenga tu panel de control. Los cuadros de mando son una parte muy importante de las soluciones IoT, ya que podemos acceder a todos los datos de nuestros dispositivos desde cualquier parte del mundo, pero... sólo si tenemos conexión a Internet.
Para crear un cuadro de mando, vaya a la sección Datos > Panel de control. A continuación, haga clic en _Nuevo cuadro de mando y asígnele el nombre que desee.
Para añadir nuevos widgets, basta con hacer clic en el icono azul del signo más, seleccionar el tipo de widget y establecer algunas personalizaciones de visualización. Llegados a este punto, es hora de ser creativo y empezar a explorar los diferentes widgets que ofrece Ubidots.
Este es el aspecto de mi salpicadero.
Ubidots Dashboard
Para obtener más información sobre los cuadros de mando y la configuración de los widgets, te recomiendo que consultes las siguientes guías:
Configuración de Vonage
Gracias a la Mensajes API de Vonagepodemos habilitar diferentes estrategias de mensajería de manera simple. No sólo nos permite enviar SMSsino que también permite la comunicación a través de diferentes canales como MMS, Whatsapp, Facebook Messengery Viber. Para este proyecto voy a utilizar el canal SMS, ya que quiero demostrar cómo solicitar datos cuando no se tiene acceso a Internet.
Veamos los pasos a continuación para configurar nuestra Account de Vonage:
Accede a tu Account de Vonage. Si aún no tienes una inscríbete y comienza a construir hoy.
Una vez iniciada la sesión, busque la Clave API y Secreto API de tu Account en la parte superior del Panel de API de Vonage. Estas credenciales son necesarias para establecer comunicación desde servicios externos como Ubidots. Ten en cuenta que estas credenciales siempre deben mantenerse seguras y nunca deben compartirse.
Crear una nueva aplicación. Puedes hacerlo a través del panel de control de la API de Vonage, sólo ve a nuestras aplicaciones > + Crear una nueva aplicación y asígnale un nombre, o enviando una solicitud HTTP. Para que esta guía sea fácil de usar, decidí hacerlo directamente desde el panel. Basta con hacer unos pocos clics, asignar un nombre y ¡ya está!
Para recibir mensajes entrantes, tendrá que alquilar un número virtual. El número puede alquilarse utilizando el panel del desarrollador, Nexmo CLIo la API.
Vincule el número alquilado a la solicitud creada previamente haciendo clic en el enlace enlace en la sección de números de la solicitud.
Vonage Virtual Number
Integración de Vonage y Ubidots
En la cuenta de Ubidots, vaya a la sección Dispositivo > Funciones y haga clic en el icono más situado en la parte superior derecha del sitio para crear una nueva función. Para crear la función debe asignar los siguientes parámetros:
Nombre:
Vonage Messages APIMétodo HTTP:
POSTTiempo de ejecución:
NodeJs 10
*NOTA: La UbiFunction también se puede programar en Python, pero el código proporcionado en esta guía está en NodeJS.*
Una vez configurado, pulse el botón Activar . En este punto, veremos que el campo HTTPS Endpoint URL con el punto final que recibirá los mensajes de Vonage.
En mi caso, la URL generada fue: https://parse.ubidots.com/prv/{ubidots_username}/vonage-messages-api.
A continuación, en el portal para desarrolladores de Vonage, vaya a la sección Configuración , haz clic en tu nombre de usuario y luego asigna los siguientes parámetros en la sección Configuración predeterminada de SMS predeterminada. Para finalizar, guarda los cambios.
Recibos de entrega: URL del punto final HTTPS generado +
/webhooks/delivery-receipts:
https://parse.ubidots.com/prv/{ubidots_username}/vonage-messages-api/webhooks/delivery-receipts
Mensajes entrantes: HTTPS URL de punto final generado +
/webhooks/inbound-message:
https://parse.ubidots.com/prv/{ubidots_username}/vonage-messages-api/webhooks/inbound-message
Método HTTP:
POST
Cuando se envíe un mensaje al número virtual, éste reenviará la información a este punto final.
Ahora vuelve a la UbiFunction creada, y sustituye el código por defecto por el código de abajo:
// Import the 'request-promise' library to handle HTTP requests
var request = require("request-promise");
// Ubidots constants
const UBIDOTS_TOKEN = "BBFF-xxxx";
// Vonage constants
const VONAGE_API_SECRET = "xxxxxx";
/*
* Main function - runs every time the UbiFunction is executed
*
* @arg args, dictionary containing Vonage request data
*/
async function main(args) {
// When sending SMS, delivery receipts will be returned
// status: submitted, delivered,
if (args["status"]) {
return args;
}
// Parses incoming values
var api_key = args["api-key"];
var keyword = args["keyword"];
var msisdn = args["msisdn"];
var text = args["text"];
var to = args["to"];
var msg_type = args["type"];
//var message_timestamp = args['message-timestamp'];
//var messageId = args['messageId'];
// Verify the keyword received to request the data
if (keyword == "UBIDOTS") {
text = text.toLowerCase(); // Converts the text received to lowercase letters
// Filter the requested devices
const devices = /Devices:(.*)/i.exec(text);
const deviceList = devices[1].split(",").map((device) => device.trim());
// Filter the requested variables
const variables = /Variables:(.*)/i.exec(text);
const variableList = variables[1]
.split(",")
.map((variable) => variable.trim());
// "msg" stores the response to be sent
var msg = "Data requested:\n";
// Iterates the deviceList previously filtered
for (const device of deviceList) {
msg = msg.concat("\nDevice: ", device);
// Iterates the variableList previously filtered
for (const variable of variableList) {
// Handle GET request to Ubidots
try {
var response = await ubidots_get_request(
UBIDOTS_TOKEN,
device,
variable
);
msg = msg.concat("\nVariable: ", variable, " = ", response);
} catch (error) {
// Send a reply back in case any error is presented
var vonage_response = await vonage_messages(
api_key,
msg_type,
msisdn,
to,
"The requested data cannot be found. Please verify it and try again."
);
// Pass the error message caught as the function's response
return { message: error.message };
}
}
msg = msg.concat("\n");
}
}
// Send a reply back with the requested data
/* Reply example for multiple devices and variables:
Data requested:
Device: balcony
Variable: humidity = 50.87
Variable: temperature = 36.39
Device: kitchen
Variable: humidity = 55.72
Variable: temperature = 29.45
*/
//var vonage_response = await vonage_messages(api_key, msg_type, msisdn, to, msg);
var vonage_response = await vonage_messages(
api_key,
msg_type,
msisdn,
to,
msg
);
// Pass Vonage's API Response as the function's reponse
return vonage_response;
}
/*
* Handle an HTTP POST request to Vonage Messaging API
* API Documentation: https://developer.nexmo.com/api/messages-olympus#overview
*
* @arg api_key [Mandatory], Nexmo account's API Key
* @arg msg_channel [Mandatory], type of message that you want to send.
* @arg recipient [Mandatory], phone number of the message recipient
* @arg sender [Mandatory], phone number of the message sender
* @arg msg [Mandatory], text of the message
*
* @return message_uuid, UUID of the message
*/
async function vonage_messages(api_key, msg_type, recipient, sender, msg) {
// Base64 encoded API key and secret joined by a colon
var auth =
"Basic " +
Buffer.from(api_key + ":" + VONAGE_API_SECRET).toString("base64");
var options = {
method: "POST",
url: "https://api.nexmo.com/v0.1/messages",
headers: {
Authorization: auth,
"Content-Type": "application/json",
Accept: "application/json",
},
json: {
from: {
type: "sms",
number: sender,
},
to: {
type: "sms",
number: recipient,
},
message: {
content: {
type: msg_type,
text: msg,
},
},
},
};
// Pass UUID of the message sent
return await request.post(options);
}
/*
* Handle an GET request to Ubidots API
* API Documentation: https://ubidots.com/docs/sw/
*
* @arg token [Mandatory], Ubidots account's Token
* @arg device_label [Mandatory], single and unique label of device
* @arg variable_label [Mandatory], single and unique label of variable
*
* @return last_value, variable last value
*/
async function ubidots_get_request(token, device_label, variable_label) {
var options = {
method: "GET",
url:
"https://industrial.api.ubidots.com/api/v1.6/devices/" +
device_label +
"/" +
variable_label +
"/lv",
json: true,
headers: {
"Content-Type": "application/json",
"X-Auth-Token": token,
},
};
var last_value = await request.get(options);
return last_value;
}
/*
* Handle an POST request to Ubidots API
* API Documentation: https://ubidots.com/docs/sw/
*
* @arg token [Mandatory], Ubidots account's Token
* @arg device_label [Mandatory], single and unique label of device
* @arg variable_label [Mandatory], single and unique label of variable
*
* @return last_value, variable last value
*/
async function ubidots_post_request(token, label, body) {
var options = {
method: "POST",
url: "https://industrial.api.ubidots.com/api/v1.6/devices/" + label,
body: body,
json: true,
headers: {
"Content-Type": "application/json",
"X-Auth-Token": token,
},
};
var response = await request.post(options);
return response;
}
Entonces, debemos sustituir la UBIDOTS_TOKEN por el Ubidots TOKENy el VONAGE_API_SECRET por el Secreto de la API de Vonage para permitir la comunicación entre la UbiFunction y ambos servicios.
// Ubidots constants
const UBIDOTS_TOKEN = "BBFF-xxxx";
// Vonage constants
const VONAGE_API_SECRET = "xxxxxx";No olvides pulsar el botón Activar para guardar los cambios realizados.
El código proporcionado está comentado en detalle para cada uno de sus procesos y funciones, por lo que entenderlo no debería ser demasiado difícil. Sin embargo, vamos a destacar cómo funciona:
El código principal de UbiFunction se encarga de recibir la carga útil enviada por Vonage cuando se envía un nuevo SMS o cuando se informa otro estado de SMS.
A continuación, se analizan los SMS recibidos para identificar la clave API, la palabra clave, el SMS recibido y el remitente.
Si la palabra clave recibida es igual a Ubidots, se filtrará el texto recibido para crear una lista de los dispositivos y variables a solicitar.
Las listas creadas se iteran para solicitar el último valor de cada una de las variables a Ubidots.
Los datos solicitados se concatenan en una cadena, que se envía como respuesta al remitente una vez que todos los datos se han solicitado correctamente.
Para que la solicitud de datos se realice satisfactoriamente a través de SMS, debemos utilizar las siguientes plantillas:
Para un solo dispositivo:
Solicitud de SMS:
Ubidots request data
Devices: {device_label}
Variables: {variable_label_1}, {variable_label_2}, {variable_label_n}Respuesta SMS:
Data requested:
Device: {device_label}
Variable: {variable_label_1} = 23
Variable: {variable_label_2} = 246
Variable: {variable_label_n} = 85Para varios dispositivos:
Solicitud de SMS:
Ubidots request data
Devices: {device_label_1}, {device_label_2}, {device_label_n}
Variables: {variable_label_1}, {variable_label_2}, {variable_label_n}Respuesta SMS:
Data requested:
Device: {device_label_1}
Variable: {variable_label_1} = 23
Variable: {variable_label_2} = 246
Variable: {variable_label_n} = 85
Device: {device_label_2}
Variable: {variable_label_1} = 23
Variable: {variable_label_2} = 246
Variable: {variable_label_n} = 85
Device: {device_label_n}
Variable: {variable_label_1} = 23
Variable: {variable_label_2} = 246
Variable: {variable_label_n} = 85*NOTA IMPORTANTE: Las solicitudes de dispositivos múltiples sólo se admitirán para dispositivos que contengan las mismas variables.*
Para comprobar que todo funciona como debe, enviemos dos mensajes al número alquilado, uno con el dispositivo creado (weather-station), y otro con un dispositivo que no existe para diferenciar las respuestas:
Petición #1:
Ubidots request data
Devices: weather-station
Variables: dew_point, lux_blue, amb_hum, temp_mplSolicitud #2:
Ubidots request data
Devices: ws
Variables: dew_point, lux_blue, amb_hum, temp_mplLas respuestas recibidas fueron:
Satisfactory reply
Device not found
Como era de esperar, ¡funciona correctamente! Ahora si comparamos los valores recibidos con los valores de nuestro dashboard podemos ver que son los mismos:
Ubidots Final Dashboard
Conclusión y próximos pasos
Cuando hablamos del Internet de las Cosas, lo primero que nos viene a la cabeza es "Internet", pero la realidad es que existen otras alternativas que nos permiten tener acceso a esos datos aunque no tengamos acceso a Internet en algún momento.
En esta guía, hemos cubierto todo lo que necesitas saber para comunicarte con la Messages API de Vonage y Ubidots para solicitar datos a través de un SMS. Sin embargo, puedes ampliar este desarrollo y personalizarlo para cualquier aplicación de IoT que puedas tener en mente, ya sea una aplicación de control de luces para el hogar, redes comunitarias para sensores, chatbot personalizado y mucho más.
Además, puedes explorar los otros canales que ofrece la Mensajes API de Vonagey estoy seguro de que con él, podrás comenzar a trabajar en tu próximo superhéroe :)