Smart Cube: Centro de Control Doméstico de Nueva Generación
Componentes y suministros
| Arduino 101 | × | 1 |
| LED (genérico) | × | 5 |
| Resistencia 221 ohm | × | 5 |
| Protoboard (genérica) | × | 1 |
| Seeed Base Shield V2 | × | 1 |
| Seeed Grove LCD RGB Backlight | × | 1 |
| Seeed Grove Sound Sensor | td>×1 | |
| Seeed Grove Buzzer | × | 1 |
| Seeed Grove Temperature Sensor | × | 1 |
| Teclado matricial (Keypad) | × | 1 |
| Cables jumpers (genéricos) | × | 1 |
| Batería 9V (genérica) | × | 1 |
| Conector batería 9V | × | 1 |
| Fibra de densidad media (MDF) 20x30 cm, 3mm | × | 1 |
Herramientas y máquinas necesarias
- Cortadora láser (genérica)
- Soldador (genérico)
Aplicaciones y servicios en línea
- Arduino IDE
- Nordic Semiconductor nRF Connect SDK (opcional)
Sobre el proyecto
¿Qué es SMART CUBE?
Smart Cube es un controlador para tus dispositivos de hogar inteligente.
Hoy en día, gestionar de forma más inteligente todos los dispositivos de nuestro hogar se está volviendo una exigencia. Necesitamos algo simple e intuitivo de usar. Smart Cube podría ser una solución: es un dispositivo portátil que contiene una placa Arduino 101 y algunos sensores que se comunican con los electrodomésticos y actuadores de tu hogar inteligente.
La innovación de este mando a distancia está relacionada con la innovación de la placa Arduino 101. Utiliza Bluetooth (BLE) para controlar luces, temperatura y tu TV, y también puedes sincronizarlo con tu smartphone. Pero la mayor innovación es la forma en que interactúas con Smart Cube mediante gestos usando el giroscopio y el acelerómetro. El cubo tiene 6 caras y cada una controla una función particular. La función que quieres usar se detecta gracias al giroscopio que reconoce la cara superior. Por ejemplo, puedes encender las luces de la habitación en la que estás simplemente colocando el cubo con la "cara de luces" en la posición superior. Si quieres apagar la luz, solo necesitas agitar el cubo.
Si una cara está ARRIBA y no se mueve durante más de 2 segundos, se activa la función relacionada. Este retraso se hace para que tengas tiempo de rotar e interactuar con el cubo para encontrar la cara que necesitas sin activar accidentalmente otras funciones. Cuando agitas el cubo durante más de 2 segundos, la última función activada se cierra.
Este proyecto pretende ayudarte a construir un controlador inteligente. Este dispositivo necesita un receptor (centralita inteligente en la imagen) que interprete los datos y gestione las funciones de tu hogar inteligente. La principal salida del cubo es una señal BLE que puede usarse de muchas formas: por ejemplo, puedes conectar el cubo con una app de smartphone (o crear la tuya propia), o puedes construir una estación con otro Arduino que recoja los datos BLE y controle directamente los electrodomésticos de tu casa. Debido a la variedad de casos, esta parte depende de tus necesidades. En esta guía veremos cómo construir un Smart Cube y aprenderás a personalizarlo.

Funciones:
La estructura del código es fácil de personalizar (analizamos el código más adelante) para que decidas qué funciones controlar. Estas son las funciones que decidí controlar:

LUZES: Esta cara en posición ARRIBA enciende las luces de la habitación en la que estás. Si agitas el cubo, las luces se apagan y un LED amarillo en esta cara se enciende para que puedas encontrar el cubo en la oscuridad. La comunicación con tus lámparas se hace por el BLE de la placa 101.
TEMPERATURA: Esta cara ARRIBA activa (vía BLE) el aire acondicionado si hace calor o la calefacción si hace frío. Detecta la temperatura usando un sensor térmico y enciende un LED azul si el aire acondicionado está activo (copito de nieve) o uno rojo si la calefacción está activa (sol).
TEMPORIZADOR: Esta cara ARRIBA inicia un temporizador que ves en la pantalla LCD. Hay un buzzer que funciona como alarma cuando termina la cuenta regresiva. Si agitas, detienes el temporizador y ves el tiempo restante. Cuando termina la cuenta regresiva, el color del LCD cambia de azul a rojo y el buzzer suena tres veces.
TV: Esta cara ARRIBA enciende la TV. El cubo se convierte en un mando a distancia para tu TV. Hay un panel de botones con números que se activa solo si esta cara está ARRIBA para evitar toques accidentales. El número que pulsas se envía vía BLE a la centralita que está conectada a tu TV. Agitando el cubo apagas la TV.
SONIDO: Esta cara ARRIBA activa un LED cuyo brillo se basa en el nivel de ruido de la habitación. El ruido se detecta gracias a un sensor de sonido. Si agitas el cubo, cierras esta función. (Si quieres, puedes activar tu función personal aplaudiendo).
Cara OFF: Si no agitas el cubo, esta cara es como una posición neutra en la que no cambia nada. Si quieres cerrar todo, coloca el cubo con la cara OFF ARRIBA y agítalo. Este gesto es como el botón de inicio en tu smartphone que pulsas si quieres salir rápido. Hay un LED rojo para que puedas encontrar el cubo si está oscuro.
Diferencias con el concepto original:
El plan original era usar también comunicación IR para conectar tu TV directamente al cubo. Como el Arduino 101 no soporta (por ahora) la librería que gestiona las señales IR, decidí enviar la información vía BLE a una estación que pueda gestionar esta librería (como Arduino UNO). Por este problema eliminé la función de radio (muy similar a la cara TV), reemplazándola por una cara con sensor de sonido. Esta cara podría usarse para reconocer un ruido fuerte (como aplausos) y activar algo. El mayor cambio está en el material del cubo. Inicialmente pensé en construirlo con una impresora 3D pero luego decidí usar una cortadora láser. Así es más fácil sustituir una cara si quieres cambiar una función. Por ejemplo, puedes quitar la cara del temporizador y cambiarla por una que llene automáticamente el cuenco de tu gato. Al ser modular, no necesitas reconstruir toda la estructura.

¡Construyámoslo!
Sigue estas instrucciones para construir tu propio Smart Cube. Empezaremos por el hardware, ensamblando primero los componentes electrónicos y luego la caja del cubo cortada con láser en MDF. Después explicaré cómo funciona el código y cómo personalizarlo. Tras subir el código a tu Arduino 101, puedes descargar la app para ver la salida BLE del cubo o conectarlo directamente con tu hogar inteligente.

Hardware - Electrónica:
Empecemos por tu Arduino 101. Este es el esquema Fritzing a seguir:

Monta el Grove Base Shield en tu placa y empieza con las conexiones.

Keypad: debes conectar los cables en orden a los pines: 10, 8, 7, 6, 5, 4, 2.

Conexiones LED:
Primero preparamos los LEDs:
- Conecta la pata larga del LED (ánodo) a una resistencia de 220 ohm y luego a un cable rojo (este es el cable para conectar al pin)
- Conecta la pata corta (cátodo) a un cable blanco (este irá a GND)
- Suellda las partes y cúbrelas con cinta aislante
- Conecta todos los cables blancos a un solo cable blanco (este irá a GND) y suelda todos juntos
Ahora conecta los cables rojos a tu Arduino: LED VERDE al pin 9, LED AMARILLO al pin 11, LED ROJO al pin 12, LED AZUL al pin 13 y el último ROJO al pin A2.

Sensores Grove:
Conecta los sensores Grove al shield (ver esquema en adjuntos).
Buzzer a D3, LCD RGB a I2C, Sensor temperatura a A0, Sensor sonido a A1.

Bien, ahora tenemos conectadas todas las partes eléctricas. Ahora necesitas la caja.
Hardware - Caja
Puedes descargar el esquema del cubo para cortar con láser. Las líneas rojas en el esquema son los símbolos de las caras, solo graba (grabado). Las líneas negras deben cortarse. La dimensión interna del cubo es 9 cm. El esquema sirve si usas material de 3mm, si usas otro grosor debes modificarlo (puedes usar esta web: https://www.makercase.com/).
El material que elijo es MDF (Fibra de Densidad Media) pero puedes usar lo que quieras.
Aquí algunas fotos del corte láser:

Ahora hay que ensamblarlo.
Pegué algunos trozos de cartón para dar grosor a los LEDs. Así quedarán alineados con la superficie.

Montamos el keypad. Insértalo en el agujero, quita la película adhesiva y vuelve a conectar los pines.

Ahora el LCD RGB. Encaja perfectamente en el agujero.

Preparamos el conector de batería:
Corté un enchufe de transformador viejo y lo conecté a un conector de batería. Así ahorramos espacio dentro de la caja.

En este punto esto es lo que deberías tener:

Ahora solo necesitas conectar la batería, subir el código y cerrar el cubo!
CONSEJO: fija la placa y la batería a la caja para que al agitar el cubo permanezcan estables.

Código
Puedes encontrar el código en los adjuntos. Súbelo a tu placa con el Arduino IDE (recuerda actualizar tu software para compatibilidad con Arduino 101).
He comentado casi cada línea del código para hacerlo lo más comprensible posible. No te asustes por las 500+ líneas, la estructura no es tan complicada.
Al principio están las librerías y la declaración de todas las variables.
En esta parte también está la definición de servicios y características BLE. Usé el servicio Automation IO. Usé la característica Digital para luces y temperatura (usa 2 bits, así que 4 casos posibles para codificar) y la Analog para TV (para enviar todos los códigos del keypad).
Luego el setup. Esta parte se ejecuta una sola vez al principio. Aquí inicializamos los componentes como entradas o salidas e inicializamos el BLE y el giroscopio de la placa 101.
La parte principal es el loop. Está dividido en cuatro partes:
- 1 La primera parte copiada del tutorial de Arduino: (https://www.arduino.cc/en/Tutorial/Genuino101CurieIMUAccelerometerOrientation) esta parte se ejecuta constantemente y devuelve la orientación de la placa.
- 2 La segunda parte activa una cara solo si está en posición superior durante más de dos segundos. Usamos la función millis para contar el tiempo. Cuando la posición cambia, memoriza el valor de millis y si la orientación permanece igual, tras un intervalo (2 seg), entramos en una zona if donde la cara seleccionada se vuelve true (para la 4ª parte).
- 3 La tercera parte se activa solo si el cubo se agita con cierta intensidad y durante más de 2 segundos. La última cara activada se cierra y la cara se pone como false. Si la cara es false no puede entrar en la 4ª parte.
- 4 La cuarta parte es solo para caras true. Aquí está el núcleo de las funciones del Smart Cube. En esta parte se ejecutan constantemente solo las caras que son true en el loop.
Puedes modificar las funciones de las caras con algunos cambios en el código. La estructura principal debe ser como se describe. Puedes cambiar la parte dentro de las condiciones if de cada cara.
if (face2 == true) { // cara TEMPERATURA
// EMPEZAR CAMBIOS AQUÍ
digitalWrite (LEDOFF, LOW); // si esta cara es true, el LED OFF está LOW
if (central.connected() == true) { // si el cubo está conectado por BLE
// leer valor temperatura
int val = analogRead(pinTemp); // obtener valor analógico
resistance=(float)(1023-val)*10000/val; // obtener resistencia
temperature=1/(log(resistance/10000)/B+1/298.15)-273.15; // calcular temperatura
// condiciones de activación
if (temperature > tooHot) { // activar aire acondicionado
digitalWrite(LEDhot, LOW); // apagar LED calefacción
digitalWrite(LEDcold, HIGH); // encender LED aire acondicionado
termoChar.setValue(1); // establecer vía BLE condición 1 = frío on - calor off
}
if (temperature < tooCold) { // activar calefacción
digitalWrite(LEDhot, HIGH);
digitalWrite(LEDcold, LOW);
termoChar.setValue(2); // 2 = frío off - calor on
}
if (temperature > tooCold && temperature < tooHot) { // temperatura ideal: nada activado
digitalWrite(LEDhot, LOW);
digitalWrite(LEDcold, LOW);
termoChar.setValue(0); // 0 = frío off - calor off
}
}
// TERMINAR AQUÍ
}
También debes programar la parte "false" cuando se agita el cubo:
// Desactivación TEMPERATURA
if (lastFUNCTION == 2) { // cara TEMPERATURA
// EMPEZAR CAMBIOS AQUÍ
// si hay una central conectada al periférico:
if (central.connected() == true) {
digitalWrite(LEDhot, LOW); // apagar LED rojo temperatura
digitalWrite(LEDcold, LOW); // apagar LED azul temperatura
termoChar.setValue(0); // señal BLE temperatura: 0 = frío off - calor off
// TERMINAR AQUÍ
}
Serial.println("TEMPERATURE false - CLOSE");
face2 = false; // cara TEMPERATURA se vuelve false
}
Recuerda poner la cara como false cuando la agitas.
App:
Para ver las salidas BLE del cubo puedes descargar esta app: nRF Connect
https://play.google.com/store/apps/details?id=no.nordicsemi.android.mcp&hl=it
Al abrirla, solo busca dispositivos y conecta con "smartcubesketch". Luego verás tres pestañas "Automation IO", haz clic en ellas y pulsa el recolector de datos continuo.
Es importante conectar el cubo porque algunas funciones (luces, temperatura y TV) solo se ejecutan si el cubo está conectado.
Cómo funciona: VIDEO
Sube el código, inserta la batería, cierra la caja y...
...¡ahora tienes un SMART CUBE!
Hice un video para mostrarte todas las funciones del cubo y cómo usarlo.
Conclusiones
Este proyecto es solo el primer paso hacia un hogar inteligente. Mi objetivo era usar el potencial de la placa Arduino 101 para crear algo nuevo. Creo que el acelerómetro y el giroscopio dan a la placa nuevas oportunidades en términos de movilidad. Con el BLE, además de ser portátil, también es fácil de conectar.
Es la primera vez que realizo concretamente uno de mis proyectos (quiero decir con un prototipo funcional). Fue duro y hubo algunas dificultades en el camino, pero al final aprendí mucho y estoy contento con el resultado. Espero que todos los que lean esta guía puedan aprender algo de mi trabajo y también modifiquen este proyecto según sus necesidades. Disculpad mi mal inglés, pero espero que las imágenes os ayuden.
En el futuro de este proyecto espero crear la centralita que es como el puente entre el Smart Cube y los actuadores (luces, temperatura, TV...). Esta centralita recibirá la señal BLE del cubo y usará esta información para hacer cosas inteligentes en tu casa.
Estoy muy contento de haber tenido la oportunidad de usar Arduino 101 y el Grove kit (el kit es muy simple y rápido para prototipar).
Espero que usar la placa de esta manera pueda ser una inspiración para vuestros proyectos. Podéis personalizarlo como queráis: ¡tengo curiosidad por ver qué funciones crearéis y en qué contextos diferentes lo usaréis!
Quizás no sea una revolución, pero es una nueva forma de interactuar con tu hogar.
Espero que os guste este tutorial.
Ahora es vuestro turno: poned las manos en el cubo y ¡hackeadlo!
Código
SMART CUBE - código completo con comentarios Arduino
// Librerías
#include "CurieIMU.h" // Acelerómetro y Giroscopio
#include <CurieBLE.h> // Bluetooth Low Energy
#include <Wire.h>
#include "rgb_lcd.h" // LCD
#include <Keypad.h> // Keypad
rgb_lcd lcd; // Inicialización LCD
// Inicialización Bluetooth:
BLEPeripheral blePeripheral; // Dispositivo BLE Periférico (la placa que programas)
// Servicios BLE
BLEService lightsService("1815"); // BLE Automation IO (1815) - info luces
BLEService termoService("1815"); // BLE Automation IO - info temperatura
BLEService TVService("1815"); // BLE Automation IO - info TV
// Características BLE
BLEUnsignedCharCharacteristic lightsChar("2A56", // Característica Digital (2A56) - luces
BLERead | BLENotify);
BLEUnsignedCharCharacteristic termoChar("2A56", // Característica Digital - temperatura
BLERead | BLENotify);
BLEUnsignedCharCharacteristic TVChar("2A58", // Característica Analog (2A58) - TV
BLERead | BLENotify);
// Constantes y declaración de variables:
// Funciones de orientación de cara y shake:
int lastOrientation = -1; // orientación anterior (para comparación)
unsigned long previousMillis = 0; // última actualización de tiempo
unsigned long interval = 2000; // tiempo de espera en posición superior antes de activar cara
unsigned long SHAKEpreviousMillis = 0; // última actualización tiempo shake
unsigned long SHAKEinterval = 2000; // tiempo de espera durante shake para desactivar cara
boolean keep = false; // usado para contar solo una vez el cambio de orientación de cara
int lastFUNCTION = -1; // usado para saber la orientación anterior
// Inicialización de caras: al principio todas false
boolean face0 = false;
boolean face1 = false;
boolean face2 = false;
boolean face3 = false;
boolean face4 = false;
boolean face5 = false;
// Cara LUCES
const int LEDlights = 11; // pin 11: LED amarillo
// Cara TEMPERATURA
const int pinTemp = A0; // pin A0: sensor temperatura
const int LEDhot = 12; // pin 12: LED rojo
const int LEDcold = 13; // pin 13: LED azul
float temperature; // valor temperatura memorizado
int B=3975; // valor B del termistor
float resistance; // valor resistencia memorizado
float tooHot = 26.0; // temperatura para activar aire acondicionado [AJUSTE]
float tooCold = 23.0; // temperatura para activar calefacción [AJUSTE]
// Cara TEMPORIZADOR
int BUZZER = 3; // pin 3: buzzer
boolean KEEPtime = false; // usado para contar solo una vez el cambio de orientación (no reiniciar mientras cuenta)
int TIMERmillis = 0; // para determinación de cuenta regresiva
int prevSHOWsecond = 0;
int CountdownInMillis = 0;
int SHOWmillis = 0; // cálculo resultado valor millis
int SHOWminute = 0; // valor minutos para mostrar en monitor cuenta regresiva
int SHOWseconds = 0; // valor segundos para mostrar en monitor cuenta regresiva
const int SETminute = 2; // temporizador 2 minutos [AJUSTE]
const int SETsecond = 30; // temporizador 30 segundos [AJUSTE]
// Cara SONIDO
const int soundLED = 9; // pin 9: LED verde
const int soundSENSOR = A1; // pin A0: sensor sonido
int brightness = 0; // brillo LED verde inicialización
// Cara TV
const byte ROWS = 4; // cuatro filas keypad
const byte COLS = 3; // tres columnas keypad
char keys[ROWS][COLS] = {
{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'*','0','#'}
}; // valores botones keypad
byte rowPins[ROWS] = {10,8,7,6}; // pines 10,8,7,6: conectar a pines filas keypad
byte colPins[COLS] = {5,4,2}; // pines 5,4,2: conectar a pines columnas keypad
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS); // inicialización keypad
// Cara OFF
const int LEDOFF = A2; // pin A2: LED rojo
void setup() {
pinMode(LEDlights, OUTPUT); // cada LED como salida
pinMode(LEDhot, OUTPUT);
pinMode(LEDcold, OUTPUT);
pinMode(soundLED, OUTPUT);
pinMode(LEDOFF, OUTPUT);
Serial.begin(9600); // inicializar comunicación serial
CountdownInMillis = (SETminute*60 + SETsecond)*1000; // calcula valor en millis desde minutos y segundos
lcd.begin(16, 2); // inicialización LCD
lcd.setRGB(0, 0, 0); // LCD RGB APAGADO al inicio
// inicializar dispositivo
Serial.println("Inicializando dispositivo IMU...");
CurieIMU.begin(); // Iniciar IMU
// Establecer rango acelerómetro a 2G
CurieIMU.setAccelerometerRange(2);
// Activar detección de golpes
CurieIMU.setDetectionThreshold(CURIE_IMU_SHOCK, 7000); // 7.0g = 7000 mg (intensidad del golpe)
CurieIMU.setDetectionDuration(CURIE_IMU_SHOCK, 2000); // 2000ms (duración del golpe)
CurieIMU.interrupts(CURIE_IMU_SHOCK);
// Configuración BLE
blePeripheral.setLocalName("SmartCubeSketch"); // nombre del proyecto
blePeripheral.setAdvertisedServiceUuid(lightsService.uuid()); // añadir UUID servicio luces
blePeripheral.addAttribute(lightsService); // añadir servicio BLE luces
blePeripheral.addAttribute(lightsChar); // añadir característica BLE luces
lightsChar.setValue(3); // valor inicial para esta característica = 3
// Significado valor BLE luces: 0 = luces off, 1 = luces on, 3 = estado inicial, 4 = no usado
blePeripheral.setAdvertisedServiceUuid(termoService.uuid()); // añadir UUID servicio temperatura
blePeripheral.addAttribute(termoService); // añadir servicio BLE temperatura
blePeripheral.addAttribute(termoChar); // añadir característica BLE temperatura
termoChar.setValue(0); // valor inicial 0: frío off - calor off
// Significado valor BLE termo: 0 = frío off - calor off, 1 = frío on - calor off, 2 = frío off - calor on, 3 = no usado
blePeripheral.setAdvertisedServiceUuid(TVService.uuid()); // añadir UUID servicio TV
blePeripheral.addAttribute(TVService); // añadir servicio BLE TV
blePeripheral.addAttribute(TVChar); // añadir característica TV
TVChar.setValue('x'); // valor inicial para esta característica (x = nada)
// Significado valor BLE TV: #número corresponde a botón pulsado, C: cerrar TV, O: abrir TV, x: estado inicial
blePeripheral.begin();
Serial.println("Dispositivo Bluetooth activo, esperando conexiones...");
}
// fin setup
void loop() {
BLECentral central = blePeripheral.central(); // conexión BLE
unsigned long currentMillis = millis(); // valor actual tiempo en milisegundos
// El siguiente código viene de www.arduino.cc/en/Tutorial/Genuino101CurieIMUAccelerometerOrientation
// se usa para detectar la orientación de la placa
int orientation = -1; // orientación de la placa
String orientationString; // string para imprimir descripción orientación
// leer acelerómetro:
int x = CurieIMU.readAccelerometer(X_AXIS);
int y = CurieIMU.readAccelerometer(Y_AXIS);
int z = CurieIMU.readAccelerometer(Z_AXIS);
// calcular valores absolutos para determinar el mayor
int absX = abs(x);
int absY = abs(y);
int absZ = abs(z);
if ((absZ > absX) && (absZ > absY)) { // orientación base en Z
if (z > 0) {
orientationString = "up";
orientation = 0;
} else {
orientationString = "down";
orientation = 1;
}
} else if ((absY > absX) && (absY > absZ)) { // orientación base en Y
if (y > 0) {
orientationString = "digital pins up";
orientation = 2;
} else {
orientationString = "analog pins up";
orientation = 3;
}
} else { // orientación base en X
if (x < 0) {
orientationString = "connector up";
orientation = 4;
} else {
orientationString = "connector down";
orientation = 5;
}
}
// fin código tutorial.
// En este punto tienes el valor de orientación de la placa constantemente actualizado:
/* Orientaciones de la placa:
0: plana, procesador hacia arriba (TEMPORIZADOR)
1: plana, procesador hacia abajo (TV)
2: horizontal, pines analógicos abajo (TEMPERATURA)
3: horizontal, pines analógicos arriba (OFF)
4: vertical, conector USB arriba (LUCES)
5: vertical, conector USB abajo (SONIDO)
*/
// Para este proyecto necesitas saber si la cara ha cambiado de la anterior [lastFUNCTION != orientation]
// pero esta info se imprime solo si la cara está en posición SUPERIOR por más de [interval] tiempo
// y solo una vez [keep] (no necesitas activar constantemente la cara, solo una vez)
// como el valor de orientación se actualiza constantemente, necesitas empezar a contar tiempo cuando la orientación cambia [orientation != lastOrientation]
if (orientation != lastOrientation) {
// si la orientación cambió, empezar a contar tiempo
lastOrientation = orientation; // memorizar orientación actual de la cara
previousMillis = currentMillis; // memorizar tiempo cuando la cara cambió
keep = false;
} else if (currentMillis - previousMillis > interval && keep == false && lastFUNCTION != orientation) {
// esta condición imprime la orientación solo si la cara está arriba por un intervalo
// y solo una vez (keep)
// y solo si la cara es diferente del loop anterior
Serial.println(orientationString); // imprimir orientación
// la cara actual [orientation] se pone como true (función de cara activada)
if (orientation == 1) { // cara TV
face1 = true; // cara TV true
lastFUNCTION = orientation; // memorizar esta activación en [lastFUNCTION]
Serial.println("TV true"); // imprimir cara activada
TVChar.setValue('O'); // O: señal abrir TV (BLE): TV abierta solo una vez
}
if (orientation == 4) { // cara LUCES
face4 = true;
lastFUNCTION = orientation;
Serial.println("LIGHTS true");
}
if (orientation == 3) { // cara OFF
face3 = true;
lastFUNCTION = orientation;
Serial.println("OFF true");
}
if (orientation == 5) { // cara SONIDO
face5 = true;
lastFUNCTION = orientation;
Serial.println("SOUND true");
}
if (orientation == 2) { // cara TEMPERATURA
face2 = true;
lastFUNCTION = orientation;
Serial.println("TEMPERATURE true");
}
if (orientation == 0) { // cara TEMPORIZADOR
face0 = true;
lastFUNCTION = orientation;
Serial.println("TIMER true");
if (KEEPtime == false) { // temporizador activado solo si es 1er ciclo o se ha detenido
TIMERmillis = currentMillis; // empezar a contar tiempo
}
}
keep = true; // [keep] cambia valor para que en próximo loop no entre en esta condición si la cara no cambia (evita activar otra vez misma cara)
}
// Esta condición es para la función shake: si agitas por más de [SHAKEinterval] tiempo, la cara se desactiva
if (CurieIMU.getInterruptStatus(CURIE_IMU_SHOCK) && currentMillis - SHAKEpreviousMillis > SHAKEinterval) {
Serial.println("SHAKE"); // imprimir "SHAKE" si se detecta agitación
// La última cara activada [lastFUNCTION] se pone como false (función de cara desactivada)
// Desactivación TV
if (lastFUNCTION == 1) { // cara TV
TVChar.setValue('C'); // C: cerrar TV señal BLE
Serial.println("TV false - CLOSE"); // imprimir cara cerrada
face1 = false; // cara TV false
}
// Desactivación LUCES
if (lastFUNCTION == 4) { // cara LUCES
if (central.connected() == true) { // si hay central conectada a periférico:
lightsChar.setValue(0); // luces OFF señal BLE
digitalWrite(LEDlights, HIGH); // encender LED amarillo para ver cubo en oscuridad
}
Serial.println("LIGHTS false - CLOSE");
face4 = false; // cara LUCES false
}
// OFF
if (lastFUNCTION == 3) { // cara OFF
// Cara OFF agitada: todo se cierra y LED rojo OFF se enciende
digitalWrite(LEDOFF, HIGH); // LED rojo OFF encendido cuando cubo cerrado
// ahora cerrar todas las funciones activadas:
// CERRAR TV
TVChar.setValue('C'); // C: cerrar TV señal BLE
Serial.println("TV false - CLOSE");
face1 = false;
// CERRAR LUCES
Serial.println("LIGHTS false - CLOSE");
if (central.connected() == true) {
lightsChar.setValue(0);
digitalWrite(LEDlights, LOW); // LED luces apagado si cara OFF agitada
}
face4 = false;
// CERRAR SONIDO
analogWrite(soundLED, LOW); // apagar LED sonido
Serial.println("SOUND false - CLOSE");
face5 = false;
// CERRAR TEMPERATURA
if (central.connected() == true) {
digitalWrite(LEDhot, LOW);
digitalWrite(LEDcold, LOW);
termoChar.setValue(0); // señal BLE temperatura: 0 = frío off - calor off
}
Serial.println("TEMPERATURE false - CLOSE");
face2 = false;
// CERRAR TEMPORIZADOR
Serial.println("TIMER false - CLOSE");
lcd.setRGB(0, 0, 0); // LCD RGB apagado
lcd.clear();
KEEPtime = false;
face0 = false;
// El cubo inactivo, solo LED OFF activo
Serial.println("OFF false - CLOSE");
face3 = false; // cara OFF false
}
// Desactivación SONIDO
if (lastFUNCTION == 5) { // cara SONIDO
analogWrite(soundLED, LOW); // apagar LED sonido
Serial.println("SOUND false - CLOSE");
face5 = false; // cara SONIDO false
}
// Desactivación TEMPERATURA
if (lastFUNCTION == 2) { // cara TEMPERATURA
// si hay central conectada a periférico:
if (central.connected() == true) {
digitalWrite(LEDhot, LOW); // apagar LED rojo temperatura
digitalWrite(LEDcold, LOW); // apagar LED azul temperatura
termoChar.setValue(0); // señal BLE temperatura: 0 = frío off - calor off
}
Serial.println("TEMPERATURE false - CLOSE");
face2 = false; // cara TEMPERATURA false
}
// Desactivación TEMPORIZADOR
if (lastFUNCTION == 0) { // cara TEMPORIZADOR
Serial.println("TIMER false - CLOSE");
face0 = false; // cara TEMPORIZADOR false
// si agitas el cubo mientras el tiempo corre, el LCD se pone rojo y muestra tiempo restante
lcd.setRGB(180, 40, 0); // retroiluminación RGB roja
lcd.clear(); // LCD limpio
lcd.setCursor(0, 0);
lcd.print("STOP AT ");
lcd.setCursor(8, 0);
lcd.print(SHOWminute); // indica minutos al agitar
lcd.setCursor(9, 0);
lcd.print(":");
lcd.setCursor(10, 0);
lcd.print(SHOWseconds); // indica segundos al agitar
tone(BUZZER,1000,1000); // sonido corto
delay(2000);
lcd.clear(); // limpiar LCD
lcd.setRGB(0, 0, 0); // retroiluminación LCD apagada
KEEPtime = false; // cara TEMPORIZADOR false
}
SHAKEpreviousMillis = currentMillis; // memorizar valor para cálculo [SHAKEinterval]
}
// Las siguientes instrucciones se ejecutan en loop solo si la cara está activada
if (face1 == true) { // cara TV
digitalWrite(LEDOFF, LOW); // si esta cara true, LED OFF LOW
if (central.connected() == true) { // si cubo conectado BLE
char key = keypad.getKey(); // leer valor keypad
if (key && orientation == 1){ // si algo pulsado y solo cuando cara TV arriba (evitar pulsaciones involuntarias)
if (key == '0') { TVChar.setValue(key); Serial.println(key); }
if (key == '1') { TVChar.setValue(key); Serial.println(key); }
if (key == '2') { TVChar.setValue(key); Serial.println(key); }
if (key == '3') { TVChar.setValue(key); Serial.println(key); }
if (key == '4') { TVChar.setValue(key); Serial.println(key); }
if (key == '5') { TVChar.setValue(key); Serial.println(key); }
if (key == '6') { TVChar.setValue(key); Serial.println(key); }
if (key == '7') { TVChar.setValue(key); Serial.println(key); }
if (key == '8') { TVChar.setValue(key); Serial.println(key); }
if (key == '9') { TVChar.setValue(key); Serial.println(key); }
if (key == '*') { TVChar.setValue(key); Serial.println(key); }
if (key == '#') { TVChar.setValue(key); Serial.println(key); }
}
}
}
if (face4 == true) { // cara LUCES
digitalWrite(LEDOFF, LOW);
if (central.connected() == true) {
lightsChar.setValue(1); // LUCES activada señal BLE
digitalWrite(LEDlights, LOW); // LED amarillo apagado porque luces de casa encendidas
}
}
if (face3 == true) { // cara OFF
// cuando cara OFF arriba no se hace nada
digitalWrite(LEDOFF, LOW); // LED OFF activado solo al agitar, ahora LOW
}
if (face5 == true) { // cara SONIDO
digitalWrite(LEDOFF, LOW);
// sensor sonido activado, brillo LED regulado por sonido
// este código viene de ejemplo regulación brillo
long sum = 0;
for (int i=0; i<32; i++) {
sum += analogRead(soundSENSOR);
}
sum >>= 5;
brightness = (sum*255)/1024; // calcular valor brillo
analogWrite(soundLED, brightness); // intensidad brillo LED verde regulada por ruido
delay(50);
}
if (face2 == true) { // cara TEMPERATURA
digitalWrite(LEDOFF, LOW);
if (central.connected() == true) {
// leer valor temperatura
int val = analogRead(pinTemp); // obtener valor analógico
resistance=(float)(1023-val)*10000/val; // obtener resistencia
temperature=1/(log(resistance/10000)/B+1/298.15)-273.15; // calcular temperatura
// condiciones activación
if (temperature > tooHot) { // activar aire acondicionado
digitalWrite(LEDhot, LOW); // apagar LED calefacción
digitalWrite(LEDcold, HIGH); // encender LED aire acondicionado
termoChar.setValue(1); // establecer vía BLE condición 1 = frío on - calor off
}
if (temperature < tooCold){ // activar calefacción
digitalWrite(LEDhot, HIGH);
digitalWrite(LEDcold, LOW);
termoChar.setValue(2); // 2 = frío off - calor on
}
if (temperature > tooCold && temperature < tooHot){ // temperatura ideal: nada activado
digitalWrite(LEDhot, LOW);
digitalWrite(LEDcold, LOW);
termoChar.setValue(0); // 0 = frío off - calor off
}
}
}
if (face0 == true) { // cara TEMPORIZADOR activada
digitalWrite(LEDOFF, LOW);
// calcular tiempo para mostrar en display
SHOWmillis = (CountdownInMillis - (currentMillis - TIMERmillis))/1000;
SHOWminute = SHOWmillis/60; // valor minutos para LCD
SHOWseconds = SHOWmillis%60; // valor segundos para LCD
lcd.setRGB(50, 100, 70); // abrir LCD con color RGB azul
if (prevSHOWsecond != SHOWseconds){ // refrescar pantalla cada segundo (refrescar cada loop es muy rápido)
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("TIMER ");
lcd.setCursor(7, 0);
lcd.print(SETminute); // escribe minutos configurados
lcd.setCursor(8, 0);
lcd.print(":");
lcd.setCursor(9, 0);
lcd.print(SETsecond); // escribe segundos configurados
lcd.setCursor(0, 1);
lcd.print(SHOWminute); // escribe minutos restantes actuales
lcd.setCursor(1, 1);
lcd.print(":");
lcd.setCursor(2, 1);
lcd.print(SHOWseconds); // escribe segundos restantes actuales
KEEPtime = true;
prevSHOWsecond = SHOWseconds; // para refrescar cada segundo
}
if (SHOWminute == 0 && SHOWseconds == 0) { // cuando termina cuenta regresiva
lcd.clear(); // limpiar LCD
lcd.setCursor(4, 0);
lcd.setRGB(180, 40, 0); // LCD RGB rojo
lcd.print("TIME OUT");
tone(BUZZER,1000,500); // tres sonidos
delay(900);
tone(BUZZER,1000,500);
delay(900);
tone(BUZZER,1000,1000);
delay(1500);
lcd.clear(); // limpiar y cerrar LCD
lcd.setRGB(0, 0, 0);
face0 = false; // cara TEMPORIZADOR cerrada (false)
KEEPtime = false;
}
}
} // fin loop
Piezas personalizadas y cajas
Este es el archivo (.dxf) que puedes subir a tu cortadora láser. Usé tablero de fibra de densidad media (MDF) de 3mm. Corta las líneas negras y graba las rojas. Importante: si el grosor de tu material es diferente debes modificar este esquema.
smart_cube_8sVCflFmhM.dxfEl mismo archivo de la caja pero en formato diferente: .pdf
Esquemas
Este es un .jpeg del esquema Fritzing (los cables amarillos están conectados a componentes Grove)
Este es un esquema de las conexiones en el Grove Shield
_cI0IwUsPVZ.Base%20shield%20connectionsProceso de manufactura
- Por Qué un Diseño Ligeramente Mayor Puede Acelerar la Innovación y Reducir Riesgo
- Construya una Red de Sensores Inalámbrica Económica para su Hogar
- Monitoriza la temperatura de tu casa con un panel Raspberry Pi
- Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure
- Controla tu Ventilador de Techo con Alexa: Guía Paso a Paso
- Paneles solares: una inversión inteligente para su hogar
- Cómo la tecnología de hogar inteligente transforma la vida cotidiana
- Cerrando la Brecha de Habilidades en Hogar Inteligente: Por Qué Reino Unido Rezaga en Europa
- Evolución del Hogar Inteligente: Qué Nos Depara el Futuro de la Vida Conectada
- Seguridad inteligente: Estrategias de expertos para proteger sus dispositivos IoT domésticos de hackers
- Cómo Fortalecer la Seguridad de tu Hogar Inteligente: Consejos de Expertos