Resumindo, este projeto possui duas características. Primeiro, a mesa é conectada do Google Smart Home ao Heroku usando comandos de voz e, segundo: o Heroku e a própria mesa se comunicam usando o protocolo MQTT da Internet das Coisas. MQTT é uma boa solução para a Internet das Coisas, bem como para superar alguns outros obstáculos que teremos que enfrentar.
Em primeiro lugar, direi que fiz este projeto apenas por diversão. Espero que você ache o artigo interessante e motive você a encontrar tempo para fazer algo por si mesmo.

Parte de hardware
A primeira e provavelmente a mais difícil parte do trabalho é redesenhar a mesa. Em uma vida passada, a mesa tinha uma alça destacável, que ficava na borda da mesa. A princípio pensei em prender algo no orifício da alça sem ter que interferir no desenho da mesa. Comprei vários drives para descobrir como prender o motor à mesa, mas sem sucesso. Então surgiu a ideia: uma haste percorrendo o comprimento de toda a mesa, que conectaria suas pernas de modo que elas subissem e caíssem ao mesmo tempo. Se eu prender uma unidade que se encaixa na haste, posso usar uma correia para conectar a haste ao motor. Também seria possível equipar a mesa com um motor sem muita interferência em seu design.
A importância do torque
Depois de pedir a transmissão e a correia corretas, comecei a pesquisar na Amazon por um motor de alto torque. E - oh, milagre! - Encontrei muitos motores adequados! Ou assim me pareceu ... Tendo comprado um pequeno motor, esperei cerca de um mês pela sua chegada da China. Fiquei tão animado quando o motor finalmente chegou! Mal podia esperar o fim de semana para finalmente juntar tudo e ter minha mesa motorizada.
As coisas não correram conforme o planejado. Passei o dia abrindo um buraco para uma haste no painel de metal da mesa. Naquela época, eu só tinha ferramentas manuais, então o processo demorou mais do que eu esperava. No final do dia, terminei de montar a mesa e estava pronto para experimentá-la.
Liguei o motor, a tensão na fonte de alimentação do meu desktop e ... nada aconteceu. Alguns momentos depois, o motor começou a girar e os dentes da correia adquirida estalaram. Aprendi duas lições com isso: a correia obviamente não está fazendo seu trabalho, e a palavra "Motor em alto torque" não significa "Eu posso levantar qualquer coisa". A segunda lição é observar o tamanho do motor em comparação com seus dedos. O meu era minúsculo!

À esquerda da foto está um motor e um cinto. Acima à direita está um motor preso à mesa (você verá mais sobre isso mais tarde). No canto inferior direito, o motor está posicionado na mesa.
Motor adequado
Para selecionar o motor correto, foi necessário calcular quanto torque é necessário para elevar o tampo da mesa. Fiquei surpreso com a facilidade de fazer isso.
O torque é a força multiplicada pelo comprimento do braço da alavanca.
Bem, eu tinha um braço de alavanca (esta é uma alça de mesa), bastava calcular a força que faria girar facilmente o braço de alavanca. Eu carreguei a mesa amarrando a jarra de leite na alça e gradualmente adicionando água à jarra até que a alavanca começou a girar. Girando a alça para cima com o jarro cheio, garanti que o peso girasse a alça facilmente. Descobri que o braço de alavanca tem 11 cm de comprimento e a força necessária é de 4 libras. Substituindo esses números na fórmula, descobri que o motor deve produzir um torque de pelo menos 19,95 kg / cm. E ele começou a procurá-lo.
Decidi refazer a tabela de forma irreversível. Eu sabia que a haste que passava pelo meio da mesa era oca. Depois de procurar um motor de eixo duplo, pude cortar a haste e remontá-la com o motor no meio. Ao adquirir dois motores com torque de 20 kg / cm, assegurei-me de que há torque suficiente para levantar a mesa.
Em outro lindo sábado, desmontei minha mesa em quatro pedaços, serrando os eixos do motor para que pudessem ser usados na montagem da haste. Empurrei mais buracos no metal para encaixar os motores. Desta vez não havia correia: os motores eram conectados diretamente à haste, os orifícios eram bastante grandes. Quando a noite caiu, remontei a mesa e carreguei-a com material de escritório.

As duas fotos de cima são motores totalmente montados na mesa. As duas fotos de baixo são uma haste integrada que percorre o comprimento da mesa com a ajuda de motores.
Eu conectei os motores e os conectei à fonte de alimentação. Ligando a energia, vi a mesa se mover! Desta vez, fiquei mais confiante, pois dimensionei corretamente os motores. Dobrei a potência dos motores por uma questão de confiança, mas foi incrível vê-los se movendo!
No entanto, deixe-me esclarecer que a mesa estava lenta. Filmei um vídeo para mostrar a um amigo como funciona a mesa, mas ele teve que ligar a aceleração do tempo no vídeo para não assistir por 5 minutos enquanto a mesa mudava de posição.
A rotatividade é importante. Versão final
Finalmente percebi que tudo se resume a duas coisas: torque e rpm. Era necessário encontrar um motor com um número suficiente de rotações em um torque já conhecido.
Não foi tão difícil. Embora eu não tenha encontrado um motor de eixo duplo, encontrei uma caixa de engrenagens retangular que converte um motor de eixo único em um motor de eixo duplo.
Resumindo, o mês seguinte foi um mês de espera por uma caixa de câmbio da China e, no sábado seguinte, depois de esperar, eu tinha uma mesa se movendo na velocidade certa.

O último motor em si está à esquerda e o motor instalado está à direita. Pouco hardware e muito software.
Não fiquei feliz com a enorme fonte de alimentação na minha mesa, mentindo apenas para controlar a altura do tampo da mesa. Além disso, para mudar a posição da mesa de um para o outro e vice-versa, troquei os fios. Pequeno problema, mas o projeto foi feito para, idealmente, apenas pressionar um botão e ter várias predefinições de altura.
Bluetooth
A primeira solução foi adicionar o Bluetooth à mesa. No final do dia, parece que quase todos os dispositivos da casa têm Nluetooth, e o telefone parece ser uma interface de controle conveniente para algo como minha mesa.
Então agora eu tenho uma placa controladora de motor, uma placa bluetooth NRF52 nórdica, sensores de distância e comecei a mexer no firmware do controlador.
No final do artigo, deixarei links para software e firmware que escrevi para o projeto. Sinta-se à vontade para comentar sobre o código: Não sou um desenvolvedor profissional de firmware e gostaria de receber algumas orientações.
Como uma introdução rápida: ESP32 é escrito em C ++ usando bibliotecas Arduino para interagir com o aplicativo Terminal BLE no telefone. Instalar e configurar o BLE é bastante complexo. Primeiro, você precisa criar todas as características para os valores que deseja controlar por meio do BLE. Pense em uma característica como uma variável em seu código. BLE envolve uma variável em vários manipuladores para obter e definir o valor dessa variável.
As características são então empacotadas em um serviço com seu próprio UUID, o que torna o serviço único e identificável no aplicativo. Por fim, você deve adicionar este serviço à carga útil do anúncio para que seu serviço possa ser descoberto pelo dispositivo. Quando um dispositivo remoto se conecta ao seu serviço e envia dados por meio das especificações, a tabela reconhece que o usuário deseja ajustar a altura para uma predefinição diferente e começa a se mover.
Para ajuste de altura, a bancada possui um sensor TFMini-S LiDAR que detecta a altura atual. Este é um sensor divertido: é chamado de LiDAR quando na verdade é um laser. Ele usa ótica e LEDs para determinar o tempo de vôo da radiação infravermelha. De uma forma ou de outra, o sensor determina a altura da mesa. A placa de controle então detecta a diferença entre a altitude atual e a altitude solicitada e dá partida no motor, que gira na direção desejada. Algumas das partes principais do código estão abaixo, mas você pode ver o arquivo completo aqui .
void setup()
{
Serial.begin(115200);
Serial2.begin(TFMINIS_BAUDRATE);
EEPROM.begin(3); // used for saving the height presets between reboots
tfminis.begin(&Serial2);
tfminis.setFrameRate(0);
ledcSetup(UP_PWM_CHANNEL, PWM_FREQUENCY, PWM_RESOLUTION);
ledcAttachPin(UP_PWM_PIN, UP_PWM_CHANNEL);
ledcSetup(DOWN_PWM_CHANNEL, PWM_FREQUENCY, PWM_RESOLUTION);
ledcAttachPin(DOWN_PWM_PIN, DOWN_PWM_CHANNEL);
state_machine = new StateMachine();
state_machine->begin(*t_desk_height, UP_PWM_CHANNEL, DOWN_PWM_CHANNEL);
BLEDevice::init("ESP32_Desk");
...
BLEServer *p_server = BLEDevice::createServer();
BLEService *p_service = p_server->createService(BLEUUID(SERVICE_UUID), 20);
/* ------------------- SET HEIGHT TO PRESET CHARACTERISTIC -------------------------------------- */
BLECharacteristic *p_set_height_to_preset_characteristic = p_service->createCharacteristic(...);
p_set_height_to_preset_characteristic->setCallbacks(new SetHeightToPresetCallbacks());
/* ------------------- MOVE DESK UP CHARACTERISTIC ---------------------------------------------- */
BLECharacteristic *p_move_desk_up_characteristic = p_service->createCharacteristic(...);
p_move_desk_up_characteristic->setCallbacks(new MoveDeskUpCallbacks());
/* ------------------- MOVE DESK UP CHARACTERISTIC ---------------------------------------------- */
BLECharacteristic *p_move_desk_down_characteristic = p_service->createCharacteristic(...);
p_move_desk_down_characteristic->setCallbacks(new MoveDeskDownCallbacks());
/* ------------------- GET/SET HEIGHT 1 CHARACTERISTIC ------------------------------------------ */
BLECharacteristic *p_get_height_1_characteristic = p_service->createCharacteristic(...);
p_get_height_1_characteristic->setValue(state_machine->getHeightPreset1(), 1);
BLECharacteristic *p_save_current_height_as_height_1_characteristic = p_service->createCharacteristic(...);
p_save_current_height_as_height_1_characteristic->setCallbacks(new SaveCurrentHeightAsHeight1Callbacks());
/* ------------------- GET/SET HEIGHT 2 CHARACTERISTIC ------------------------------------------ */
...
/* ------------------- GET/SET HEIGHT 3 CHARACTERISTIC ------------------------------------------ */
...
/* ------------------- END CHARACTERISTIC DEFINITIONS ------------------------------------------ */
p_service->start();
BLEAdvertising *p_advertising = p_server->getAdvertising();
p_advertising->start();
xTaskCreate(
updateDeskHeight, // Function that should be called
"Update Desk Height", // Name of the task (for debugging)
1024, // Stack size
NULL, // Parameter to pass
5, // Task priority
NULL // Task handle
);
}
Há muito mais coisas acontecendo no arquivo, mas este código tem contexto suficiente para entender o que está acontecendo. Observe que criamos e configuramos todos os retornos de chamada BLE para todas as características, incluindo movimento manual, definição e recuperação de valores predefinidos e, o mais importante, alinhando a tabela com a predefinição.
A imagem abaixo mostra a interação com as características de ajuste da altura da mesa. A última peça do quebra-cabeça é uma máquina de estados que conhece a altura da mesa atual, a altura desejada pelo usuário e trabalha com esses dois valores.
Então, finalmente, eu tinha uma mesa que fazia o que eu queria. Eu poderia salvar a altura em predefinições e extrair as alturas da memória para colocar a mesa em minhas posições favoritas. Eu usei o Terminal BLEno meu telefone e computador, para que eu pudesse enviar mensagens brutas para minha mesa e monitorar sua posição. Funcionou, mas eu sabia que a batalha com a BLE estava apenas começando.

Interface bluetooth nua ... Faltava apenas aprender a escrever aplicativos para iOS ...
Depois de tudo isso, minha esposa disse algo que mudou todo o projeto: "E se você controlar a voz?"
Além de ser legal e adicionar um novo dispositivo à lista do Google Assistant, não havia necessidade de escrever um aplicativo iOS para controlar a mesa. E você não precisava mais alcançar o telefone para ajustar a altura. Outra pequena vitória!
Adicionando a Internet das Coisas
Agora vamos falar sobre como atualizar sua mesa para controle de voz via Google Smart Home e como torná-la compatível com Wi-Fi.
Adicionar Wi-Fi foi muito fácil. Substituí o microcontrolador Nordic NRF52 por um ESP32 com WiFi integrado. A maior parte do software era portátil porque foi escrito em C ++ e ambos os dispositivos podiam ser programados com Platform.IO e as bibliotecas do Arduino, incluindo os tfmini-s que escrevi para medir a altura da mesa atual.
A arquitetura do sistema de interação da mesa com o Google Smart Home é mostrada a seguir. Vamos falar sobre a interação entre mim e o Google.

Portanto, o Bluetooth foi ativado. É hora de descobrir como interagir com o Google Smart Home. Esta tecnologia controlava a casa usando Smart Home Actions . O que é interessante sobre suas ações é que o serviço atua como um servidor OAuth2, não um cliente. A maior parte do trabalho feito com o servidor foi implementar um aplicativo OAuth2 Node.js Express que chega ao Heroku e se comunica como um proxy entre o Google e minha mesa.
Tive sorte: houve uma implementação de servidor decente usando duas bibliotecas. A primeira biblioteca, node-oauth2-server, foi encontrada aqui . A segunda biblioteca express-oauth-server para conexão Express foi encontrada aqui .
const { Pool } = require("pg");
const crypto = require("crypto");
const pool = new Pool({
connectionString: process.env.DATABASE_URL
});
module.exports.pool = pool;
module.exports.getAccessToken = (bearerToken) => {...};
module.exports.getClient = (clientId, clientSecret) => {...};
module.exports.getRefreshToken = (bearerToken) => {...};
module.exports.getUser = (email, password) => {...};
module.exports.getUserFromAccessToken = (token) => {...};
module.exports.getDevicesFromUserId = (userId) => {...};
module.exports.getDevicesByUserIdAndIds = (userId, deviceIds) => {...};
module.exports.setDeviceHeight = (userId, deviceId, newCurrentHeight) => {...};
module.exports.createUser = (email, password) => {...};
module.exports.saveToken = (token, client, user) => {...};
module.exports.saveAuthorizationCode = (code, client, user) => {...};
module.exports.getAuthorizationCode = (code) => {...};
module.exports.revokeAuthorizationCode = (code) => {...};
module.exports.revokeToken = (code) => {...};
Em seguida, vem a configuração do próprio aplicativo Express. Abaixo estão os endpoints necessários para um servidor OAuth, mas você pode ler o arquivo completo aqui.
const express = require("express");
const OAuth2Server = require("express-oauth-server");
const bodyParser = require("body-parser");
const cookieParser = require("cookie-parser");
const flash = require("express-flash-2");
const session = require("express-session");
const pgSession = require("connect-pg-simple")(session);
const morgan = require("morgan");
const { google_actions_app } = require("./google_actions");
const model = require("./model");
const { getVariablesForAuthorization, getQueryStringForLogin } = require("./util");
const port = process.env.PORT || 3000;
// Create an Express application.
const app = express();
app.set("view engine", "pug");
app.use(morgan("dev"));
// Add OAuth server.
app.oauth = new OAuth2Server({
model,
debug: true,
});
// Add body parser.
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(express.static("public"));
// initialize cookie-parser to allow us access the cookies stored in the browser.
app.use(cookieParser(process.env.APP_KEY));
// initialize express-session to allow us track the logged-in user across sessions.
app.use(session({...}));
app.use(flash());
// This middleware will check if user's cookie is still saved in browser and user is not set, then automatically log the user out.
// This usually happens when you stop your express server after login, your cookie still remains saved in the browser.
app.use((req, res, next) => {...});
// Post token.
app.post("/oauth/token", app.oauth.token());
// Get authorization.
app.get("/oauth/authorize", (req, res, next) => {...}, app.oauth.authorize({...}));
// Post authorization.
app.post("/oauth/authorize", function (req, res) {...});
app.get("/log-in", (req, res) => {...});
app.post("/log-in", async (req, res) => {...});
app.get("/log-out", (req, res) => {...});
app.get("/sign-up", async (req, res) => {...});
app.post("/sign-up", async (req, res) => {...});
app.post("/gaction/fulfillment", app.oauth.authenticate(), google_actions_app);
app.get('/healthz', ((req, res) => {...}));
app.listen(port, () => {
console.log(`Example app listening at port ${port}`);
});
Existe uma grande quantidade de código, mas explicarei os pontos principais. As duas rotas OAuth2 usadas para o servidor são / oauth / token e / oauth / authorize. Eles são usados para receber um novo token ou atualizar tokens expirados. Em seguida, você precisa fazer o servidor responder à ação do Google. Você notará que o endpoint / gaction / fulfillment está apontando para um objeto
google_actions_app
.
O Google envia solicitações ao seu servidor em um formato específico e fornece uma biblioteca para ajudar a processar essas solicitações. Abaixo estão as funções necessárias para se comunicar com o Google, e todo o arquivo está aqui. Finalmente, há o ponto de extremidade / healthz, que abordarei no final do artigo.
O ponto de extremidade / gaction / fulfillment usa um middleware chamado app.oauth.authenticate (), o trabalho árduo de colocar o servidor OAuth2 em funcionamento era fazer com que esse middleware funcionasse. Ele verifica se o token do portador fornecido a nós pelo Google se refere a um usuário existente e não expirou. A rota então envia a solicitação e a resposta ao objeto
google_actions_app
.
O Google envia solicitações ao seu servidor em um formato específico e fornece uma biblioteca para ajudar a analisar e processar essas solicitações. Abaixo estão as funções de que você precisa para entrar em contato com o Google, mas você pode ver o arquivo completo aqui .
const { smarthome } = require('actions-on-google');
const mqtt = require('mqtt');
const mqtt_client = mqtt.connect(process.env.CLOUDMQTT_URL);
const model = require('./model');
const { getTokenFromHeader } = require('./util');
mqtt_client.on('connect', () => {
console.log('Connected to mqtt');
});
const updateHeight = {
"preset one": (deviceId) => {
mqtt_client.publish(`/esp32_iot_desk/${deviceId}/command`, "1");
},
"preset two": (deviceId) => {
mqtt_client.publish(`/esp32_iot_desk/${deviceId}/command`, "2");
},
"preset three": (deviceId) => {
mqtt_client.publish(`/esp32_iot_desk/${deviceId}/command`, "3");
},
};
const google_actions_app = smarthome({...});
google_actions_app.onSync(async (body, headers) => {...});
google_actions_app.onQuery(async (body, headers) => {...});
google_actions_app.onExecute(async (body, headers) => {...});
module.exports = { google_actions_app };
Quando você adiciona uma ação inteligente à sua conta do Google, o Google emite uma solicitação de sincronização. Esta solicitação permite que você saiba quais dispositivos estão disponíveis em sua conta. Em seguida, vem uma consulta de pesquisa: o Google consulta seus dispositivos para determinar seu estado atual.
Ao adicionar uma ação do Google pela primeira vez à sua conta Smart Home, você notará que o Google primeiro envia uma solicitação de sincronização e, em seguida, uma solicitação de pesquisa para obter uma visão holística de seus dispositivos. O último é um pedido para cumprir o que o Google diz aos seus dispositivos para fazerem algo.
"Recursos" (característica) do dispositivo Google Smart Home
O Google usa recursos específicos do dispositivo para fornecer elementos de interface do usuário para controlar seus dispositivos para o Google e para criar modelos de comunicação de controle de voz. Alguns dos recursos incluem as seguintes configurações: ColorSetting, Modes, OnOff e StartStop. Demorei um pouco para decidir qual recurso funcionaria melhor em meu aplicativo, mas depois escolhi os modos.
Você pode pensar nos modos como uma lista suspensa onde um dos N valores predefinidos ou, no meu caso, predefinições de altura são selecionados. Chamei meu modo de "altura" e os valores possíveis são "predefinição um", "predefinição dois" e "predefinição três". Isso me permite controlar minha mesa dizendo: “Ei Google, defina a altura da minha mesa para predefinir um”, e o Google enviará uma solicitação de execução correspondente ao meu sistema. Você pode ler mais sobre os recursos dos dispositivos do Google aqui .
Projeto em ação
Finalmente, o Google Smart Home e meu computador começaram a se comunicar. Antes disso, eu usava o ngrok para executar o servidor Express localmente . Agora que meu servidor finalmente está funcionando bem, é hora de disponibilizá-lo para o Google a qualquer momento. Portanto, foi necessário hospedar o aplicativo no Heroku - um provedor de PaaS que facilita a implantação e o gerenciamento de aplicativos.
Uma das principais vantagens do Heroku é o modo add-on. Com add-ons, é muito fácil adicionar servidores CloudMQTT e Postgres ao seu aplicativo. Outro benefício de usar o Heroku é sua facilidade de montagem e implantação. O Heroku detecta automaticamente qual código você está usando e o constrói / implanta para você. Você pode encontrar mais detalhes lendo sobre os Buildpacks do Heroku . No meu caso, sempre que envio código para o git Heroku remoto, ele instala todos os meus pacotes, remove todas as dependências de desenvolvimento e implanta o aplicativo, tudo com um simples comando "git push heroku main".
Em apenas alguns cliques, CloudMQTT e Postgres estavam disponíveis para meu aplicativo, e eu só precisei usar algumas variáveis de ambiente para integrar esses serviços com meu aplicativo. Heroku não pediu dinheiro. No entanto, CloudMQTT é um complemento de terceiros por US $ 5 por mês.
Eu acredito que a necessidade de Postgres é autoexplicativa, mas CloudMQTT merece mais atenção.
Da Internet para uma rede privada. O jeito difícil
Existem várias maneiras de fornecer acesso a um aplicativo ou, no meu caso, a um dispositivo IoT. A primeira é abrir uma porta na minha rede doméstica para trazer o dispositivo para a Internet. Nesse caso, meu aplicativo Heroku Express enviará uma solicitação ao meu dispositivo usando o endereço IP público. Isso exigiria que eu tivesse um IP estático público, bem como um IP estático para o ESP32. O ESP32 também teria que atuar como um servidor HTTP e ouvir as instruções do Heroku o tempo todo. Essa é uma grande sobrecarga para um dispositivo que recebe instruções várias vezes ao dia.
O segundo método é denominado "furador". Com ele, você pode usar um servidor externo de terceiros para acessar o dispositivo à Internet sem a necessidade de encaminhamento de porta. Seu dispositivo basicamente se conecta a um servidor que configura uma porta aberta. Em seguida, outro serviço pode se conectar diretamente ao seu dispositivo interno, obtendo uma porta aberta do servidor externo. Finalmente, ele se conecta diretamente ao dispositivo usando esta porta aberta. A abordagem pode ou não ser totalmente correta: eu apenas li parte do artigo sobre isso.
Há muita coisa acontecendo dentro do "furo", e eu não entendo totalmente o que está acontecendo. No entanto, se você estiver interessado, existem alguns artigos interessantes que explicam mais. Aqui estão dois artigos que li para entender melhor o furador: Wikipediae um artigo do MIT de Brian Ford e outros .
Da Internet para uma rede privada via IoT
Não fiquei muito feliz com essas soluções. Eu conectei muitos dispositivos inteligentes à minha casa e nunca tive que abrir uma porta no meu roteador, então não houve encaminhamento de porta. Além disso, fazer furos parece muito mais difícil do que o que estou procurando e é mais adequado para redes P2P. Como resultado de pesquisas adicionais, descobri o MQTT e aprendi que é um protocolo para IoT. Ele tem algumas vantagens, como baixo consumo de energia, tolerância a falhas configurável e não requer encaminhamento de porta. MQTT é um protocolo de publicador / assinante, o que significa que uma tabela é um assinante de um tópico específico e um aplicativo Heroku é o publicador desse tópico.
Assim, o Google entra em contato com o Heroku, essa solicitação é analisada para determinar o dispositivo solicitado e seu novo estado ou modo. O aplicativo Heroku então publica uma mensagem para o servidor CloudMQTT implantado como um complemento para o Heroku, instruindo a tabela a navegar até a nova predefinição. Por fim, a mesa se inscreve no tópico e recebe uma mensagem postada pelo aplicativo Heroku, por fim, a mesa ajusta sua altura conforme solicitado! No arquivo googleactionsapp, você notará que há uma função updateHeight que publica um número MQTT para um ID de dispositivo específico. É assim que o aplicativo Heroku publica uma solicitação de movimentação de tabela para MQTT.
A última etapa é receber a mensagem no ESP32 e mover a mesa. Vou mostrar alguns dos destaques do código da tabela abaixo, e todo o código-fonte está aqui .
void setup()
{
Serial.begin(115200);
...
tfminis.begin(&Serial2);
tfminis.setFrameRate(0);
...
state_machine = new StateMachine();
state_machine->begin(*t_desk_height, UP_PWM_CHANNEL, DOWN_PWM_CHANNEL);
setup_wifi();
client.setServer(MQTT_SERVER_DOMAIN, MQTT_SERVER_PORT);
client.setCallback(callback);
...
}
Quando a mesa é carregada, primeiro iniciamos a comunicação entre o TFMini-S - o sensor de distância - para obter a altura atual da mesa. Em seguida, configuramos a máquina de estado para o movimento da mesa. A máquina de estado recebe comandos por meio de MQTT e é então responsável por combinar a solicitação do usuário com a altura real da mesa lida pelo sensor de distância. Finalmente, conectamos à rede Wi-Fi, conectamos ao servidor MQTT e configuramos um retorno de chamada para todos os dados recebidos no tópico MQTT no qual estamos inscritos. Abaixo vou mostrar a função de retorno de chamada.
void callback(char *topic, byte *message, unsigned int length)
{
...
String messageTemp;
for (int i = 0; i < length; i++)
{
messageTemp += (char)message[i];
}
if (messageTemp == "1") {
state_machine->requestStateChange(ADJUST_TO_PRESET_1_HEIGHT_STATE);
}
if (messageTemp == "2") {
state_machine->requestStateChange(ADJUST_TO_PRESET_2_HEIGHT_STATE);
}
if (messageTemp == "3") {
state_machine->requestStateChange(ADJUST_TO_PRESET_3_HEIGHT_STATE);
}
...
}
A máquina de estado registra a mudança de estado recebida no tópico MQTT. Em seguida, ele processa o novo estado no loop principal.
void loop()
{
if (!client.connected())
{
reconnect();
}
client.loop();
state_machine->processCurrentState();
}
O loop principal faz várias coisas: primeiro, ele se reconecta ao servidor MQTT se ainda não estiver conectado. Em seguida, ele processa todos os dados recebidos por meio do tópico MQTT. Finalmente, o código funciona movendo a mesa para o local desejado solicitado no tópico MQTT.
Isso é tudo! A mesa é totalmente controlada por voz e se comunica com o Google para receber comandos!
Notas Recentes
O último endpoint que não mencionei é o endpoint / healthz. Isso se deve ao fato de que o Google espera uma resposta bastante rápida e carregar o aplicativo Heroku em todas as solicitações não funciona no meu caso. Eu configurei um serviço de ping para executar ping no endpoint / healthz a cada minuto para manter o serviço íntegro e pronto para responder. Se você pretende fazer algo assim, lembre-se de que todas as horas livres do estande serão dedicadas a isso. Está tudo bem agora: este é o único aplicativo usado no Heroku. Além disso, por US $ 7 por mês, você pode atualizar para o plano Hobby do Heroku, que mantém o aplicativo em execução.
Construir um dispositivo IoT exige muita sobrecarga no início. Eu projetei o hardware, construí o esquema de controle, configurei o servidor MQTT, escrevi o servidor Express OAuth2 e aprendi como interagir com o Google Smart Home por meio de ações. A sobrecarga inicial foi enorme, mas sinto que realizei muito! Sem mencionar que o MQTT Server, o Express OAuth2 Application Server e o Google Smart Home Actions podem ser usados para outro projeto. Estou interessado em casas inteligentes e posso tentar expandir meu repertório de dispositivos IoT para incluir sensores que rastreiam o que está acontecendo em minha casa e relatam por meio do MQTT. Sensores para monitoramento de solo, temperatura e sensores de luz serão muito interessantes para monitorar e analisar.
Qual é o próximo?
As alturas das bancadas agora são medidas não confiáveis, na melhor das hipóteses. Estou usando em geral um sensor de distância infravermelho TFMini-S funcional. Foi notado que a altura da mesa muda ligeiramente durante o dia quando a iluminação ambiente da sala muda. Encomendei um sensor de ângulo de rotação para contar as revoluções de uma haste na mesa. Isso deve me dar um movimento mais preciso a qualquer hora do dia. Também tenho acesso ao servidor que hospedo no porão. Nele eu posso explorar meu próprio servidor Mosquitto MQTT, aplicativos Node-RED e Express OAuth2 se eu quiser hospedar algo sozinho. Finalmente, agora todos os eletrônicos estão bem na minha mesa. Pretendo organizar os dispositivos para que tudo fique bem e arrumado!
Obrigado por ler o artigo! Por conveniência, forneço todos os links.
- Torque Calculator
- 90 degree right angle gear box
- BLE Terminal
- Platform.IO
- TFMini-S Arduino Driver
- Google Smart Home Actions
- Node OAuth2 Server
- Express OAuth2 Server
- ESP32 IoT Desk Server model.js
- ESP32 IoT Desk Server index.js
- ESP32 IoT Desk Server google_actions.js
- Google Smart Home Device Traits
- NGROK
- ESP32 IoT Desk Firmware
- Node-RED
- Heroku
- Heroku Hobby Plan
- Heroku Buildpacks
- Wikipedia Hole Punching
- MIT Paper on Hole Punching by Bryan Ford et al.
