Controle sua casa por voz de
qualquer lugar do planeta utilizando Inteligência Artificial. Para isso, basta
usar o Google Home, Dialogflow e Firebase. Sei que temos outros programas já
prontos que podem facilitar um projeto, mas tenho em mente aqui os engenheiros,
desenvolvedores de produtos, que querem, por exemplo, conectar o Google Home
com uma máquina de visão artificial, uma rede neural convolucional, isso é
possível com esses programas que escolhi.
Portanto, vamos fazer uma automação
com Google Home Mini via comando de voz. Além de conectar o Google Home Mini,
vamos criar Realtime Database no Firebase, setar o DialogFlow, criar Entidades
e Intenções e, por fim, setar o Google Actions.
Recursos usados
·
ESP32S WROOM (38 pinos)
·
Sensor HTU21D
·
Módulo de 4 Relés
·
Protoboard
·
Jumpers
·
2 Lâmpadas
·
Extensão de Tomadas
·
Cabos
·
Assistente Pessoal Google Home Mini
Montagem
Criar Realtime Database
Já criamos o banco de dados no
Firebase nesse vídeo:
DialogFlow
Banco utilizado no projeto:
Conectar o Google Home Mini
Antes é necessário conectar o
Google Home Mini a rede Wi-Fi e também parear com a mesma conta do google
utilizada no DialogFlow, Firebase e Google Actions.
Setup DialogFlow
DialogFlow é uma plataforma
para construir interfaces de conversação para bots, aplicativos e dispositivos.
·
Possui uma das melhores interfaces para
construção de aplicações com NLU (Natural Language Understanding)
·
É 100% grátis
Primeiro, entre no site do
DialogFlow.
Criando conta DialogFlow
Clique em “Go to Console”
Clique em “Google” e faça seu
login.
Clique em “Permitir”
Aceitei os termos de serviço e
clique em “Accept”
“Welcome to DialogFlow!”
Criar Agent
Clique em “Create Agente”
Coloque o nome do Agente,
escolha a linguagem dos diálogos e clique em “Create”
Import Intenções e Entidades
Clique na ferramenta ao lado
do nome do Agent
Clique em “Export and Import”
Selecione o arquivo .zip
escreva “IMPORT” no campo de texto e depois clique em “IMPORT”. Assim importará
um projeto pronto com as entidades e intenções já criadas.
OBS: Vou fazer um vídeo para
falar sobre criar entidades e intenções.
Uso DialogFlow
É possível adicionar novas
intenções e entidades para controle do banco de dados.
Primeiro crie uma entidade e
depois faça o controle da entidade com o uso das intenções.
Exemplo de intenção citando
entidades:
DialogFlow Fulfillment
Fulfillmente é o processo
total, que começa ao cliente falar algo, e termina até receber uma resposta.
Clique em Fulffilment.
Vamos usar o Inline Editor
para usarmos o cloud functions do Firebase.
Clique em “Disable” para
habilitar.
Código Fulfillment DialogFlow
Código Fulfillment
const functions = require('firebase-functions'); const {WebhookClient} = require('dialogflow-fulfillment'); const admin = require('firebase-admin'); admin.initializeApp({ credential: admin.credential.applicationDefault(), databaseURL: 'ws://teste-1172b.firebaseio.com/', projectId: "teste-1172b", }); process.env.DEBUG = 'dialogflow:debug'; exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => { const agent = new WebhookClient({ request, response }); console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers)); console.log('Dialogflow Request body: ' + JSON.stringify(request.body)); function handleDevice(agent) { const pegar = agent.parameters.pegar; const device = agent.parameters.devices; const status = agent.parameters.status; if(device && status){ if(device=='tudo'){ var novoLuz,novoLed,novoVentilador; if(status =='ligar' || status =='on'){ novoLuz='ligada'; novoLed='ligado'; novoVentilador='ligado'; } else{ novoLuz='desligada'; novoLed='desligado'; novoVentilador='desligado'; } admin.database().ref('automation/luz').set({ status: novoLuz, }); admin.database().ref('automation/led').set({ status: novoLed, }); admin.database().ref('automation/ventilador').set({ status: novoVentilador, }); agent.add(`Feito!`); } else{ var novo; if(device == 'luz'){ if(status == "ligar" || status == 'on') novo="ligada"; else novo="desligada"; } else{ if(status == "ligar" || status == 'on') novo="ligado"; else novo="desligado"; } admin.database().ref('automation/'+device).set({ status: novo, }); agent.add(`Feito!`); } } else{ if(device){ return admin.database().ref('/automation/'+device+'/status').once('value').then(function(snapshot) { var valor = snapshot.val(); console.log('valor ='+valor); console.log('device = '+device); if(device =="temperatura"){ console.log('entrou'); agent.add('O valor da temperatura é de '+valor+' graus Celsius'); } else{ if(device == "umidade"){ agent.add(`O valor da umidade é de `+valor+` porcento`); } else{ if(device=="luz"){ agent.add(`A luz está `+valor); } else{ if(device=="led"){ agent.add(`O led está `+valor); } else{ if(device=="ventilador"){ agent.add(`O ventilador está `+valor); } } } } } }); } else{ agent.add(`Desculpe, não entendi`); } } } // Run the proper function handler based on the matched Dialogflow intent name let intentMap = new Map(); intentMap.set('controla', handleDevice); agent.handleRequest(intentMap); });
DialogFlow Fulfillment
Coloque o código na caixa de
texto e clique em “DEPLOY”
Clique em “Integrations”
Integração com Google Assistent
Clique em Integration Settings
Action Google
Clique em “MANAGE ASSISTANT
APP” e será direcionado pra outra página do Actions on Google
Aceite os termos e clique em
“Agree and Continue”
Para fazer o deploy da sua
action é necessário cumprir todos os requisitos e preencher todos os campos
obrigatórios
Clique em “Decide how your
Actions is invoked”
Escolha o nome como deseja
chamar, escolha a voz da assistente e clique em Save
Preencha todas as informações
do “Directory Information” e clique em “Save”
Após preencher todas as
informações obrigatórias clique em “Release” no canto esquerdo da tela.
Agora para testar iremos
enviar a versão Alpha, então clique em “Submit for Alpha”
Aceite os termos e clique em
“Submit”.
Demora cerca de 3 horas para
ser aceito caso tudo esteja certo.
Simulações no Actions on Google
Clique em “Simulator” no canto
esquerdo para abrir o simulador.
Basta simular diálogos para
fazer melhorias. Mudando as intenções, entidades ou código para obter melhor
resultado em suas aplicações.
Código - Configurações
Bibliotecas necessárias
Biblioteca do Firebase
Biblioteca do sensor HTU21D
Fluxograma – Código fonte
Declarações e variáveis
#include <Arduino.h> #include "esp_task_wdt.h" // Lib do watchdog #include <IOXhop_FirebaseESP32.h> // Lib do Firebase #include <Wire.h> // Lib necessária para comunicação i2c #include <SparkFunHTU21D.h> // Lib do sensor HTU21D // Pinos do sensor (i2c - canal 1) #define SDA 21 #define SCL 22 // Objeto referente ao sensor HTU21D htudSensor; // Objeto de conexão (wire) do sensor (O sensor usará o canal 1) TwoWire wireSensor = TwoWire(1); // Intervalo de envios de temperatura e umidade (5 segundos) #define SEND_DATA_INTERVAL 5000 // Url do Firebase #define FIREBASE_HOST "NOMEDOPROJETO.firebaseio.com/" #define FIREBASE_AUTH "" // Nome da rede WiFi e senha const char *ssid = "SSIDWiFi"; const char *password = "SenhaWiFi"; // Pinos dos relés const int luzLed = 19, luz = 18, ventilador = 5; // Valores de temperatura e umidade que serão enviados para o Firebase String temp = "", humd = "";
Setup
void setup() { // Iniciamos a serial Serial.begin(115200); // Inicializamos o watchdog com 15 segundos de timeout esp_task_wdt_init(15, true); // Setamos os pinos dos relés como saída pinMode(luz, OUTPUT); pinMode(luzLed, OUTPUT); pinMode(ventilador, OUTPUT); // Iniciamos o sensor htu21Begin(); // Iniciamos o WiFi wifiBegin(); // Iniciamos a conexão com o Firebase firebaseBegin(); // Iniciamos a task de envio de temperatura e umidade xTaskCreatePinnedToCore(sendSensorData, "sendSensorData", 10000, NULL, 1, NULL, 0); }
firebaseBegin
// Função que inicia a conexão com o Firebase void firebaseBegin() { // Iniciamos a comunicação Firebase Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); // Setamos o callback (Executado a cada alteração do firebase) Firebase.stream("/", [](FirebaseStream stream) { String path, value; // Se o evento que vem do callback é de alteração "put" if(stream.getEvent() == "put") { // Obtemos os valores de path e value path = stream.getPath(); value = stream.getDataString(); // Deixamos em maiúsculo path.toUpperCase(); value.toUpperCase();
// Se for a mensagem inicial enviada pelo firebase assim que o ESP inicia sua comunicação if(value.startsWith("{\"AUTOMATION\"")) { // Sincronizamos as saídas para os relés de acordo com a mensagem recebida syncFirebase(value); Serial.println("Firebase sincronizado"); } else // Se não for uma mensagem referente a temperatura e umidade, executamos um comando e exibimos na serial if(!path.equals("/AUTOMATION/UMIDADE/STATUS") && !path.equals("/AUTOMATION/TEMPERATURA/STATUS")) Serial.println(executeCommandFromFirebase(path, value)); } }); }
SyncFirebase
// Função que ativa/desativa todos os relés de acordo com a mensagem recebida ao iniciar o Firebase (Sincronizando as saídas do ESP com os valores atuais do Firebase) void syncFirebase(String value) { /* EXEMPLO DE MENSAGEM RECEBIDA: "LED":{"STATUS":"LIGADO"},"LUZ":{"STATUS":"LIGADA"},"TEMPERATURA":{"STATUS":"26.27"},"UMIDADE":{"STATUS":"36.76"},"VENTILADOR":{"STATUS":"LIGADO"}}} */ // Obtendo a substring referente a lampada led String aux = value.substring(value.indexOf("LED")); int posVar = aux.indexOf("STATUS\":\"")+9; String status = ""; for(int i = posVar; aux.charAt(i)!='\"'; i++) status += aux.charAt(i); Serial.println("Status LED:"+status); // Sincronizando saída referente a lampada led if(status.equals("LIGADO")) digitalWrite(luzLed, LOW); else if(status.equals("DESLIGADO")) digitalWrite(luzLed, HIGH);
status = ""; // Obtendo a substring referente a lampada incandescente aux = value.substring(value.indexOf("LUZ")); posVar = aux.indexOf("STATUS\":\"")+9; for(int i = posVar; aux.charAt(i)!='\"'; i++) status += aux.charAt(i); Serial.println("Status LUZ:"+status); // Sincronizando saída referente a lampada incandescente if(status.equals("LIGADA")) digitalWrite(luz, LOW); else if(status.equals("DESLIGADA")) digitalWrite(luz, HIGH); status = ""; // Obtendo a substring referente ao ventilador aux = value.substring(value.indexOf("VENTILADOR")); posVar = aux.indexOf("STATUS\":\"")+9; for(int i = posVar; aux.charAt(i)!='\"'; i++) status += aux.charAt(i); Serial.println("Status VENTILADOR:"+status); // Sincronizando saída referente ao ventilador if(status.equals("LIGADO")) digitalWrite(ventilador, LOW); else if(status.equals("DESLIGADO")) digitalWrite(ventilador, HIGH); }
executeCommandFromFirebase
// Função que executa um comando ativando e desativando os relés String executeCommandFromFirebase(String cmd, String value) { // Retira a primeira barra if(cmd.charAt(0) == '/') cmd = cmd.substring(1); // Exibe na serial o comando e o valor Serial.println(cmd); Serial.println(value); // Caso for um comando referente a lampada incandescente if(cmd.equals("AUTOMATION/LUZ")) { // Se o valor for "LIGADA" if(value.equals("{\"STATUS\":\"LIGADA\"}")) // Ativamos o relé (lógica inversa) digitalWrite(luz, LOW); else // Caso contrário desativamos o relé // Desativamos o relé (lógica inversa) digitalWrite(luz, HIGH); }
else // Caso for um comando referente a lampada led if(cmd.equals("AUTOMATION/LED")) { if(value.equals("{\"STATUS\":\"LIGADO\"}")) // Ativamos o relé (lógica inversa) digitalWrite(luzLed, LOW); else // Caso contrário desativamos o relé digitalWrite(luzLed, HIGH); } else if(cmd.equals("AUTOMATION/VENTILADOR")) { if(value.equals("{\"STATUS\":\"LIGADO\"}")) // Ativamos o relé (lógica inversa) digitalWrite(ventilador, LOW); else // Caso contrário desativamos o relé digitalWrite(ventilador, HIGH); } else // Se não entrou em nenhum "if" acima, retornamos uma mensagem de comando inválido return "Invalid command"; // Se for um comando válido retornamos a mensagem "OK" return "OK"; }
sendSensorData
// Task que envia os dados de temperatura e umidadade para o Firebase de tempo em tempo void sendSensorData(void *p) { // Adicionamos a tarefa na lista de monitoramento do watchdog esp_task_wdt_add(NULL); while(true) { // Resetamos o watchdog esp_task_wdt_reset(); // Lê os valores do sensor readClimate(); // Se foi possível ler o sensor if(temp != "" && humd != "") { // Enviamos para o Firebase Firebase.setString("/automation/temperatura/status", temp); Firebase.setString("/automation/umidade/status", humd); Serial.println("sent"); } // Aguardamos um tempo de 5 segundos delay(SEND_DATA_INTERVAL); } }
readClimate
// Função que lê os valores do sensor void readClimate() { // Retorna 999 caso dê erro de leitura float h = htudSensor.readHumidity(); float t = htudSensor.readTemperature(); if(t < 900) temp = String(t); else temp = ""; if(h < 900) humd = String(h); else humd = ""; }
htu21Begin e WifiBegin
// Função que inicializa o sensor HTU21D void htu21Begin() { // Iniciamos a comunicação i2c wireSensor.begin(SDA, SCL, 400000); // Inicializamos o sensor htudSensor.begin(wireSensor); }
// Função que inicia o WiFi void wifiBegin() { // Iniciamos o WiFi WiFi.begin(ssid, password); Serial.println("Wifi Connecting"); // Enquanto não estiver conectado exibimos um ponto while (WiFi.status() != WL_CONNECTED) { Serial.print("."); esp_task_wdt_reset(); delay(1000); } // Exibimos "OK" Serial.println("OK"); }
Loop
void loop() { }
20 Comentários
Boa noite Fernando, acompanho todos seus canais. Parabéns pelo belo trabalho.
ResponderExcluirAté a que distância o Google Home Mini reconhece os comandos? Um TV ligada interfere muito no reconhecimento?
EU TENHO GOOGLE HOME E ELE CAPTA TUDO MESMO COM BARULHO
ExcluirBoa noite Fernando, mais um vídeo fantástico. Só uma dúvida os arquivos INO e JS estão com mensagem de erro ao tentar abrir com o winrar. Obrigado
ResponderExcluirestou afim de fazer o projeto mas falta o vídeo de inteções
ResponderExcluirShow Fernando!
ResponderExcluirObrigado Carlos !
Excluirmais uma excelente aula mestre!!!!
ResponderExcluirestava querendo muito criar um protocolo de comunicação cambus para pegar algumas informações da central dos veiculos e criar uma interface intuitiva, sei que ja existe um negocio no ml por 30 reais mas quero desenvolver!!!!! curto muito desenvolver algo ainda que seja o mais simples possivel!
Sim David,
Excluiresse espírito de desenvolver as coisas é que levam a melhoria dos produtos e novas abordagens.
A tecnologia melhora porque sempre podemos criar algo novo ou também melhorar o que existe.
continue com essa forma de pensar. Abraços !
Onde encontro o arquivo .zip que vai no intent do dialogflow?
ResponderExcluirFernando, não encontrei o arquivo automation.zip com o projeto pronto com as entidades e intenções já criadas para fazer o download no Dialogflow. Onde posso encontrá-lo?
ResponderExcluirBeleza Fernado, como posso fazer que meu device ative o dialogflow para eu escutar a mensagem? por exemplo, quero que quando a temperatura passe de 40C, ele "fale" um alerta tipo "temperatura alta, cuidado".Abraço
ResponderExcluirFernando, não encontrei o arquivo automation.zip com o projeto pronto com as entidades e intenções já criadas para fazer o download no Dialogflow. Onde posso encontrá-lo?
ResponderExcluirFernando,onde está o arquivo .zip ??
ResponderExcluirCara todo mundo já te perguntou, e como tu não respondeu, vou perguntar novamente: ONDE ESTÁ O ARQUIVO .ZIP QUE ESTÁ NO DIALOGFLOW???
ResponderExcluirboa noite fernando, se possível poderia atualizar o tutorial, algumas coisas mudaram e estou com dificuldades de realizar o tutorial.
ResponderExcluirBoa dia, alguém foi respondido? deviam postar a resposta pq tenho a mesma pergunta.
ResponderExcluirExiste algum tutorial que possamos fazer a comunicação com o firebase via cabo, usando uma shield w5500? Tenho um esp32 que conecto ao roteador via cabo, e gostaria de acessar o firebase desta forma.... alguém ?
ResponderExcluirOla acompanho muito o seu trabalho.Obrigado pela dedicação e seu prazer em compartilhar seus conhecimentos com a gente. Tô tentando fazer com que o Google ligue um dispositivo e avise que foi ligado ,após um determinado tempo ele desligue sozinho e o Google avisa..tô tentando adaptar esse projeto que vc compartilhou com a gente
ResponderExcluirGostei bastante do material, porem vejo que não existe resposta para as pessoas que estão tentando baixar os arquivos. Alguem poderia por favor disponibilizar os arquivos .rar e também o arquivo de entidade e intenções? Grato.
ResponderExcluirMuito bom! Tem muito esforço nesse projeto. Misericórdia...Bom demais..
ResponderExcluir