Interface Física Robusta para Controle de Automação Residencial
Componentes e Materiais
| Componente | Quantidade |
|---|---|
| Servo TowerPro SG90 | 1 |
| Dobradiças Pequenas | 1 conjunto |
| Botões | 1 conjunto |
| Arduino Yun | 1 |
| Transformador de Corrente 100A | 1 |
| Resistores e Capacitores | 7 |
Sobre o Projeto
Veja os dois vídeos abaixo para uma explicação rápida do projeto.
Interface de Automação Residencial Física – Controle do Mundo Real
Uma interface transmite informação e permite controle. A maioria das plataformas de automação residencial usa "interface virtual": você pega o smartphone, abre o app, vê o estado da casa e liga/desliga luzes. Funciona bem quando você está fora. Mas olhar uma representação virtual e processar a informação no display exige esforço. Requer foco e não é intuitivo.
Quis criar uma "interface física" – uma pequena casa modelo que imita fisicamente o que quero saber sobre minha casa real. Quando a porta da garagem abre, a porta da garagem no modelo também abre. O modelo fica na mesa de centro: olho e vejo se a garagem ficou aberta antes de dormir. Ou na mesa do trabalho, conectado via VPN à casa. Olho e vejo se a porta da frente ficou aberta. Esta interface física pode ser tão criativa ou utilitária quanto eu quiser.
Nos passos a seguir:
- Construir casa modelo para mostrar posição de portas, consumo de energia, luzes acesas;
- Construir monitor de energia com biblioteca Open Energy Monitor Arduino, enviar dados à casa modelo e ao OpenHAB;
- Mostrar formas de enviar posição de portas/janelas ao modelo. Demonstrar como usar hub Wink e sensor de contato Wink "Tripper" em sistema DIY;
- Usar Wink e Arduino para saídas: abrir/fechar porta da garagem real, ligar/desligar luzes.
A casa modelo tem servos e LEDs ligados a um controlador Arduino. Este assina mensagens MQTT indicando posições de portas e consumo de energia, e aciona servos conforme isso. Mesmo para LED indicando luz acesa. Há algumas opções para levar info dos sensores ao broker MQTT – detalharei depois. No centro, um Raspberry Pi roda broker MQTT (Mosquitto) e OpenHAB. OpenHAB não é obrigatório para o modelo, mas dá interface para app no smartphone e permite monitoramento/atuação remota. Ter interface física não significa jogar fora a virtual.
A casa modelo também tem dois botões. Um alterna lâmpada Zigbee ligada/desligada. O outro abre/fecha a porta da garagem (da casa REAL).
Parte 1: Construção da Casa
Passo 1: Construção da Casa Modelo
Não pretendo ser prescritivo. Sou amador em artesanato, apenas mostro como construí. Você deve adaptar à sua moradia e ao que importa para você. Muita criatividade possível. Alguns componentes na foto (como transformador de corrente) serão usados em passos posteriores.
Componentes
- (1) Caixa de papelão. Tamanho e proporções a seu gosto.
- (3) Servo Tower Pro SG90 link
- (2) Dobradiças pequenas link
- Material adesivo. Usei fitas dupla-face 3M de ganchos.
- Arduino Yun ou Arduino Uno + Ethernet Shield.
- Botões link
- Coisas pela casa.
Telhado
Cortei uma aba lateral da caixa e fixei na outra (ainda presa) para formar telhado. Usei caixa pequena para estruturar o ângulo reto, depois reforcei com peça Lego. Use o que tiver em casa.
Portas / Janelas
Corte furos para portas que quer monitorar. Fixe dobradiça(s) na porta com fita dupla-face e prenda na casa. Nada sofisticado – improvise com o que tiver. Usei fitas 3M dupla-face de espuma (as de ganchos). Também usei para fixar os servomotores.
Para porta da garagem: braço do servo move a porta para abrir, gravidade fecha. Para porta da frente: precisei prender linha na porta com dobradiça para o braço do servo abri-la. Peça Lego amarela serve para afastar servo da dobradiça.
Medidor de Energia
Nada complexo. Recorte seta e fixe no braço do servo. Recorte formato de arbusto, marque escala em kW, e encaixe o servo na caixa com o arbusto entre eles.
Acima do servo de energia, colei um LED vermelho.
Dois botões para controlar luzes e porta da garagem. Botões momentâneos, rosqueados com porca por fora para prender na parede da caixa. Do outro lado, contatos metálicos para soldar fios.
Passo 2: Fiação e Código
Fiação
Fiz bagunça na fiação interna. Se preferir só saber pinos:
- LED status (pino 7)
- LED indicador de luz (pino 4)
- Servo 1 – porta da frente (pino 3)
- Servo 2 – porta da garagem (pino 5)
- Servo 3 – medidor de energia (pino 6)
- Botão 1 – Luzes lig/deslig (pino 8)
- Botão 2 – Garagem abre/fecha (pino 9)
Opções de Controlador
Use o que preferir e tiver. Opção mais barata (~$20): Arduino Uno clone + Ethernet Shield. Comecei com isso, mas me prendia ao cabo Ethernet. Mudei para Arduino Yun (~$65). Mais caro, mas dá liberdade Wi-Fi. Yun foi fácil:
- Conecte Yun ao roteador via Ethernet;
- Acesse página web do Yun;
- Configure senhas e IP fixo no roteador;
- Faça upload do sketch do Yun.
Sketches para Arduino Uno e Yun anexados. São similares, exceto pela bridge Ethernet do Yun – dá para copiar código do Yun para o Uno. Após mudar para Yun, adicionei os dois botões de controle. Por isso o sketch do Uno não tem esses botões.
Vídeo no Passo 1 mostra Arduino Yun. Vídeo com Uno + Ethernet Shield (sem botões ainda, resto funciona igual).
Parte 2: Entradas (Sensores)
Passo 3: Sensor – Monitor de Energia
Agora que temos interface física mostrando consumo, precisamos de nó sensor para ler consumo da casa e publicar no broker MQTT. Algumas formas. Uso Arduino Yun – menos complicado, não o mais barato. Alternativas: Arduino Uno + Ethernet Shield + roteador como bridge Wi-Fi, ou Raspberry Pi com pacote Open Energy Monitor. Cubro só o método Yun.
Transformador de corrente $7 do eBay. Versão 100A YHDC SCT-013-000. Ligue conforme diagrama e faça upload do sketch Arduino Yun (final deste passo). Modifique IP do broker MQTT no código. Referência: Open Energy Monitor.
Valores Ideais dos Componentes
- Resistor de Carga (Burden) = 33 Ω
- Resistores Divisor de Tensão = 10k Ω
- Capacitor = 10 µF
Meu circuito não bate exatamente com diagrama – não tinha componentes exatos. Usei dois resistores 68 Ω em paralelo (no lugar do 33 Ω). Não tinha capacitor 10 µF, usei dois 22 µF em série (capacitância equivalente próxima).
Fixe o transformador de corrente em uma das fases de entrada da casa. Só tinha um transformador 100A, monitoro apenas uma fase. Futuramente, mais transformadores para outra perna e circuitos derivados. Com amperímetro real, meu DIY sempre lia 1A acima em diferentes leituras. Simples: subtrair esse 1A extra.
OpenHAB
Já que temos dados, exibir no OpenHAB para gráficos. Configuração relevante:
Definição de Itens
Number itm_smarthome_energy_amps "Energy (amps) [%.1f]" {mqtt="<[mymosquitto:2853:state:default]"}
Number itm_smarthome_energy_watts "Energy (Watts) [%.1f]" {mqtt="<[mymosquitto:2852:state:default]"}
Sitemap
Text label="Energy" icon="firstfloor" {
Frame label="Energy Usage" {
Text item=itm_smarthome_energy_amps
Text item=itm_smarthome_energy_watts
Chart item=itm_smarthome_energy_watts period=h refresh=5000
}
}
Persistência
Para gráficos, precisamos estratégia de persistência. RRD4J é mais fácil. Arquivo /openhab/configurations/persistence/rrd4j.persist:
Strategies {
everyMinute : "0 * * * * ?"
}
Items {
DemoSwitch,NoOfLights,Window_GF_Toilet,Heating* : strategy = everyChange, everyMinute, restoreOnStartup
Temperature*,Weather_Chart* : strategy = everyMinute, restoreOnStartup
itm_smarthome_energy_watts : strategy = everyUpdate
}
Passo 4: Sensor – Nós DIY Sem Fio
Opções para sensores sem fio de aberto/fechado.
Em projeto anterior usei transceptor sem fio $5 para enviar dados via gateway MQTT. Ainda uso para status da porta da garagem no OpenHAB; no vídeo demo, a porta da garagem do modelo reflete a real via esse método. Código e circuito detalhados no projeto anterior (meio feio, mas fica na garagem onde ninguém vê).
Também uso sensor de luz para indicar luz acesa. Do mesmo projeto anterior: "Uber sensor" com fotorresistor envia nível de brilho sem fio ao OpenHAB. Aqui, apenas assino tópico MQTT de nível de luz.
Fiz sensor de reed switch alimentado por bateria com mesmo transceptor/gateway. Mas não fica bonito – não uso em porta/janela interna por estética. Por isso uso sensores reed switch consumer-grade da Wink. Próximo passo.
Passo 5: Sensor – Hub Wink
Encontrei blog de usuário inicial do Wink Hub que achou forma de fazer root no hub para acessar exploit PHP. Permite rodar utilitário "aprontest" para controlar dispositivos pareados com Wink Hub. Com isso, controlo luzes via interface OpenHAB.
Maior benefício do root: controle local de luzes e status de sensores sem acessar servidor Wink. Wink Hub/API sempre precisa internet para contato com servidor Wink. Com exploit PHP, operações ficam na LAN local. Ótimo.
Script PHP incluso no final deste passo (ou link alternativo). Roda no Raspberry Pi e faz polling do Wink Hub para status de dois sensores Wink Tripper. Status enviado ao OpenHAB via REST API. OpenHAB publica tópicos MQTT para posições das portas. Controlador da casa modelo abre/fecha portas assinando esses tópicos.
Três arquivos de configuração OpenHAB (itens, sitemap, rules) anexados – necessários para tudo funcionar. Definem itens de contato que script de polling usa via REST. Também script exemplo para controlar lâmpada Zigbee via OpenHAB.
Scripts e arquivos de configuração:
sitemap.txtrules.txtitems.txtdemo_1_general.shpolling.php
Passo 6: Saída – Luzes
Devido à ordem dos arquivos de configuração, passos anteriores já proveram tudo para controlar "lâmpada conectada" via interface física e OpenHAB. Luzes: qualquer uma suportada pelo Wink Hub. Testado com Cree Connected Bulb e GE Wink Lights – ambas funcionam. Vídeo mostra sensor de luz e botões controlando lâmpada inteligente.
Passo 7: Saída – Abridor de Porta de Garagem
Arquivos de configuração do Passo 5 incluem itens OpenHAB necessários para controlar porta de garagem. Mas ainda precisa de algo que abra/feche fisicamente. Modifiquei partes de Instructable anterior. Componentes:
- Arduino Clone ($10)
- Ethernet Shield ($7)
- Relé Reed ($2)
- Controle remoto reserva da garagem ($22)
Arduino controla relé reed abrindo/fechando contatos secos. Botão do controle reserva ligado nos contatos secos do relé. Conecte Pino 5 e GND do Arduino aos dois pinos da bobina (pinos externos) do relé reed; pinos internos do relé ao botão do controle remoto.
Arduino assina tópico MQTT e aguarda comando abrir/fechar. Ao ver tópico, energiza relé momentaneamente, fechando "botão" do controle reserva. Sketch Arduino anexado. Adicione garage_monitor_rules.txt ao arquivo de rules – necessário além das rules do Passo 5. Se não usar sensor ultrassônico que usei, adapte essa parte.
Se porta da garagem é silenciosa ou quer aviso sonoro em outra parte da casa quando abre, rule acima toca arquivo de áudio. Ouça no primeiro vídeo demo ~1min30s.
Arquivos:
garage_monitor_rules.txtgarage_opener.ino
Passo 8: Outras Considerações
Decisões refletem ferramentas que domino, peças que tinha e prioridades. Você tem ferramentas, hardware e ideias diferentes.
Há muita flexibilidade com MQTT e OpenHAB – não precisa fazer exatamente como eu. Controlador da casa modelo: Arduino, Raspberry Pi, SparkCore. Sensores DIY: Arduino ou ESP8266 standalone. Restrição: dados dos sensores devem ser publicados no broker MQTT. Se tiver stick USB Z-Wave no OpenHAB, use como bridge Z-Wave → MQTT, e sensores Z-Wave para portas.
Sensores Wink abertos/fechados também podem ser feitos diferente. Sem root no Wink Hub, use Wink API para pegar status e postar no OpenHAB ou direto via MQTT. Usa servidor Wink, mas remove necessidade de hub com root.
Muitas formas de fazer. Tendo a usar hardware de menor denominador comum: Arduino e caixas de papelão.
Código
smarthome_yun.inosmarthome_ethernet.inoenergy_monitor_yun.ino
smarthome_yun.ino
// Eric Tsai // 2015-04-13 // Arduino Yun para interface física smart home
// Modifique tópicos MQTT e IP do broker
#include <Bridge.h>
#include <YunClient.h>
#include <PubSubClient.h>
#include <Servo.h>
unsigned long keepalivetime=0;
unsigned long MQTT_reconnect=0;
YunClient yun;
PubSubClient client("192.168.1.101", 1883, callback, yun);
bool conn_ok;
int ledPin = 4; // indica luz acesa
int statusPin = 7; // indica status MQTT
int servo1Pin = 3; // porta da frente
int servo2Pin = 5; // porta da garagem
int servo3Pin = 6; // medidor de energia
Servo servo1, servo2, servo3;
int button1 = 8; // botão luzes
int button2 = 9; // botão garagem
int servo1_target = 5, servo2_target = 5, servo3_target = 180;
int servo1_pos_cur = 5, servo2_pos_cur = 5, servo3_pos_cur = 180;
int servo1Opened = 5, servo1Closed = 130;
int servo2Opened = 5, servo2Closed = 150;
unsigned long servo1_time = 0, servo2_time = 0, servo3_time = 0;
unsigned long button1_db = 0, button2_db = 0;
int button = 0, callback_flag = 0;
char buff_message[12];
void callback(char* topic, byte* payload, unsigned int length) {
int mytopic = atoi(topic);
payload[length] = '\0';
float mymsg = atof((const char*)payload);
if (mytopic == 2822) { // LED luz
digitalWrite(ledPin, mymsg == 1 ? HIGH : LOW);
}
if (mytopic == 2832) { // servo 1 - porta frente
servo1_target = (mymsg == 1) ? servo1Opened : servo1Closed;
}
if (mytopic == 2842) { // servo 2 - porta garagem
servo2_target = (mymsg == 1) ? servo2Opened : servo2Closed;
}
if (mytopic == 2852) { // servo 3 - energia
if (mymsg > 6000) mymsg = 6000;
if (mymsg < 0) mymsg = 0;
servo3_target = 180 - ((1 - ((6000 - mymsg) / 6000)) * 180) - 25;
callback_flag = 1;
}
}
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(statusPin, OUTPUT);
pinMode(button1, INPUT_PULLUP);
pinMode(button2, INPUT_PULLUP);
digitalWrite(ledPin, HIGH);
Bridge.begin();
client.connect("yun smarthome");
client.publish("watch", "Smart Home Connected!");
keepalivetime = millis();
MQTT_reconnect = millis();
client.subscribe("2822");
client.subscribe("2832");
client.subscribe("2842");
client.subscribe("2852");
digitalWrite(ledPin, LOW);
servo1.attach(servo1Pin); servo1.write(90);
servo2.attach(servo2Pin); servo2.write(90);
servo3.attach(servo3Pin); servo3.write(5);
}
void loop() {
client.loop();
// Movimento suave dos servos (sem delay)
if ((millis() - servo1_time) > 20) {
if (servo1_pos_cur > servo1_target) servo1_pos_cur--;
else if (servo1_pos_cur < servo1_target) servo1_pos_cur++;
servo1.write(servo1_pos_cur);
servo1_time = millis();
}
if ((millis() - servo2_time) > 20) {
if (servo2_pos_cur > servo2_target) servo2_pos_cur--;
else if (servo2_pos_cur < servo2_target) servo2_pos_cur++;
servo2.write(servo2_pos_cur);
servo2_time = millis();
}
if ((millis() - servo3_time) > 20) {
if (servo3_pos_cur > servo3_target) servo3_pos_cur--;
else if (servo3_pos_cur < servo3_target) servo3_pos_cur++;
servo3.write(servo3_pos_cur);
servo3_time = millis();
}
if (callback_flag == 1) {
callback_flag = 0;
dtostrf(servo3_target, 4, 5, buff_message);
client.publish("watch", buff_message);
}
// Botão 1 - Luzes
button = digitalRead(button1);
if (button == 0) {
if ((millis() - button1_db > 3000) || (button1_db > millis())) {
button1_db = millis();
client.publish("2862", "button1 yaya");
}
}
// Botão 2 - Garagem
button = digitalRead(button2);
if (button == 0) {
if ((millis() - button2_db > 3000) || (button2_db > millis())) {
button2_db = millis();
client.publish("2872", "button2 yaya");
}
}
// Reconexão MQTT a cada 60s
if ((millis() - MQTT_reconnect) > 60000) {
conn_ok = client.connected();
digitalWrite(statusPin, conn_ok ? HIGH : LOW);
if (!conn_ok) {
client.disconnect();
delay(5000);
while (client.connect("smarthouse") != 1) {
digitalWrite(statusPin, LOW);
delay(4000);
}
digitalWrite(statusPin, HIGH);
}
MQTT_reconnect = millis();
client.publish("watch", "smart home heartbeat!");
}
}
smarthome_ethernet.ino
// Eric Tsai // 2015-04-1 // Arduino Uno + Ethernet para interface física smart home
#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
#include <Servo.h>
byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0x43, 0x13 };
byte server[] = { 192, 168, 1, 101 };
EthernetClient ethClient;
PubSubClient client(server, 1883, callback, ethClient);
unsigned long keepalivetime=0, MQTT_reconnect=0;
bool conn_ok;
int ledPin = 4, statusPin = 7;
int servo1Pin = 3, servo2Pin = 5, servo3Pin = 6;
Servo servo1, servo2, servo3;
int servo1_target = 5, servo2_target = 5, servo3_target = 180;
int servo1_pos_cur = 5, servo2_pos_cur = 5, servo3_pos_cur = 180;
int servo1Opened = 5, servo1Closed = 120;
int servo2Opened = 5, servo2Closed = 150;
unsigned long servo1_time = 0, servo2_time = 0, servo3_time = 0;
void callback(char* topic, byte* payload, unsigned int length) {
Serial.println("received MQTT");
int mytopic = atoi(topic);
payload[length] = '\0';
float mymsg = atof((const char*)payload);
Serial.print("("); Serial.print(mytopic); Serial.print(", "); Serial.print(mymsg); Serial.println(")");
if (mytopic == 2822) digitalWrite(ledPin, mymsg == 1 ? HIGH : LOW);
if (mytopic == 2832) servo1_target = (mymsg == 1) ? servo1Opened : servo1Closed;
if (mytopic == 2842) servo2_target = (mymsg == 1) ? servo2Opened : servo2Closed;
if (mytopic == 2852) {
if (mymsg > 6000) mymsg = 6000;
if (mymsg < 0) mymsg = 0;
servo3_target = 180 - ((1 - ((6000 - mymsg) / 6000)) * 180);
}
}
void setup() {
Serial.begin(9600);
Serial.println("starting");
pinMode(ledPin, OUTPUT); pinMode(statusPin, OUTPUT);
digitalWrite(ledPin, HIGH);
while (Ethernet.begin(mac) != 1) {
Serial.println("Error getting IP via DHCP, retrying...");
delay(5000);
}
Serial.println("ethernet OK");
keepalivetime = millis();
while (client.connect("smarthouse") != 1) {
Serial.println("Error connecting to MQTT");
delay(4000);
}
MQTT_reconnect = millis();
Serial.println("setup complete");
client.publish("smarthouse", "hello world");
client.subscribe("2822"); client.subscribe("2832"); client.subscribe("2842"); client.subscribe("2852");
digitalWrite(ledPin, LOW);
servo1.attach(servo1Pin); servo1.write(90);
servo2.attach(servo2Pin); servo2.write(90);
servo3.attach(servo3Pin); servo3.write(5);
}
void loop() {
client.loop();
if ((millis() - servo1_time) > 20) {
if (servo1_pos_cur > servo1_target) servo1_pos_cur--;
else if (servo1_pos_cur < servo1_target) servo1_pos_cur++;
servo1.write(servo1_pos_cur); servo1_time = millis();
}
if ((millis() - servo2_time) > 20) {
if (servo2_pos_cur > servo2_target) servo2_pos_cur--;
else if (servo2_pos_cur < servo2_target) servo2_pos_cur++;
servo2.write(servo2_pos_cur); servo2_time = millis();
}
if ((millis() - servo3_time) > 20) {
if (servo3_pos_cur > servo3_target) servo3_pos_cur--;
else if (servo3_pos_cur < servo3_target) servo3_pos_cur++;
servo3.write(servo3_pos_cur); servo3_time = millis();
}
if ((millis() - MQTT_reconnect) > 60000) {
conn_ok = client.connected();
digitalWrite(statusPin, conn_ok ? HIGH : LOW);
if (!conn_ok) {
client.disconnect(); delay(5000);
while (client.connect("smarthouse") != 1) {
digitalWrite(statusPin, LOW); delay(4000);
}
digitalWrite(statusPin, HIGH);
}
MQTT_reconnect = millis();
client.publish("smarthouse", "heartbeat every minute!");
}
}
energy_monitor_yun.ino
/* Eric Tsai 2015-04-22 Arduino Yun para publicar consumo de energia no MQTT
Modifique "PubSubClient client" para IP do seu broker */
#include <Bridge.h>
#include <YunClient.h>
#include <PubSubClient.h>
#include "EmonLib.h"
int LED = 3;
EnergyMonitor emon1;
unsigned long MQTT_reconnect=0, read_energy=0;
double Irms;
bool conn_ok;
YunClient yun;
PubSubClient client("192.168.1.101", 1883, callback, yun);
void callback(char* topic, byte* payload, unsigned int length) {
digitalWrite(LED, HIGH); delay(500); digitalWrite(LED, LOW);
}
void setup() {
pinMode(LED, OUTPUT);
digitalWrite(LED, HIGH); delay(1000); digitalWrite(LED, LOW);
Bridge.begin();
client.connect("yun_energy");
client.publish("watch", "Energy Monitor Connected!");
client.subscribe("yun_energy");
digitalWrite(LED, HIGH); delay(3000); digitalWrite(LED, LOW);
emon1.current(5, 60); // pino entrada, calibração
}
void loop() {
char buff_message[12];
float value;
client.loop();
Irms = emon1.calcIrms(1480);
if (millis() - read_energy > 10000) {
value = Irms;
dtostrf(value, 4, 5, buff_message);
client.publish("2853", buff_message); // amps
value = Irms * 115;
dtostrf(value, 4, 5, buff_message);
client.publish("2852", buff_message); // watts
read_energy = millis();
}
if ((millis() - MQTT_reconnect) > 60000) {
conn_ok = client.connected();
digitalWrite(LED, conn_ok ? HIGH : LOW);
if (!conn_ok) {
client.disconnect(); delay(5000);
while (client.connect("yun_energy") != 1) delay(4000);
digitalWrite(LED, HIGH);
client.publish("watch", "Energy Monitor reconnected");
}
MQTT_reconnect = millis();
}
}
Esquemáticos
Processo de manufatura
- Teste de Gravidez Caseiro: Funcionamento, Design e Futuro
- Dominando Interfaces em C#: Definição, Implementação e Casos Práticos
- Dominando Interfaces em Java: Conceitos, Implementação e Boas Práticas
- Como Tecnologia de Casa Inteligente Transforma Vida Cotidiana
- Construa Sistema de Automação Residencial com Raspberry Pi para Controle Remoto
- Labman Automation: Pioneira em Soluções Robóticas Personalizadas em Diversas Indústrias
- IoT e Automação Residencial: Moldando a Vida Inteligente do Amanhã
- Dominando Interfaces em C#: Contratos de Design para POO Robusta
- Automação Industrial 4.0: Revolucionando a Eficiência da Produção
- Dominando a Automação de Prensas: Técnicas, Segurança e Eficiência