Sistema Domótico Inteligente: Raspberry Pi y MediaTek Linkit de Bajo Coste
Componentes y Suministros
| Componente | Cantidad | Notas |
|---|---|---|
| Raspberry Pi 2 Model B | 1 | Orange PI también serviría |
| Xbee | 1 | |
| Arduino UNO | 1 |
Aplicaciones y Servicios Online
- Microsoft Azure
Sobre este Proyecto
Introducción
Veamos qué necesitamos para configurar un sistema domótico inteligente usando MediaTek Linkit. Como hay muchos expertos aquí para guiarte en la conexión de hardware para leer datos de sensores, me concentraré en crear APIs y configurar un servidor local de ultra bajo coste ($15) para capturar todos tus datos de sensores. Opcionalmente, registro los datos en Azure.
Configuración
Los sensores transmiten sus datos mediante señales de radio usando Xbee o cualquier transceptor de bajo coste al MediaTek LinkIt. El MediaTek LinkIt recibe todos los datos brutos de los sensores, los empaqueta en objetos JSON usando la librería ArduinoJson y hace una petición POST al servidor local. El servidor local aloja una aplicación web Node.js y recibe todos los datos de los sensores como objetos JSON.
El servidor local se usa como preprocesador y añade la hora UTC y la firma. Cualquier validación, conversión y filtrado de datos puede procesarse aquí. El servidor local registra todos los datos en el servicio en la nube, en nuestro caso Azure Storage Services. Alternativamente, MediaTek LinkIt puede publicar directamente los objetos JSON en Azure Storage Services. Configuré un servidor local solo para demostrar que un PC de $15 puede ser lo suficientemente potente para manejar nuestros datos. Podemos registrar nuestros datos en cualquier base de datos NoSQL incluso en nuestro servidor local, eliminando completamente la necesidad de almacenamiento en la nube externo. Dejo todo esto a vuestra elección.
Demo
Requisitos Previos
Asumo que sabes cómo leer datos de sensores usando sensores y microcontroladores como Arduino o MediaTek. Para limitar el alcance de este proyecto, voy a asumir que los datos de los sensores están disponibles para MediaTek LinkIt. Puedes usar transceptores de radio de bajo coste o Xbee para transmitir y recibir señales de radio de sensores conectados a microcontroladores como MediaTek. Los principiantes pueden usar el kit de inicio MediaTek LinkIt Grove para leer datos del entorno externo como temperatura, humedad, luz, etc.
JSON JSON JSON
JSON se ha convertido en el estándar de facto para IoT y ha sido ampliamente adoptado. Dicho esto sobre los requisitos previos, comencemos modelando nuestros datos de sensores. El propósito principal es capturar la mayor cantidad de datos posible y pasarlos al servidor. El servidor puede hacer todo el trabajo pesado como analítica, conversión de datos, machine learning, etc.
El objeto JSON 'desired' será el estado deseado de los datos del sensor. Por ejemplo, cuando registramos la temperatura, el valor deseado de 24 significa que necesitamos sincronizar el valor en la nube con el valor de 24. Nuestros clientes como app web o app móvil se actualizarán a este valor.
Cuando queremos encender una luz decimos, el estado deseado como "on". Significa que la luz está encendida o será encendida. Todas nuestras aplicaciones cliente usarán este estado para reflejar los cambios al usuario. Quiero decir, el icono en nuestra app web se encenderá o apagará.
Esto no es un estándar internacional, solo se me ocurrió. Así que siéntete libre de usar tu propio formato conveniente.
Ejemplos de Objetos JSON
Temperatura
{
"deviceid" : "iot/myhome/livingroom/thermostat",
"desired" : {
"temperature" : "24",
"humidity": "80"
},
"timeutc": "2015-11-23T00:41:48.824Z",
"singedBy" : "localserver"
}
Micrófono
{
"deviceid" : "iot/myhome/livingroom/mic",
"desired" : {"intensity" : "66"},
"timeutc": "2015-11-23T00:41:48.824Z",
"singedBy" : "localserver"
}
Distancia
{
"deviceid" : "iot/myhome/livingroom/obstacle",
"desired" : {"proximity" : "150"},
"timeutc": "2015-01-01",
"singedBy" : "localserver"
}
PIR (Movimiento)
{
"deviceid" : "iot/myhome/livingroom/pir",
"desired" : {"motion start" : "2500", "motion end" : "5345"},
"timeutc": "2015-11-23T00:41:48.824Z",
"singedBy" : "localserver"
}
GPS
{
"deviceid" : "iot/mydevice/location",
"desired" : {"lat" : "25.5", "long" : "32.2"},
"timeutc": "2015-11-23T00:41:48.824Z",
"singedBy" : "localserver"
}
Humedad del Suelo
{
"deviceid" : "/iot/myhome/garden/moisture",
"desired" : {"moisture": "20"},
"timeutc": "2015-11-23T00:41:48.824Z",
"singedBy" : "localserver"
}
Gas
{
"deviceid" : "/iot/myhome/kitchen/gas",
"desired" : {"leak": "No"},
"timeutc": "2015-11-23T00:41:48.824Z",
"singedBy" : "localserver"
}
Luz
{
"deviceid" : "/iot/myhome/livingroom/light",
"desired" : {"intensity": "60"},
"timeutc": "2015-11-23T00:41:48.824Z",
"singedBy" : "localserver"
}
Salón (Múltiples Sensores)
{
"deviceid" : "/iot/myhome/livingroom",
"desired" : {
"temperature" : "25",
"humidity" : "80",
"window": "open",
"door": "closed",
"light": "80",
"noise": "low"
}
}
Dormitorio (Múltiples Sensores)
{
"deviceid" : "/iot/myhome/bedroom",
"desired" : {
"temperature" : "24",
"humidity" : "70",
"window": "closed",
"door": "closed",
"light": "80",
"ac": "on",
"noise": "low"
}
}
MediaTek - Receptor
Por favor, consulta el archivo .ino adjunto en la sección de software para registrar los datos en el servidor local. Los datos de los sensores están simulados; puedes pasar las lecturas reales al objeto JSON respectivo.
Servidor Local
El servidor local añade una sobrecarga pero será muy útil de muchas maneras. Podemos hacer uso del servidor local como preprocesador para nuestros datos IoT. Los datos pueden ser filtrados, marcados con timestamp y firmados.
Un PC pequeño y Node.js es una excelente opción para servidor local. Podemos elegir cualquier PC pequeño como Raspberry Pi, Odroid, Banana Pi, BeagleBone, etc. He elegido Orange Pi ($15) para este proyecto.
Configuración
Raspberry Pi 2 u Orange Pi con cualquier sabor de Linux OS que soporte Node.js 5. He elegido Orange Pi con Arch Linux para ARM7. Instalé Node.js y npm. Descargué mi iotapp desde GitHub y navegué a /tu/ruta/local/iotapp y ejecuté npm install. La aplicación Express.js básica comienza a escuchar en tu puerto 3000.
Navega a tu-ip-local:3000 para comprobar si la vista por defecto de Express.js se renderiza. He creado estas APIs para recibir los datos de los sensores:
- /iot/myhome/livingroom/thermostat - API Temperatura
- /iot/myhome/livingroom/mic - API Sonido
- /iot/myhome/livingroom/pir - API Sensor de presencia
- /iot/myhome/livingroom/distance - API Sensor de distancia
- /iot/myhome/mydevice/location - API Rastreador GPS
- /iot/myhome/garden/moisture - API Sensor humedad suelo
- /iot/myhome/kitchen/gas - API Sensor fuga gas
- /iot/myhome/livingroom/light - API Sensor luz
- /iot/myhome/livingroom - Otra API para salón
- /iot/myhome/bedroom - Otra API para dormitorio
Para configurar el servidor local: Clona el código fuente iotapp desde mi GitHub. Modifica index.js para poner tu dirección IP o nombre de dominio en la nube donde la aplicación ASP.NET 5 está alojada en Azure.
Servidor Remoto (Nube)
Publicar datos en la nube se ha vuelto popular hoy en día. Podemos comprar suscripción de proveedores de datos IoT como Amazon, Azure, SparkFun, PubNub, Initial State y muchos otros. He elegido Azure para esta demo. Algoritmos de analítica de datos, minería de datos y machine learning pueden desarrollarse para procesar nuestros datos.
Descarga la iotwebapp desde mi GitHub. La creé usando Visual Studio 2015 apuntando a ASP.NET 5. Estas APIs se configuraron para recibir los datos IoT. La API registra los datos IoT en tablas de Azure Storage.
El parámetro deviceid puede establecerse para identificar la ubicación del sensor.
Estas APIs se han configurado:
- api/iot/myhome/thermostat - API ASP.NET 5 para registrar todos los datos del termostato
- api/iot/myhome/microphone - API ASP.NET 5 para registrar todos los datos del micrófono
- api/iot/myhome/pir - API ASP.NET 5 para registrar todos los datos PIR
- api/iot/myhome/distance - API ASP.NET 5 para registrar todos los datos del sensor de distancia
- api/iot/myhome/device/location - API ASP.NET 5 para registrar datos GPS
- api/iot/myhome/moisture - API ASP.NET 5 para registrar datos del sensor de humedad
- api/iot/myhome/gas - API ASP.NET 5 para registrar datos del sensor de gas
- api/iot/myhome/light - API ASP.NET 5 para registrar todos los datos del sensor de luz
- api/iot/myhome/livingroom - API ASP.NET 5 para registrar todos los atributos/datos de sensores del salón. Podemos usar esta única API para enviar todos los valores de sensores.
- api/iot/myhome/bedroom - Lo mismo que arriba, he creado una para registrar los detalles de mi dormitorio
Para configurar el servidor remoto: Clona el código fuente iotwebapp desde mi GitHub. Crea una tabla de Azure Storage. Modifica IoTController.cs y pon tu nombre de cuenta y clave de tabla de Azure Storage. Usa este nombre de dominio o IP en el servidor local.
Conclusión
Hay muchas áreas para refactorizar en el código. Siéntete libre de modificar y avísame si te atascas.
Código
MediaTekRx (C/C++)
MediaTek como receptor. Sketch para enviar datos al servidor local.
/* Web client
Este sketch se conecta a un sitio web usando funcionalidad Wi-Fi en plataforma MediaTek LinkIt.
Cambia las macros WIFI_AP, WIFI_PASSWORD, WIFI_AUTH y SITE_URL según corresponda.
created 13 July 2010 by dlf (Metodo2 srl)
modified 31 May 2012 by Tom Igoe
modified 20 Aug 2014 by MediaTek Inc.
*/
#include <LTask.h>
#include <LWiFi.h>
#include <LWiFiClient.h>
#include <ArduinoJson.h>
#define WIFI_AP "your ap"
#define WIFI_PASSWORD "your password"
#define WIFI_AUTH LWIFI_WPA // elegir entre LWIFI_OPEN, LWIFI_WPA, o LWIFI_WEP.
#define SITE_URL "your ip" // tu dirección IP o nombre de dominio Node.js o Azure
LWiFiClient c;
void setup() {
LWiFi.begin();
Serial.begin(115200);
// seguir reintentando hasta conectar al AP
Serial.println("Connecting to AP");
while (0 == LWiFi.connect(WIFI_AP, LWiFiLoginInfo(WIFI_AUTH, WIFI_PASSWORD))) {
delay(1000);
}
// seguir reintentando hasta conectar al sitio web
Serial.println("Connecting to WebSite");
while (0 == c.connect(SITE_URL, 3000)) {
Serial.println("Re-Connecting to WebSite");
delay(1000);
}
}
boolean disconnectedMsg = false;
void loop() {
// Asegurarse de que estamos conectados, y volcar el contenido de la respuesta a Serial
while (!c) {
Serial.println(" Server disconnected..");
// seguir reintentando hasta conectar al sitio web
Serial.println("Connecting to WebSite");
while (0 == c.connect(SITE_URL, 3000)) {
Serial.println("Re-Connecting to WebSite");
delay(1000);
}
}
Serial.println(" Reading temperature..");
updateTemperature();
delay(3000);
Serial.println("Detecting sound..");
updateSound();
delay(3000);
Serial.println("Detecting person movement..");
updatePIR();
delay(3000);
Serial.println("Detecting obstacle..");
updateDistance();
delay(3000);
Serial.println("Updating device location..");
updateGPSTracker();
delay(3000);
Serial.println("Calculating soil moisture..");
updateMoisture();
delay(3000);
Serial.println("Detecting gas leakage..");
updateGasLeak();
delay(3000);
Serial.println("Recording light intensity..");
updateLightIntensity();
delay(3000);
updateLivingroomAttributes();
delay(3000);
updateBedroomAttributes();
delay(3000);
}
void writeToConsole() {
// Asegurarse de que estamos conectados, y volcar el contenido de la respuesta a Serial
while (c) {
int v = c.read();
if (v != -1) {
Serial.print((char)v);
}
}
Serial.println();
Serial.println(" Server disconnected..");
// seguir reintentando hasta conectar al sitio web
Serial.println("Connecting to WebSite");
while (0 == c.connect(SITE_URL, 3000)) {
Serial.println("Re-Connecting to WebSite");
delay(1000);
}
}
// ... (funciones updatePIR, updateDistance, updateGPSTracker, updateMoisture,
// updateGasLeak, updateLightIntensity, updateLivingroomAttributes,
// updateBedroomAttributes, updateSound, updateTemperature)
// Todas siguen el mismo patrón: crear JSON, hacer POST HTTP, esperar respuesta
nodejs - Servidor Local (JavaScript)
El index.js que tiene las rutas para recibir datos de MediaTek.
var express = require('express');
var router = express.Router();
var buf = require('buffer');
var request = require("request");
// Reemplaza your-ip-or-domain-name con tu dirección IP o nombre de dominio real
// ejemplo iot.azurewebsites.com
// ejemplo tudominio.com
// ejemplo 47.12.67.16
// Aceptar POST en la página de inicio
router.post('/iot/myhome/livingroom/thermostat', function (req, res) {
var state = req.body;
state.timeutc = new Date();
state.signedby = "orangepi";
console.log(state);
var options = {
method: 'POST',
url: 'https://your-ip-or-domain-name/api/iot/myhome/livingroom/thermostat',
headers: {
'cache-control': 'no-cache',
'content-type': 'application/json'
},
body: state,
json: true
};
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
res.send('Living room temperature recorded');
});
// ... (rutas similares para mic, pir, distance, gps, moisture, gas, light, livingroom, bedroom)
Controladores ASP.NET 5 (C#) para Azure
Ejemplos de controladores para registrar datos en Azure Table Storage:
ThermoStatController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc;
using Newtonsoft.Json;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Auth;
using Microsoft.WindowsAzure.Storage.Table;
namespace iotwebapp.Controllers {
[Route("api/iot/myhome/livingroom/[Controller]")]
public class ThermoStatController : IoTController {
[HttpPost]
public IActionResult Post([FromBody]IotTemperature iotTemperature) {
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
CloudTable table = tableClient.GetTableReference("iot");
iotTemperature.PartitionKey = "thermostat";
iotTemperature.RowKey = Guid.NewGuid().ToString();
TableOperation insertOperation = TableOperation.Insert(iotTemperature);
table.Execute(insertOperation);
return Ok("Temperature data logged to azure cloud..");
}
}
public class IotTemperature : TableEntity {
public string deviceid { get; set; }
public string timeutc { get; set; }
public string signedby { get; set; }
public string state { get { return JsonConvert.SerializeObject(this.desired); } set {; } }
public Desired desired { get; set; }
public class Desired {
public string temperature { get; set; }
public string humidity { get; set; }
}
}
}
Otros controladores siguen el mismo patrón: PIRController, MoistureController, LivingRoomController, LightController, GPSController, GasController, DistanceController, BedRoomController.
Enlace al Código Fuente Completo
Código fuente para Node.js app, ASP.NET 5 y MediaTek receptor ino: https://github.com/syediddi/iot-mediatek-linkIt
Esquemáticos
Proceso de manufactura
- Construya un Controlador Domótico 433 MHz con Sensorflare y Raspberry Pi
- Construye sistema domótico con Raspberry Pi para control remoto
- Barman Inteligente: Construye tu Propia Estación de Cócteles con Raspberry Pi
- Las mejores mejoras para el hogar inteligente que modernizan tu espacio vital
- Datos inteligentes: Navegando la próxima frontera de IoT y Big Data
- Hospitales Inteligentes del Mañana: El Papel Crítico del Software Inteligente
- Cerrando la Brecha de Habilidades en Hogar Inteligente: Por Qué Reino Unido Rezaga en Europa
- Cómo la Interconectividad Impulsa Eficiencia, Seguridad y Sostenibilidad en Lugares de Trabajo Modernos
- Evolución del Hogar Inteligente: Qué Nos Depara el Futuro de la Vida Conectada
- Fábricas inteligentes: De la visión a la realidad — Por qué la mayoría de empresas UK aún fallan el objetivo
- Conectividad para hogares inteligentes: 3 pasos probados para superar obstáculos clave