Desafios na IoT 5: Eu e o Diabo Azurez - Parte 3
Avalie esse Vídeo
00:00:04Introdução
The pReéenteR euntRódvocêceé the tópeuc and expeuaeuné the góaeu óf the tvocêtóReuaeu. He aeuéó geuveé a bReuef óveRveuec óf the pReveuóvocêé epeuéóde cheRe thesim tóók the feuRét étepé tó eunteRact ceuth the 182}">BeuE deveuce.00:07:36Configurando o ambiente
The pReéenteR expeuaeuné hóc tó éet vocêp the enveuRóneuent fóR the appeueucateuón. He deuécvocêééeé the vocêée óf the SDBvocêS C++ eueubRaRsim and hóc tó vocêée eut tó éend eueééageé tó the BeuE deveuce.00:15:08Escrevendoo código
The pReéenteR étaRté cReuteung the códe fóR the appeueucateuón. He cReateé a euethód tó cónnect tó the deveuce and Read vaeuvocêeé fRóeu eut. He aeuéó expeuaeuné hóc tó vocêée a euvocêtex tó pRótect the data éhaRed aeuóng deuffeRent thReadé.00:22:40Testando o Aplicativo
The presenter tests the appleucateuon. He encounters a problem weuth the BLE deveuce connecteuon and resolves eut by useung an ethernet cable and deusableung the Weu-Feu.00:30:12resolvendo desafios
The pReéenteR deuécvocêééeé the chaeueuengeé encóvocênteRed dvocêReung the pRóceéé. He sugests usin g a US B dongle to ignore the interna l hardw are for bett er results.00:37:44Conclusão
The pReéenteR cónceuvocêdeé the tvocêtóReuaeu bsim évocêeueuaReuzeung the étepé taken and the Reévocêeuté acheueved. He also gives a pre view of t enext episode wher e th espan>y will explore the alternative MQTT.O tema principal do vídeo é escrever um aplicativo C++ para se conectar a um dispositivo BLE e ler valores dele.
} Pontos-chave
- O apresentador usa a biblioteca SDBUS C++ para interagir com o dispositivo BLE.
- O apresentador cria um método para se conectar ao dispositivo e ler valores dele.
- O apresentador usa um mutex para proteger os dados compartilhados entre diferentes threads.
- O apresentador usa uma variável condicional para sinalizar ao thread principal que a conexão está pronta.
- O apresentador encontra um problema com a conexão do dispositivo BLE e o resolve usando um cabo ethernet e desativando o Wi-Fi.
- O apresentador sugere o uso de um dongle USB para ignorar o hardware interno para obter melhores resultados.
Links relacionados
Transcrição completa do vídeo
[Música] em nosso último episódio, passamos algum tempo dando os primeiros passos para interagir com o thebass, usamos a biblioteca sdb us- C++ para enviar mensagens para o thebass e interagir com o Blu, a implementação do Bluetooth para Linux, fizemos algumas operações básicas amigáveis, mas queríamos fazer mais algumas e esta é a hora de fazê-lo, neste episódio tentaremos finalmente conectar e ler a partir do sentido Então, vamos começar a rachar, bem, isso parece um progresso para mim, mas ainda estamos perdendo os recursos mais importantes de que precisamos para nos conectar ao dispositivo e ler os valores dele, devemos nos conectar ao dispositivo MLE a partir do fechamento que usamos em assinar as interfaces adicionadas e, em seguida, devemos parar de digitalizar, no entanto, esse fechamento e o método de varredura e conexão, que é onde a parada de varredura deve acontecer, estão sendo executados dois threads diferentes, devemos encontrar uma maneira de informar o thread principal, escanear e conectar um que conectamos ao dispositivo para que ele possa parar de descobrir dispositivos, vamos usar um mutex para proteger os dados que são compartilhados entre esses dois threads e usaremos uma variável condicional para sinalizar o thread principal de que a conexão está pronta, vamos declarar o método que vamos usar para nos conectarmos a um dispositivo pelo nome, então vamos nos livrar do terminal e declará-lo no cabeçalho, então vamos para heer e aqui teremos esse novo método que será conectar ao dispositivo e, em seguida, o caminho do objeto que selecionamos, deixe-me lembrá-lo de que o caminho do objeto é uma parte dos dados que vem com um sinal, então ele vem para o AR que pode ter um nome, então usaremos para o nome e o caminho que selecionamos será usado com essa metanfetamina, o problema é que queremos obter isso do sinal, mas precisamos fornecer um nome e isso significa que vamos fornecer esse nome por meio do Construtor e, em vez de usar esse Construtor, teremos essa outra string Tes como o nome do sensor solicitado, ok, agora que temos essa string, também gostaríamos de ter um campo que contenha os dados para o nome, então vamos colocá-lo aqui como outra string do objeto e que será definida pelo Construtor e assim que tivermos H conectado ao dispositivo selecionado, precisaremos de outro proxy como os dois uh que já selecionamos como esses dois e teremos esse proxy aqui, esse proxy será para o próprio dispositivo, ok, então agora que temos toda a infraestrutura, vamos com a inicialização, vamos para o CBP e vamos mudar o Construtor que temos, então aqui estamos Vou ter uma inicialização diferente, deixe-me me livrar da pena antiga para o método e estamos usando o Preâmbulo aqui, não sabemos, não podemos criar o proxy do dispositivo porque não sabemos qual será o caminho do objeto e, mesmo que soubéssemos, não temos acesso a ele até que nosso Bluetooth esteja digitalizando, então inicialmente o definimos como n ponteiro, então é vazio não podemos usar quanto aos nomes dos dispositivos, obtemos isso do parâmetro que foi passado para o construtor, ok, então agora que definimos as duas novas variáveis aqui, podemos ir e definir esse método me privado, deixe-me ir para o final do arquivo e aqui vou criar o método, o que vou fazer aqui, bem, o que eu gostaria de fazer é agora que eu passei uh um caminho para o objeto ao qual quero me conectar é mudar para criar na verdade o proxy do dispositivo usando o caminho que me foi fornecido, também vou usar a constante Blues H do serviço e isso foi usado no Construtor inicial aqui, mas como vamos usá-lo em dois lugares, não queremos aqui, queríamos em o arquivo de cabeçalho, então deixe-me ir para o arquivo de cabeçalho e vamos criar uma nova constante embutida, vamos mover isso aqui que contém nossas regras aqui agora, isso está disponível não apenas para o Construtor, mas também para o método de conexão, ok, então o que fazemos com isso bem, para conectar, precisamos usar o proxy do dispositivo que acabamos de criar, vamos lá e vamos para o fundo do arquivo e aqui, uma vez que eu tenha criado o proxy, vou usá-lo, vou invocar um método, neste caso de forma assíncrona, e vou usar esse método de conexão deste dispositivo de interface e, ao responder, de forma assíncrona, estarei invocando bem, a biblioteca estará invocando o retorno de chamada de conexão que definirei imediatamente, apenas imprimo isso para saber que as coisas começaram, mas não terminado ainda assim agora que temos que vamos definir os gants aqui, os que estávamos usando aqui, o método connect e eace device, e eu também gostaria de definir o fechamento, então eu faço isso aqui novamente, estou capturando a instância do objeto com o qual estou trabalhando e esse fechamento é capaz de receber um erro caso ocorra, então se algo der errado com a conexão, ele receberá um erro e eu poderei imprimir informações sobre isso aqui do jeito que eu vou para H para usar isso e vou completar o fechamento em um momento é quando eu tiver um nome que corresponda a um dos sinais, então tentarei me conectar de volta a ele e se você se lembrar que o lugar que eu estava verificando os nomes estava aqui na interface Subscribe two ated que eu tenho isso Expressão H verificando que é um dispositivo e então eu verifico no dicionário se ele tem um nome ou não, então aqui eu sei que qual é o nome e o que vou fazer é usar esse nome para me conectar a ele, então se o nome é aquele que me disseram para me conectar através do Construtor, tentarei me conectar a ele I Vou Brint a mensagem e usar o método que acabei de criar e isso é bom, mas gostaríamos de fazer um pouco mais do que apenas conectar, uma vez que nos conectamos, uh, deixe-me voltar ao método público que estávamos usando, estávamos fazendo isso, estávamos assinando as interfaces, é aí que estaremos nos conectando, habilitamos a digitalização e esperamos por algum tempo aleatório aqui T segundos e então paramos de escanear o que faríamos Na verdade, gosto de fazer é saber que nos conectamos ao dispositivo e, em seguida, parar de escanear imediatamente, então vamos fazer isso, vamos criar as variáveis a que vamos precisar de campos que vamos precisar para implementar essa funcionalidade, então aqui no cabeçalho vou declarar mais alguns campos, neste caso, isso será um mutex, então uma exclusão mútua uh coisa para nós e uma variável de condição, a variável de condição nos permite sinalizar de um lugar para outro H e, em seguida, podemos usar o padrão de simultaneidade ER do produtor consumidor para implementar isso, então o que vamos fazer aqui é ter o cabeçalho certo para que isso seja aceito compilado e, com isso no lugar, podemos usá-lo a partir do método que estávamos usando, mas antes tendo o método H usando-o, gostaríamos de inicializá-lo, então vamos para o arquivo de implementação e aqui no Preâmbulo eu estava inicializando o nome do dispositivo e o proxy do dispositivo, neste caso, o que não é isso, o que vou fazer é ter essa outra inicialização que é um pouco mais completa que pega o dispositivo como proxy e inicializa para n ponteiro como antes e o nome do dispositivo com o nome do sensor que fornecemos, nos foi fornecido e, em seguida, a variável condicional e o mutex são inicializados e temos essa propriedade que é um sinalizador para H dizer se já estamos conectados a um dispositivo ou não e é inicializado como falso ok, então agora podemos ir e er mover para o método que tínhamos o conexão e, neste método, vamos obter isso aqui, é aqui que assinamos as interfaces adicionadas, em seguida, habilitamos a digitalização, espero que aqui nos conectemos e, em seguida, desativemos a verificação antes de fazer isso, obteremos uma instância H na fechadura do mutex, então obteremos esse bloqueio por H usando o mutex que criamos e se o mutex estiver disponível, se ninguém mais estiver rodando nessa zona, vamos assinar as interfaces e habilitar a varredura e aqui, em vez de esperar que a conexão aconteça e um pouco mais, talvez vamos substituir isso por uh, desculpe, porque isso está duplicado, então deixe-me remover as coisas que não são necessárias, então aqui pode remover isso pode remover isso e eu posso remover isso para que eu tenha a mesma varredura habilitável verdadeira e falsa que eu tinha antes, mas ao invés do atraso agora eu tenho uh esperar que a condição e a variável sejam notificadas H para serem sinalizadas e ele usa o log para poder ter acesso às informações e usa esse fechamento que pega a instância do objeto e verifica se esses objetos conectam o sinalizador que é um campo desse objeto foi alterado para true se for isso significa que estou conectado e então vou parar de escanear bonito, não é, então vamos fazer a outra parte deste contrato no fechamento da conexão, vamos para onde a conexão estava acontecendo e aqui no método de conexão ao dispositivo, vamos trabalhar no fechamento que ainda não concluímos, então a primeira coisa que estamos Vou fazer é lidar com o erro, caso aconteça, se tivermos um erro com não queremos continuar, queremos imprimir as informações e deve ser isso, mas se não houver erro, o que vamos fazer é trabalhar com os dados que temos e aqui vamos obter uma olhada no mtic, digamos que estamos conectados, digamos que o conectado A bandeira H agora é verdadeira, então desbloqueamos porque queremos que ela tenha acesso exclusivo ao conectado enquanto a modifica, mas agora não precisamos mais disso e então notificamos os fechamentos, desculpe, os fechamentos, os threads que estão esperando que isso aconteça, neste caso, a principal ameaça e apenas imprimimos a mensagem dizendo: ei, terminamos aqui, então isso deve ser tudo o que precisamos, a única coisa que H tem que ser alterado na implementação ER do CPP principal que, como você pode ver, está em vermelho agora é que agora precisamos de algum valor para criar uma instância do sensor BL, então vamos r isso e fornecer o nome do nosso sensor aqui e isso deve ser mais do que suficiente para ter nosso sensor selecionado, vamos executar isso primeiro, vamos compilar e se pudermos conectar para o dispositivo, a varredura irá parar imediatamente, a única coisa que não estamos fazendo aqui é que ela esperará para sempre se não pudermos nos conectar ao dispositivo, então ele detectou o RP2 essor e estamos aguardando a conexão ser concluída, a conexão começou, mas está demorando um pouco para acontecer e, em seguida, ele se conectou e imediatamente obtemos a parada de varredura Mensagem agora que temos uma conexão com o dispositivo BL, receberemos sinais sobre as interfaces adicionadas, essas interfaces serão os serviços, as características e os descritores da pilha Bluetooth e queremos ouvir os sinais, já temos um fechamento que está prestando atenção aos sinais, no entanto, esse fechamento está se concentrando em dispositivos em dispositivos BLE, vamos mudar o código para que também estar ouvindo as características para que possamos encontrar a característica certa usando-a uid e, em seguida, usar o método read para obter o valor dela, já estamos recebendo informações sobre os dispositivos aos quais nos conectamos e, usando a mesma assinatura, estaremos recebendo informações sobre os caminhos, mas precisamos lidar com isso de uma maneira diferente, então vamos para esse método que está no implementação e devemos ir para o subscrip cribe para interfaces adicioná-lo que é onde estamos ouvindo os sinais coisa aqui é que vamos nos comportar de forma diferente se já estivermos conectados do que se não estivermos porque se ainda não estivermos conectados, estaremos tentando obter uma informação sobre um caminho de um novo dispositivo que foi adicionado enquanto se tivermos já foi conectado e vou escrever isso aqui, então estaremos prestando atenção às coisas que estávamos fazendo antes, que é H os dispositivos de escuta, mas neste caso que têm informações sobre a característica ou os atributos do dispositivo Bluetooth uh de baixa energia, então vamos ter esse H compressão aqui ele reclama que a correspondência não está disponível, então vamos mover a correspondência aqui e agora que temos a partida pronta, precisamos me deixar ir até lá Defina a expressão regular que estamos usando aqui, então vamos, como fizemos antes, vamos definir a expressão regular aqui e, neste caso, a expressão regular será semelhante, inclui como o endereço MAC e assim por diante Ligado, mas também está procurando um serviço e uma característica e, se encontrarmos uma correspondência aqui, vamos trazer que encontramos uma característica com esse caminho e, em seguida, tentaremos procurar em seu dicionário para ver se ela pertence a esse tipo de coisa e tentaremos verificar o UID que é o uuid do personagem que queremos ler uh se você Lembre-se de que essa era a medição de temperatura, então, pesquisando sobre isso, agora podemos apontar para a característica que estávamos procurando para ter essa característica vermelha, precisamos ter, sim, você adivinhou, uh, outro proxy, então vamos criar esse proxy aqui usando o mesmo formato uh que estávamos fazendo antes de s o baixo criar proxy e precisamos declará-lo como um campo aqui, então vamos faça com que ele declare em nosso hether e esse será o nosso último, eu prometo, então aqui temos esse proxy de atributo de temperatura temporária e precisamos inicializá-lo como estávamos fazendo antes no Construtor, então vamos para o Construtor e vamos para o início no Construtor, vamos definir essa nova inicialização que agora usa o preâmbulo para não inicialize apenas o proxy do dispositivo, mas também o proxy do atributo de temperatura aqui também H para ponteiro nulo, porque inicialmente não sabemos qual será o caminho do dispositivo para a característica, o caminho do objeto para a característica, agora que criamos isso e temos no lugar, podemos ir e definir alguns métodos, um privado, um público, como estávamos fazendo antes, então vamos para a pena e aqui vamos definir um que será o público [Música] e outro que será o privado, então aqui temos esses dois métodos e agora podemos implementá-los, vamos para a implementação e aqui vamos para o final do arquivo e criamos a Declaração para o público, uh, esta é a metanfetamina pública, então isso vai ser isso um eu vou mover mais tarde, mas e aqui criamos o privado, o privado está invocando um método como na maioria dos outros casos e aqui temos a interface de leitura de método CH, alguns argumentos e onde queremos armazenar o resultado, então vamos passo a passo e preencher os espaços em branco aqui e a primeira coisa que queremos fazer é inicializar as constantes que estamos usando aqui então queremos dar valor aos argumentos que temos aqui, neste caso, precisamos dizer que o deslocamento que queremos ler é zero e estaremos lendo esse deslocamento e Stor no resultado nesta variante aqui, oh, desculpe, e Stor o resultado neste u em 8 aqui, então esta é uma matriz de H bytes que conterá o valor que nós leia a partir do sensor, agora que temos isso no lugar, podemos tentar usar essas informações H e imprimi-las, então como obtemos esse valor, bem, o que podemos fazer é apenas mostrar o conteúdo desses resultados e a parte com a qual nos preocupamos são os últimos quatro bytes, então começa em zero, então queremos de uma à quinta mordida porque essas são as peças que contêm a temperatura, a primeira era uma bandeira que dizia se tínhamos uma temperatura em Celsius ou em Fahrenheit e se temos um carimbo de data/hora ou não, não interessamos é que só queremos o valor, então agora que temos esse número contendo apenas as coisas que queremos para a temperatura, podemos tentar criar um novo método privado que será deixado eu vou para o Heather aqui e, neste caso, vamos ter isso, oh, desculpe, esse novo método que se transforma de um formato de 11073 triplo em um float, ele pega essa matriz de mordida que extraímos da temperatura e a converte em um float regular, então agora que criamos isso, podemos ir para a implementação e aqui podemos implementar esse método e não vou dar um passo a passo na transformação porque é muito semelhante ao que fizemos no episódio número dois para implementar o firmware blle em python microp python então mesma transformação, mas ao contrário, os três primeiros bytes h contêm o valor e o último contém CHS, a potência H para 10que é usada para transformar esse valor em algo que significa que está reclamando aqui porque não temos ER, o cabeçalho matemático H incluído aqui, então essa é a próxima coisa que vamos fazer e agora que temos isso, devemos ficar bem, então agora a energia deve estar disponível e é uma função que agora está visível aqui e a única coisa que temos que fazer é usar o valor que lemos como fazer fazemos isso bem, o que vamos fazer é aqui, depois de invocar esse método H que recuperamos aqui, vamos transformar o valor usando o método the the private method que acabamos de definir e imprimir como o valor da textura e agora que fizemos isso, podemos executar isso no ER do thread principal para que possamos obter o valor lá fora, então vamos para o CPP, o arquivo CPP principal, e aqui vou adicionar o aviso de leitura de que o ER primeiro, deixe-me incluir o que está faltando aqui para não reclamar, desculpe, precisamos incluir o tópico e agora que temos isso deve estar perfeitamente bem e estou usando theay aqui novamente porque devo usar a outra variável condicional para saber que me conectei e que vi que sou um proxy conectado à característica real, mas não fiz isso porque não quero tornar isso mais longo do que deveria e é por isso que preciso desses dois métodos aqui, essas duas implementações de um atraso antes e depois de obter o valor, então deve ser agora, devemos executá-lo e deve funcionar, vamos tentar isso e Vamos compilá-lo e agora vamos executá-lo novamente tentando conectar ao nosso dispositivo blle que eu tenho preto aqui na minha mesa, então temos o binário pronto e o usamos, ele começa a escanear, não mostra meu sensor e por que isso é bem, deixe-me dizer por que é, deixe-me parar este programa e se você tiver esse problema, o que você precisa fazer é ir para Bluetooth CTL e você vê que ainda está conectado ao dispositivo, então a primeira coisa que você precisa fazer aqui é conectar e agora você tem que esperar um segundo, agora que o baile é Bluetooth, você pode desligar se quiser o dispositivo e pode sair desta interface e tentar novamente e agora você pode ver que o sensor de2 RP está disponível aqui, ele está tentando conectar, ainda estamos esperando que a conexão aconteça, uma vez que ele se conecta, ele para de escanear, mas lê todas as características que temos informações sobre coisas que não são uma característica como está impressa, mas não é totalmente irrelevante aqui e uma vez que encontrou a característica que foi Wass H para ler, lê o valor, esses são os bytes e esta é a temperatura final 37 81 uh graus Celsius, não se preocupe, está muito frio aqui, então é apenas a temperatura na placa, ok, então é isso, finalmente, precisamos nos desconectar do dispositivo para deixar as coisas do jeito que as encontramos, somos ótimos meninos Cortes se não o fizermos, da próxima vez que executarmos o carrinho, ele não funcionará porque o sensor ainda estará conectado e ocupado, vamos implementar um método para se desconectar do dispositivo, então voltamos ao status inicial e, para fazer isso, vamos implementá-lo, esse é o fato, encontre-o no cabeçalho e começamos criando um método público aqui que será chamado de desconectar e um privado que será chamado de desconectar do dispositivo novamente, a mensagem será a privada, a pública será apenas H oferece a interface pública, então agora que temos os dois métodos disponíveis, vamos implementar o código aqui, então vamos para a implementação e aqui vou para a parte inferior do arquivo e vou criar a desconexão do método Dev viice Eu não fui passo a passo porque é a mesma coisa que vamos H ter esse método de chamada síncrono e seremos invocando essa chamada de desconexão de desconexão de volta quando isso terminar, então o que vamos fazer a seguir é trabalhar no conteúdo desse método que será o primeiro a lidar com o erro, se obtivermos um erro aqui, queremos imprimi-lo e sair e se tudo correr bem, o que vamos fazer é obter o Unique Look H, o mutex que temos, vamos bloqueie-o e vamos desconectar e acessar essa coisa que era o que queríamos acessar h exclusivamente, uma vez que tenhamos feito isso, o proxy do dispositivo também está definido como n ponteiro e, em seguida, podemos bloquear o ER facilmente, desbloqueie, desculpe, o mutex para que o resto dos threads possam acessar esses dados e apenas imprimimos esta mensagem para dizer ei, terminamos, basicamente não é isso muito assim Vamos tentar recuar isso para verificar se está tudo bem e agora que fizemos isso, o que gostaríamos de fazer é ter uma implementação do que certo, estávamos faltando um uh ah, estava aqui, então vamos fazer a implementação do método público, que basicamente será uma invocação do privado com uma nova mensagem e é isso agora que temos as duas peças, podemos ir para o arquivo principal e aqui vamos nos desconectar do dispositivo usando o método público e deve ser isso, vamos compilar, desculpe, não este, mas este, e compilamos o projeto, geramos um novo binário com o método disconnect e com esse local binário vamos invocá-lo e esperamos que tudo esteja pronto, mas para evitar qualquer tipo de problema, vamos primeiro usar o Bluetooth CTL e desconectar novamente porque ele não foi desconectado porque o método acabou de ser adicionado, mas vamos nos desconectar do dispositivo, esperar que isso aconteça e, em seguida, ligar a pilha Bluetooth, agora que tudo está no lugar, vamos executar isso, encontramos o sensor rp2 , a conexão começa, ainda estamos recebendo sinais de outros dispositivos ah, e eu tenho um erro de correção que algo acontece e se for esse o caso, uma coisa que você pode fazer é fazer pseudo serviço Bluetooth reiniciar e, em seguida, tentar novamente, encontramos o sensor de2 rp, vamos esperar que a conexão aconteça, se a conexão for bem-sucedida, entraremos oh, é bem-sucedido, encontramos a característica, lemos e então obtemos o valor da temperatura, está tudo bem, e nos desconectamos do dispositivo e foi isso, neste episódio eu escrevi um aplicativo C++ para se conectar a um dispositivo de construção e ler valores do Sens, percebi que escrever C C++ não é como andar de microfone, muita coisa mudou desde a última vez que estive escrever código C ++ que entrou em produção, mas espero ter feito um trabalho decente ao usá-lo para este pequeno aplicativo, sinta-se à vontade para fazer comentários, o maior desafio não foi a linguagem de emparelhamento, embora eu tenha amarrado minha cabeça contra uma parede de tijolos toda vez que tentei me conectar ao dispositivo a partir do meu código no começo, eu não sabia se era meu código para reproduzir a linguagem, a biblioteca ou o quê mas depois comecei a fazer rastros com BT Moon pesquisando na internet e depois de um tempo sem encontrar muito percebi que o problema não era o código, mas sim o fato de que eu estava compartilhando a frequência de rádio em um chip com uma antena muito pequena, então o BCM 43438 que é o chip que usamos para Bluetooth e Wi-Fi no Raspberry Pi estava criando essas interferências para mim de graça e uma vez eu usei um cabo EET uh um upgrade de um Raspberry Pi 3A plus para um Raspberry Pi 4B uh e conectei-o para conectá-lo à internet usando um cabo ethernet e desativando o Wi-Fi de repente as coisas começaram a funcionar, embora a implementação não era muito complexo e a prova de conceito foi passada uh o problema com o Bluetooth levanta algumas preocupações que só poderia piorar se eu falar com vários sensores B em vez de apenas um eu ainda poderia usar uh dongle USB e ignorar o hardware interno, mas antes de eu pegar esse caminho eu gostaria de explorar a alternativa eles mqtt e que vai ser o nosso próximo episódio ficar curioso hackear seu código até a próxima