Chave USB Inteligente com Alexa – Controle de Voz para Dispositivos USB
Componentes e Materiais
| Componente | Quantidade |
|---|---|
| Arduino MKR1000 | 1 |
| Capacitor 0,1uF 0805 | 8 |
| LED (genérico) | 4 |
| Botão pressionado (longo) | 4 |
| INA219 (SOIC 8) | 1 |
| LM3526M | 2 |
| Soquete USB (Vertical) | 4 |
| Resistor 1k 0805 | 4 |
| Resistor de sentido de corrente 0,1 Ohm | 1 |
| Capacitor 1uF 0805 | 1 |
Ferramentas e Máquinas Necessárias
- Impressora 3D (genérica)
- Ferro de solda (genérico)
Aplicativos e Serviços Online
- Amazon Alexa Alexa Skills Kit
- Tinamous
- Amazon Web Services AWS Lambda
Sobre o Projeto
Alexa, ligue o ThingyStick...
Contexto
Cada vez mais dispositivos são alimentados por USB, muitos deles "burros" sem conectividade à internet ou opções de automação residencial (ex: luzes LED). Como automatizá-los ou controlá-los remotamente? Uma fonte USB ligada a um interruptor de rede é exagero, especialmente se quisermos controlar 4 dispositivos individualmente!
Este projeto permite controlar o fornecimento de energia a dispositivos USB via internet e, usando a Skill Tinamous SmartHome para Alexa, você pode habilitar controle por voz para seus dispositivos USB "burros".
Atualmente, existem poucos dispositivos no mercado para controle remoto de energia USB. Quando iniciei este projeto, não encontrei nenhum (no Reino Unido), mas alguns apareceram recentemente como parte de tomadas multi-gang (sim, a ideia começou há muito tempo, em uma galáxia muito distante). Estes não são de fabricantes conhecidos de automação residencial, mas de fabricantes sem marca (ex: ZLD-34UK), o que levanta questões: qual nuvem de dispositivo eles usam? Os dados vão para a China e voltam? O que acontece se o fabricante deixar de existir? Quão seguro é? Quão usável é o software? Estará na caixa de reciclagem na próxima semana? E muitas outras preocupações normais de dispositivos conectados à internet, sem mencionar que não são "hackeáveis" da mesma forma que um dispositivo Arduino open source.
Casos de Uso
Exemplos de dispositivos alimentados por USB que podemos querer controlar:
- Luzes alimentadas por USB
- Kindle Fire / Chrome cast sticks (especialmente em quartos de crianças para impedir que assistam TV)
- Umificadores USB
- Echo Dot (fazer a Alexa se desligar à noite? ou apenas reiniciar o dispositivo)
- Placas de desenvolvimento. Precisa reiniciar aquele projeto porque seu código entrou em loop infinito?
- Dispositivos de difícil acesso que precisam ser reiniciados ocasionalmente (ex: sensores no sótão)
- Dispositivos instalados em locais de clientes onde queremos garantir que estão alimentados (medindo consumo de corrente e tensão de entrada)
Controle simples de energia: Comutação de energia habilitada para internet, seja via controle de voz Alexa ou outros comandos através do Tinamous. Ligar e Desligar.
Controle inteligente de energia: Muitas lâmpadas USB têm controles de toque para ligar a lâmpada, o que significa que não podemos ligar a luz remotamente, mas podemos desligá-la, e na maioria das vezes isso é tudo o que queremos (tentando dormir, deixou uma lâmpada acesa? Saindo, quer todas as luzes apagadas?).
No entanto, uma vez que usamos a Alexa para Desligar a lâmpada USB, temos que pedir à Alexa para Ligar a lâmpada antes de poder ligá-la novamente, o que é bobo. Com energia inteligente habilitada, o comando desligado desligará a energia da lâmpada por alguns segundos antes de restaurar a energia ao dispositivo. O suficiente para desligar a lâmpada, mas também permitindo operação normal depois.
Automação por Timer: Faça seus dispositivos desligarem automaticamente em horários definidos. Crianças assistindo Amazon TV no Fire Stick até tarde? Faça a fonte USB desligar automaticamente às 20h.
Monitoramento de energia: Se você está desenvolvendo hardware alimentado por USB, provavelmente quer saber quanta corrente seu dispositivo consome, especialmente quando liga pela primeira vez, ou pode querer perfilar o carregamento de power banks. Com o INA219 a bordo, você pode monitorar o consumo de corrente (consegui cerca de 1kHz de amostragem com pouco esforço). Queda de tensão em cabos USB em alta corrente também pode ser um problema; o INA219 monitora a energia entrando no dispositivo para que possamos avisar sobre baixa tensão. Um bloco de terminais também é fornecido para permitir correntes maiores e cabos mais grossos.
Falha de energia: Usando a opção de bateria no MKR 1000, podemos monitorar a tensão de alimentação USB e enviar notificações se a energia de entrada falhar. Isso pode ser útil para soluções remotas (fora do local) que usam energia USB mas precisam de monitoramento extra, ou apenas como detecção simples de falha de energia da rede para sua casa.
Hardware
Este projeto é bastante simples: um Arduino MKR1000 no centro, comutação de energia USB usando dois LM3526M para fornecer comutação de lado alto e detecção de falhas (baixa tensão, sobrecorrente), junto com monitoramento de energia (tensão e corrente) usando um INA219, e finalmente LEDs e interruptores para opções de controle local.
Mandei fabricar um PCB na DirtyPCBs.com; você também pode enviar o arquivo .brd para OSHPark.com. O soquete do Arduino tem pads de PCB de cada lado de cada pino para permitir hacks. Ex: você poderia facilmente adicionar sensores para condições ambientais ou um pequeno display OLED para mostrar tensão e corrente.
No repositório GitHub há uma opção de 2 portas e 4 portas. Cuidado com o PCB de 2 portas pois errei e o layout do soquete USB ficou errado (estão de costas para frente - polaridade invertida!).
Vitória das garras da derrota:
Como se vê, montar o soquete USB no verso da placa é na verdade uma boa solução e significou que as conexões dos pinos estavam corretas (porém, para a placa de 2 portas, isso também significa que a serigrafia está no lado errado!). O Arduino com headers em um soquete estava apertado para espaço com a altura necessária para tirar os soquetes USB do gabinete, então funcionou melhor. Decidi refazer a placa com soquetes, interruptores e LEDs no verso e adicionar duas portas extras, daí a versão de 4 portas (também, os LEDs estavam horrivelmente alinhados na versão de 2 portas, então isso também foi corrigido!).
Há muito pouco impedindo que isso seja estendido para um comutador de 6 ou 8 portas, embora os LEDs e interruptores possam precisar ser removidos ou melhorados.
O esquemático parece muito mais complexo de construir do que é. Muitos dos resistores são opcionais. Resistores R23, 19, 27 e 26 são pull-ups para os interruptores; R20-22, R14 e R15 são pull-ups para controle USB e detecção de falhas. Todos podem ser feitos através do modo INPUT_PULLUP no Arduino, porém se você quiser colocar o Arduino em sono de baixa potência e usar interrupções para acordar, pode querer popular esses para que não flutuem (e saltem).

Também adicionei resistores opcionais nas linhas USB D+/D-. Podem ser instalados para informar ao dispositivo quanta energia pode usar, mas para muitos dispositivos burros são ignorados. Abaixo, apenas R24 para limitação de corrente do LED é realmente necessário. R2-5 e R28 ficam vazios.

Os LEDs e interruptores também são completamente opcionais. Se você só quer uma caixa autônoma que controle USB remotamente, não adicione essas peças.
Entrada de Energia
Este controlador pode ser alimentado via três opções:
- Interna (JP6 pinos 1 e 2 conectados): energia USB vem do pino 5V do Arduino (e portanto do conector USB do Arduino). Só deve ser usado para cargas de baixa potência.
- Externa via J2 (JP6 pinos 2 e 3 conectados): conecte 5V via J2 (conector USB micro a bordo).
- Externa via JP8 (bloco de terminais): para correntes maiores e cabos mais grossos.
Não use ambas as opções externas ao mesmo tempo. A energia externa também é roteada para o pino VIn do Arduino, então ele não precisará de sua própria opção de energia.
Para pontos extras, instalando resistores 0R em R10 e R11, bem como J2, obtemos passagem USB 3 para reiniciar um dispositivo conectado via USB, muito útil ao desenvolver hardware e não querer desgastar os soquetes USB do PC!

Gabinete
Um gabinete impresso em 3D está incluído no projeto. Usa inserts de calor M3 para conexões da PCB e tampa, embora as tolerâncias da tampa sejam boas o suficiente para encaixe por atrito.
A tampa inclui algumas opções:
- Com ou sem compartimento de bateria.
- Com ou sem pés (furos de montagem para fixar a caixa a uma superfície).
Da mesma forma, a caixa base pode ser configurada (usando OpenSCAD) para incluir aberturas para cada uma das três fontes de energia.
Foram necessárias várias tentativas para acertar o gabinete. Como você versiona suas impressões? Minhas amostras do clube de fãs Rigid.Ink foram muito úteis.



Conectando ao Tinamous
Estamos usando o Arduino MKR1000 para controlar as tomadas, então temos conectividade WiFi. Se você é novo nesta placa, precisará adicionar a opção de placa à sua IDE Arduino.
Vamos usar o servidor MQTT do Tinamous para conectar, principalmente porque é incrível, mas também, talvez, porque sou o fundador/desenvolvedor/fazedor de chá! Vamos nos inscrever no tópico de postagem de status para mensagens enviadas ao dispositivo (ex: o tópico "Status.To").
Antes de começar a codificar, precisamos garantir que o Arduino tenha o firmware mais recente e os certificados SSL necessários para obter uma conexão segura com o Tinamous. Obviamente, se preferir, você pode adaptar isso para seu próprio servidor MQTT local e não se preocupar tanto com segurança.
Passo 1
Abra a IDE Arduino e carregue o sketch FirmwareUpdater do menu de exemplos WiFi101. Envie para seu dispositivo.

Passo 2
Uma vez enviado, selecione WiFi101 Firmware Updater no menu Ferramentas.

Passo 3
Teste sua conexão e depois Atualizar Firmware. Feito isso, use o botão Adicionar domínio e adicione tinamous.com para garantir que o Arduino tenha os certificados SSL corretos. Pressione o botão Enviar Certificados para módulo WiFi para carregar os certificados.
Passo 4
Agora podemos escrever nosso próprio firmware. Você encontrará os arquivos anexados a este projeto e também no repositório GitHub (o GitHub terá a versão mais recente).
Usaremos o WiFi101 e o Cliente MQTT no seu sketch Arduino.

Selecione a opção MQTT by Joel Gaehwiler.
O arquivo secrets.h precisa ser preenchido com suas configurações WiFi e MQTT do Tinamous; não incluí minha cópia por razões óbvias.
#define SECRET_SSID "Seu SSID"
#define SECRET_PASS "Senha do seu SSID"
/************************* Configuração MQTT Tinamous *********************************/
#define MQTT_SERVER "<nome da conta tinamous>.tinamous.com"
#define MQTT_SERVERPORT 8883
#define MQTT_USERNAME "UsbSwitch.<nome da conta tinamous>"
#define MQTT_PASSWORD "Sua senha vai aqui."
#define MQTT_CLIENT_ID "UsbSwitch"
#define DEVICE_USERNAME "UsbSwitch"
Se você ainda não se registrou no Tinamous, pode criar sua conta gratuita aqui. Ao registrar, você informa um nome de Conta/Organização, que se torna sua área privada no Tinamous; você pode convidar outros membros para essa área (incluindo Alexa) e compartilhar seus dispositivos com seu grupo.
Abaixo, estou chamando minha conta de "AlexaExample", que é o que incluirei na configuração MQTT, e minha conta Tinamous está em https://AlexaExample.Tinamous.com

Passo 5
Em seguida, precisamos adicionar nosso Dispositivo. Na página Dispositivos do Tinamous, clique no botão Adicionar.

Portanto, as configurações MQTT do Tinamous para meu dispositivo ficam assim...
/************************* Configuração MQTT Tinamous *********************************/
#define MQTT_SERVER "AlexaExample.tinamous.com"
#define MQTT_SERVERPORT 8883
#define MQTT_USERNAME "UsbSwitch.AlexaExample"
#define MQTT_PASSWORD "Minha senha super secreta que totalmente não é Passw0rd...."
#define MQTT_CLIENT_ID "UsbSwitch"
#define DEVICE_USERNAME "UsbSwitch"
Isso habilita nossa conta e dispositivo Tinamous. Você pode adicionar mais dispositivos aqui se quiser, apenas atualize as configurações MQTT para DEVICE_USERNAME e MQTT_USERNAME (o MQTT não envia informações de cabeçalho como HTTP, então o Tinamous não sabe qual subdomínio você está usando, por isso precisamos especificar a conta no nome de usuário).
Passo 6
Envie o código anexado para seus dispositivos (com seu arquivo secrets.h atualizado). Reserve um momento para olhar o arquivo TinamousMQTTClient.ino; ele lida com nossas interações MQTT e, com isso, os comandos Alexa enviados ao nosso dispositivo.
Precisamos usar o WiFiSSLClient para SSL. Se quiser usar um servidor MQTT local sem SSL, pode usar o WiFi Client normal e baixar para a porta 1883, mas para qualquer coisa baseada na internet, use o Cliente SSL.
Também precisamos reservar um pouco mais que o buffer padrão para o cliente MQTT; aqui reservamos 4096 bytes.
WiFiSSLClient networkClient;
MQTTClient mqttClient(4096);
Usamos mqttClient.begin para configurar o cliente e especificar um manipulador de função em onMessage que é chamado quando uma mensagem é recebida do servidor MQTT.
mqttClient.begin(MQTT_SERVER, MQTT_SERVERPORT, networkClient);
// Manipular mensagens recebidas.
mqttClient.onMessage(messageReceived);
E então podemos conectar e assinar os tópicos nos quais estamos interessados. Aqui você vê que assinamos "Tinamous/V1/Status.To/UsbSwitch"; receberemos mensagens enviadas para @UsbSwitch na timeline do Tinamous. É assim que receberemos mensagens da Alexa.
if (!mqttClient.connect(MQTT_CLIENT_ID, MQTT_USERNAME, MQTT_PASSWORD)) {
if (mqttClient.lastError() == LWMQTT_CONNECTION_DENIED) {
// Este erro é porque seu nome de usuário ou senha está errado
}
if (mqttClient.lastError() == -6) {
// Este erro é provavelmente porque você não adicionou o certificado SSL.
}
// Força um atraso antes de tentar a conexão novamente
delay(10000);
return false;
}
// Conexão bem-sucedida. Agora assina o tópico
mqttClient.subscribe("/Tinamous/V1/Status.To/" DEVICE_USERNAME);

Você pode pensar na timeline do Tinamous como uma versão privada do Twitter para você e seus dispositivos; eles podem usar MQTT ou a API REST (ou um dos bots) para ver as mensagens enviadas a eles e agir sobre elas, bem como postar mensagens de volta.
Temos um pouco mais de trabalho a fazer no Tinamous para habilitar a integração com Alexa, mas por enquanto podemos testar nosso dispositivo e firmware usando a timeline e enviando mensagens.
Se você usar a Skill Tinamous SmartHome, isso é toda a codificação necessária.
A Skill Tinamous Smart Home para Alexa
A Skill Tinamous Smart Home está atualmente pendente de aprovação para publicação (no momento da escrita, dedos cruzados para que já esteja na loja...). Para fazer seu próprio comutador USB, você pode simplesmente usar esta Skill quando estiver disponível.
A skill é na verdade muito genérica; ela não sabe nada sobre os dispositivos ou como falar com eles. Aplicamos tags aos dispositivos no Tinamous e a skill criará um dispositivo apropriado na conta Alexa; portanto, você poderia usar esta skill e o Tinamous para habilitar por voz um de seus próprios projetos com apenas algumas linhas de código no dispositivo.
No entanto, você pode querer alterar coisas ou escrever sua própria skill, então compartilharei os detalhes do meu desenvolvimento.
Escrevi a skill em C# para .Net Core 2.0; foi desenvolvida para meu projeto de ventilador inteligente BOFF, mas para este projeto a estendi para permitir que um dispositivo tenha muitas tomadas (portas) e cada uma seja um cidadão de primeira classe nos dispositivos Alexa Smart Home.
Todo o código (incluindo alguns testes!) está no repositório Tinamous SmartHome; clone, baixe ou apenas visualize como quiser. Usei Visual Studio 2017 com as ferramentas AWS instaladas para ajudar a enviar a skill para o Lambda.
O framework desserializa a mensagem de diretiva recebida da Alexa em objetos que podemos acessar pelo código; ações apropriadas são tomadas baseadas no namespace e nome da diretiva do cabeçalho, e então uma resposta apropriada é retornada.
As principais mensagens de interesse são:
- Vinculação de Conta (Account Linking)
- Descoberta (Discovery)
- Relatório de Estado (State Report)
- Controle de Energia (Power Control)
Vinculação de Conta (Account Linking)
Isso é tratado pela Alexa para nós; após adicionarmos a skill à nossa conta, a Alexa solicitará autenticação; somos levados à página de Autorização do Tinamous para permitir que o dispositivo acesse nossa conta. Aqui você precisa inserir seu nome de conta (AlexaExample neste caso), nome de usuário (Steve) e senha (não, não vou contar!).

Descoberta (Discovery)
Uma vez que sua conta está vinculada, a Alexa solicita a realização da descoberta; a skill então consulta o Tinamous por dispositivos marcados com "Alexa.SmartDevice". Dispositivos sem isso são simplesmente ignorados.
Essas tags são aplicadas editando o dispositivo na página Dispositivos no Tinamous.
Se o dispositivo também estiver marcado com "MultiPort", cada porta é enumerada e um dispositivo também é adicionado para essas. Também aplicamos tags baseadas nas diretivas Alexa que nosso dispositivo suporta; aqui é apenas "Alexa.PowerController" e também uma tag para indicar em qual categoria o dispositivo deve ser exibido no app; aqui usei "SmartPlug".

Outras interfaces estão disponíveis, como Alexa.BrightnessController, mas não são tão úteis aqui. Veja o readme do repositório para mais detalhes.
Para nosso dispositivo MultiPort expor portas individuais à Alexa, precisamos configurar as Variáveis de Estado, também na página de edição do dispositivo.

PortCount indica o número de portas que o dispositivo tem; então "Port-1".."Port-n" dão os nomes que a Alexa usará para as portas. Qualquer porta sem nome será ignorada. Você pode facilmente alterar o nome da porta aqui e executar a descoberta novamente para atualizar a Alexa.
Durante a descoberta, a skill também procurará um campo marcado, nomeado ou rotulado "powerState", ou "powerState-port-n" conforme apropriado. Se este campo for encontrado, ele é atribuído como uma capacidade suportada para o dispositivo (mais sobre isso em Relatório de Estado).

Relatório de Estado (State Report)
Durante a fase de descoberta, dissemos à Alexa quais capacidades nosso dispositivo tem; a skill assume por padrão que estes podem ser solicitados; portanto, a Alexa enviará uma solicitação StateReport para obter os valores para estes.
Temos um último conjunto de tags a serem aplicadas para suportar isso, desta vez nos campos do dispositivo. Uma vez que seu dispositivo está enviando dados (essa é a mensagem senml sendo enviada via MQTT no código Arduino), o Tinamous criará campos para o dispositivo. Podemos então usar a opção Avançado na lista de campos para editar isso. Usar a opção de tag é o mais versátil, pois significa que não precisamos acertar o nome do campo no firmware ou ficar presos se quisermos renomeá-lo.


Se os campos específicos da porta não forem encontrados, a Alexa recorrerá ao campo não específico da porta (aqui chamado powerState).
Controle de Energia (Power Control)
Nosso dispositivo não serviria para nada na Alexa sem isso! A Alexa enviará duas diretivas à nossa Skill: "TurnOn" e "TurnOff". A função principal de ponto de entrada da skill primeiro procura o namespace (Alexa.PowerController), depois passa o trabalho para a classe controladora apropriada (PowerController.cs).
A skill então simplesmente publica uma Mensagem de Status na timeline do Tinamous.
Por exemplo:
@UsbSwitch Ligar
ou
@UsbSwitch Ligar port-1
As outras interfaces suportadas são tratadas de forma quase idêntica. Então cabe ao nosso dispositivo observar essa mensagem de status e realizar uma ação. A Alexa pode então ler o estado usando um StateReport.
É assim que a skill funciona. Agora só precisamos enviá-la para o AWS Lambda e criar uma entrada de Skill no console Alexa para realmente dar à Alexa acesso a ela.
Criando a Função AWS Lambda
Usei as ferramentas AWS dentro do Visual Studio para enviar a skill compilada para o Lambda. Mas primeiro precisamos criar o Lambda.
Dica profissional: Crie o Lambda na região AWS apropriada para o idioma que você está suportando. Inglês (Reino Unido) precisa mirar em eu-west (Irlanda).
Crie uma nova função lambda do zero. Os blueprints existentes são limitados e desatualizados (suportam apenas V2 da interface SmartHome, que é muito diferente e depreciada - estamos usando V3).
Você precisará criar uma nova role para permitir que o Lambda acesse os recursos necessários. Aqui selecionamos Simple Microservices como padrão (na verdade dá muito mais do que precisamos). Se você descobrir que não está obtendo logs no CloudWatch, pode também precisar ir e dar permissões para isso através da seção IAM.

Então precisamos publicar os binários do Visual Studio. Com as ferramentas AWS instaladas, clique com o botão direito no projeto e selecione "Publicar no AWS Lambda..."

Então preencha os detalhes para a expressão Lambda e clique em Upload...


Uma vez enviado, podemos executar alguns testes no Lambda para garantir que roda. Então precisamos "Publicar nova versão" no dropdown Actions.

Uma vez publicado, precisamos dar permissões à nossa Skill para acessar isso.
Clique no gatilho "Alexa Smart Home" e insira o skill id (ainda não temos isso...)

Criando a Skill no Console Alexa
Com nosso Lambda quase pronto, precisamos ir ao console de desenvolvedor de skills e criar uma entrada para ele. Abra https://developer.amazon.com, selecione Alexa Skills Kit e adicione uma nova Skill.
Selecione Smart Home Skill API, o idioma que deseja alvo (ex: Inglês (Reino Unido) para nós no Reino Unido) e selecione versão de payload V3 (preferida).

Na página de Configuração, entramos nos detalhes mais interessantes. Insira o Lambda ARN do nosso Lambda versionado (canto superior direito da tela). Deve terminar em algo como :1 ou :2 ou :5246 (se você teve algumas tentativas ;-) ).

Enquanto no Lambda, também podemos colar o "Application ID" ou "Skill ID" ou "ID" ou como quer que seja chamado hoje da skill; deve parecer algo como amzn1.ask.skill.2_______________50.
Certifique-se de clicar em Salvar após adicionar o Application ID. No console antigo você encontra o id no cabeçalho sob o nome da skill; no novo, erm, abra uma nova janela, volte para a lista de skills do console, e clique no link apropriado. (é como se eles nunca tivessem usado o console para realmente fazer uma skill).
Para habilitar a vinculação de conta, precisamos de uma aplicação OAuth criada no Tinamous; isso é feito usando o Alexa Bot. Vá à página Bots da sua conta Tinamous e adicione um Alexa Bot. Uma vez criado, a caixa de diálogo lhe dará todos os detalhes necessários para configurar a vinculação de conta.
NB: Se você estiver usando a (em breve a ser...) Skill Tinamous SmartHome publicada, não precisa de um Alexa Bot.


A aplicação criada pelo bot permitirá que qualquer outro detentor de conta Tinamous use sua skill e vincule sua conta. Naturalmente, você não precisa publicar sua skill e pode mantê-la privada; eles não poderão ver nada na sua conta Tinamous.
Da mesma forma, se você usar uma nuvem de dispositivo diferente (sério, por que faria isso ;-) ), precisará inserir os detalhes da aplicação OAuth deles.
Na página de Teste, certifique-se de que sua skill está definida como "Sim" para "Mostrar esta skill no App Alexa".
Salve e vá para alexa.amazon.co.uk (ou o apropriado para sua região), ou aparentemente há um app também.....
Clique em "Skills", depois no canto superior direito, "Suas Skills", e depois "DEV SKILLS"; você deve ver sua skill listada com um marcador verde indicando que é uma skill de desenvolvimento.


O "Alexa, desligue a luz USB" e informações adicionais da skill quando você a seleciona são configurados na página "Informações de Publicação"; você pode inserir as informações durante o desenvolvimento sem ter que ir para publicação completa.
Se precisar atualizar o código da skill, faça upload da nova função Lambda, crie uma nova versão, re-adicione o gatilho SmartHome e Skill Id, então cole a função Lambda versionada no console da skill (você pode conseguir usar um lambda não versionado, mas não funcionou quando tentei - embora houvesse muitas outras coisas que também tinha errado naquela época).
Sucesso!
Com nosso código de skill rodando no Lambda e a Skill instalada em nossa conta Alexa, podemos executar a descoberta e começar a controlar os dispositivos.
Você pode clicar nos logs do CloudWatch para ver as informações de log escritas pela sua skill.
Depuração da Skill & Dicas
A Alexa fornece quase nenhum feedback para desenvolvedores quando as coisas dão errado; você pode passar eras adivinhando por que a Alexa não faz o que você esperava.
- Evite a maioria das coisas além de alfanuméricos em seus endpointIDs (usei * em um estágio e tudo quebrou, mas não de forma óbvia; porém # funcionou. Vá entender!).
- Registre tudo. Verifique logs quando invocar sua skill. Sem log? Provavelmente autenticação, ou sua skill não está autorizada para a expressão Lambda.
- Use contas de email AWS e Alexa correspondentes.
- Mantenha o Lambda na mesma região da skill (Irlanda para skills UK).
- Se sua skill é invocada mas a Alexa não responde a ela (ex: não lista dispositivos), seu formato de resposta provavelmente está errado.
- Se não quiser usar sua conta Alexa do dia a dia, pode usar Amazon Households para adicionar uma segunda conta adulta. Note, porém, que isso parece limitado a 2 adultos, e você não pode mudar sem um atraso épico.
- Você pode dizer "Alexa, Trocar Perfis" para alternar entre seus perfis de desenvolvedor e regular.
- Espero que com o redesign do Console Alexa, algumas informações de depuração melhores estejam disponíveis. No momento, tudo que vejo são caixas maiores e validação um pouco melhor. Alguns logs estão disponíveis, mas são apenas logs de sucesso. Métricas de gerenciamento para sentir-se bem, e atrasados em 36 horas, o que não ajuda na depuração!
Uma Skill, Qualquer (IoT) Coisa!
Com a skill Tinamous SmartHome, desde que sua (Internet das Coisas) coisa possa conectar ao servidor MQTT Tinamous (ou esteja conectada via um bot suportado), adicionar controle Alexa SmartHome à sua coisa é simplesmente algumas linhas de código para lidar com mensagens como "Ligar", "Desligar", "Definir brilho 20". Apenas adicione as tags no Tinamous, e....
"Alexa, Descobrir Dispositivos Smart Home".
Código
- AlexaUsbSwitcher.ino
- TinamousMQTTClient.ino
- UsbControl.ino
- WiFiClient.ino
- Secrets.h
AlexaUsbSwitcher.ino Arduino
Este é o arquivo principal.
#include <MQTTClient.h>
#include <system.h>
#include <WiFi101.h>
#include <Adafruit_INA219.h>
// Forneça seu próprio Secrets.h com definições WiFi e Tinamous
#include "Secrets.h"
// ================================
/*
#define MAX_USB_PORTS 2 // Placa de 2 portas.
int led_pin[MAX_USB_PORTS][2] = {{A5, A6},{0,1}};
int switch_pin[] = {A0, A1};
// Canal B do interruptor USB -> pino 5 == USB1
int usb_enable_pin[] = {2, 5};
int usb_fault_pin[] = {3, 4};
bool usb_port_state[] = {false, false};
bool usb_power_mode[] = {0, 0, 1, 1};
*/
// ---------------------------------
// Placa de 4 portas.
#define MAX_USB_PORTS 4
// A placa de 2 portas tem LEDs bi-color, a de 4 não, então usa o mesmo pino...
// LEDs: TX, Rx, D7, D6 (1-4)
int led_pin[MAX_USB_PORTS][2] = {{14, 14}, {13,13}, {7,7}, {6,6}};
int switch_pin[] = {A0, A1, A2, A3};
// Pinos de habilitação USB, D1, D3, D4, D5 (não nessa ordem)
int usb_enable_pin[] = {5, 4, 1, 3};
// Pino de falha único (D2)
int usb_fault_pin[] = {2, 2, 2, 2};
bool usb_port_state[] = {false, false, false, false};
// Modo: 0 - Desliga conforme solicitado.
// Modo: 1 - Desliga, depois liga após atraso (útil para luzes LED com controles de toque).
int usb_power_mode[] = {1, 0, 0, 0};
// ================================
// Opções de automação.
// tempo (millis) que a porta USB deve ser ligada/desligada.
// zero indica ignorar.
unsigned long usb_power_switch_on_at[] = {0, 0, 0, 0};
// Define > 0 para ser processado no primeiro loop.
// Efeito colateral: desliga aqueles em modo de energia inteligente
// que agendarão para ligar novamente.
unsigned long usb_power_switch_off_at[] = {1, 1, 1, 1};
// Monitor de corrente INA219
Adafruit_INA219 ina219;
// Flag para indicar se uma ou mais portas USB tem falha.
bool has_usb_fault = false;
// Energia medida.
float shunt_voltage = 0;
float bus_voltage = 0;
float current_mA = 0;
float load_voltage = 0;
float power_mW = 0;
// Min/max
float max_current_mA = 0;
float max_busvoltage = 0;
float min_busvoltage = 20;
// rastrear uso de energia.
unsigned long last_measurement_time = 0;
bool power_failed = false;
bool over_current = false;
// Publicação MQTT.
// Provavelmente quer mais rápido quando alimentando dispositivos.
// ou mais lento quando não!
int update_interval_seconds = 20;
unsigned long next_message_send_at = 0;
// =================================================
// Ponto de entrada principal do setup
// =================================================
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
for (int channel=0; channel MAX_USB_PORTS) {
return;
}
// Acende LED (1..4) baseado no progresso do setup.
SetLeds(stage-1 , true, true);
}
// ===================================================
// Loop Principal
// ===================================================
void loop() {
// Dispositivo de 4 portas, LED de debug é LED da porta 4.
// se qualquer porta 4 está ligada, não desliga o LED.
// com todas as 4 portas desligadas, o LED de debug pode piscar como quiser...
if (!hasPoweredPorts()) {
digitalWrite(LED_BUILTIN, LOW);
}
// Verifica falha.
bool faulted = false;
for (int channel = 0; channel < MAX_USB_PORTS; channel++) {
if (checkFault(channel)) {
faulted = true;
}
// Permite limpar has_usb_fault se TODOS os canais não estão com falha.
has_usb_fault = faulted;
checkSwitchPressed(channel);
}
// Faz automação (ex: ligar em certo horário)
runAutomation();
// Verifica corrente, tensão e tudo mais.
readCurrent();
// Verifica falha de alimentação.
checkPowerSupply();
doDelay();
mqttLoop();
sendStatus();
}
void doDelay() {
if (hasPoweredPorts()) {
delay(100);
return;
}
// Apenas debug. LED está no LED da Porta 4 então é mostrado ao usuário quando
// todas as portas estão desligadas.
//
// Pisca apenas no modo lento para não termos que atrasar
// as leituras para o usuário ver o piscar.
// Nenhuma porta ligada, não atualiza tão frequentemente.
delay(100);
digitalWrite(LED_BUILTIN, HIGH);
delay(100);
}
// Verifica usuário pressionando interruptor para ligar uma porta.
void checkSwitchPressed(int channel) {
if (isSwitchPressed(channel)) {
// Alterna energia USB
setUsb(channel, !usb_port_state[channel]);
}
}
// Lógica de pressionar interruptor para debounce
bool isSwitchPressed(int channel) {
// Interruptor é active low.
// Atraso de debounce para garantir que o interruptor está devidamente pressionado.
// Interruptor é active low. false = pressionado.
if (digitalRead(switch_pin[channel])) {
return false;
}
// espera para ver se ainda está pressionado após 0.2s
delay(50);
if (!digitalRead(switch_pin[channel])) {
// Pequeno debounce...
delay(100);
return true;
}
return false;
}
// Lê INA219 (Tensão, Corrente)
void readCurrent() {
shunt_voltage = ina219.getShuntVoltage_mV();
bus_voltage = ina219.getBusVoltage_V();
current_mA = ina219.getCurrent_mA();
//power_mW = ina219.getPower_mW();
load_voltage = bus_voltage + (shunt_voltage / 1000);
// registra tempo de medição para calcular
// uso de energia*tempo.
last_measurement_time = millis();
if (current_mA > max_current_mA) {
max_current_mA = current_mA;
}
if (bus_voltage > max_busvoltage) {
max_busvoltage = bus_voltage;
}
if (bus_voltage < min_busvoltage) {
min_busvoltage = bus_voltage;
}
printPowerSkinny();
}
// Verifica se temos entrada de energia, não tem queda significativa de tensão
// e não estamos sobrecarregando a entrada.
void checkPowerSupply() {
// Tensão de barramento mais alta para restaurado para evitar
// vai e volta em 4.19...
if (power_failed && bus_voltage > 4.5) {
Serial.print("Energia externa restaurada. Tensão de barramento: ");
Serial.print(bus_voltage);
Serial.println(" V");
publishTinamousStatus("Energia externa foi restaurada.");
power_failed = false;
}
if (bus_voltage < 4.2 && !power_failed) {
Serial.print("Falha de energia externa! Tensão de barramento: ");
Serial.print(bus_voltage);
Serial.println(" V.");
publishTinamousStatus("Energia externa perdida!");
power_failed = true;
}
if (over_current && current_mA < 1500) {
publishTinamousStatus("Falha de corrente eliminada!");
over_current = false;
}
if (current_mA > 2000 && !over_current) {
// Sobrecarga!
publishTinamousStatus("Sobrecorrente!");
over_current = true;
}
}
void printPowerWide() {
Serial.print("Tensão Barramento:\t");
Serial.print(bus_voltage);
Serial.print(" V\t");
Serial.print("Corrente: \t");
Serial.print(current_mA);
Serial.print(" mA\t");
Serial.print("Corrente Máx:\t");
Serial.print(max_current_mA);
Serial.print(" mA\t");
Serial.print("Tensão Mín:\t");
Serial.print(min_busvoltage);
Serial.print(" V\t");
Serial.print("Tensão Máx:\t");
Serial.print(max_busvoltage);
Serial.print(" V\t");
Serial.println();
}
void printPowerSkinny() {
Serial.print(bus_voltage);
Serial.print("\t");
Serial.print(current_mA);
Serial.print("\t\t");
Serial.print(max_current_mA);
Serial.print("\t\t");
Serial.print(min_busvoltage);
Serial.print("\t");
Serial.print(max_busvoltage);
Serial.print("\t");
Serial.print("[");
for (int channel=0; channel next_message_send_at) {
Serial.println("------------------------");
Serial.println("MQTT publish measurements");
if (power_failed) {
// reduz frequência de envio quando energia
// falhou para preservar energia da bateria.
sentNextPublishAt(update_interval_seconds * 10);
} else {
sentNextPublishAt(update_interval_seconds);
}
// E faz um como senml...
String senml = "{'e':[";
// Tensão
senml = senml + "{'n':'busVoltage'";
senml = senml + ", 'v':";
senml = senml + String(bus_voltage);
senml = senml + ", 'u':'V'}";
// Tensão máxima
senml = senml + ",{'n':'maxBusVoltage'";
senml = senml + ", 'v':";
senml = senml + String(max_busvoltage);
senml = senml + ", 'u':'V'}";
// Tensão mínima
senml = senml + ",{'n':'minBusVoltage'";
senml = senml + ", 'v':";
senml = senml + String(min_busvoltage);
senml = senml + ", 'u':'V'}";
// Corrente
senml = senml + ",{'n':'Current'";
senml = senml + ", 'v':";
senml = senml + String(current_mA);
senml = senml + ", 'u':'mA'}";
// Corrente máxima
senml = senml + ",{'n':'MaxCurrent'";
senml = senml + ", 'v':";
senml = senml + String(max_current_mA);
senml = senml + "', 'u':'mA'}";
// mAh consumidos...
senml = senml + ",{'n':'mAh'";
senml = senml + ", 'v':";
senml = senml + String(0); // TODO!
senml = senml + ", 'u':'mAh'}";
senml = senml + ",{'n':'powerState'";
senml = senml + "', 'bv':";
if (isPowered()) {
senml = senml + "true";
} else {
senml = senml + "false";
}
senml = senml + "}";
for (int channel=0; channel 0 && onAt < millis()) {
Serial.print("Auto ligar para porta: ");
Serial.println(channel + 1);
setUsb(channel, true);
usb_power_switch_on_at[channel] = 0;
}
// Verifica se a porta deve ser desligada automaticamente
unsigned long offAt = usb_power_switch_off_at[channel];
if (offAt > 0 && offAt < millis()) {
Serial.print("Auto desligar para porta: ");
Serial.println(channel + 1);
setUsb(channel, false);
usb_power_switch_off_at[channel] = 0;
}
}
}
TinamousMQTTClient.ino Arduino
Este arquivo gerencia a conectividade MQTT (é a parte que responde aos comandos Alexa).
// ======================================
// Conectividade Tinamous via MQTT
// ======================================
#include <MQTTClient.h>
#include <system.h>
#include "secrets.h"
// Configurações WiFi e MQTT em Secrets.h
// Certifique-se de usar WiFiSSLClient para conexão SSL.
// para não ssl (porta 1883) use WiFiClient normal.
//WiFiClient networkClient;
WiFiSSLClient networkClient;
// https://github.com/256dpi/arduino-mqtt
// Especificando tamanho de buffer 4096 bytes
MQTTClient mqttClient(4096);
// Se estamos conectados desde ligado
bool was_connected = false;
String senml = "";
unsigned long nextSendMeasurementsAt = 0;
// =================================================
// Configura informações de conexão MQTT
// =================================================
bool setupMqtt() {
senml.reserve(4096);
Serial.print("Conectando ao Servidor MQTT Tinamous na porta:");
Serial.println(MQTT_SERVERPORT);
Serial.print("Servidor:");
Serial.println(MQTT_SERVER);
mqttClient.begin(MQTT_SERVER, MQTT_SERVERPORT, networkClient);
// Manipula mensagens recebidas.
mqttClient.onMessage(messageReceived);
connectToMqttServer();
}
// =================================================
// Conecta ao servidor MQTT. Pode ser chamado
// repetidamente e será ignorado se já conectado
// =================================================
bool connectToMqttServer() {
if (mqttClient.connected()) {
return true;
}
Serial.println("Reconectando....");
Serial.println("verificando wifi...");
if (WiFi.status() != WL_CONNECTED) {
Serial.print("WiFi Não Conectado. Status: ");
Serial.print(WiFi.status(), HEX);
Serial.println();
delay(10000);
return false;
}
Serial.println("Conectando ao Servidor MQTT...");
if (!mqttClient.connect(MQTT_CLIENT_ID, MQTT_USERNAME, MQTT_PASSWORD)) {
Serial.println("Falha ao conectar ao Servidor MQTT.");
Serial.print("Erro: ");
Serial.print(mqttClient.lastError());
Serial.print(", Código de Retorno: ");
Serial.print(mqttClient.returnCode());
Serial.println();
if (mqttClient.lastError() == LWMQTT_CONNECTION_DENIED) {
Serial.println("Acesso negado. Verifique seu usuário e senha. Username deve ser 'DeviceName.AccountName' ex: MeuSensor.MinhaCasa");
}
if (mqttClient.lastError() == -6) {
Serial.println("Verifique se seu Arduino tem o Certificado SSL carregado para Tinmaous.com");
// Carregue o sketch Firmware Updater no Arduino.
// Use a utilidade Ferramentas -> Atualizador Firmware WiFi
}
// Espera 10s antes de tentar novamente.
delay(10000);
return false;
}
Serial.println("Conectado ao MQTT Tinamous!");
mqttClient.subscribe("/Tinamous/V1/Status.To/" DEVICE_USERNAME);
Serial.println("Inscrito no tópico status.to.");
// Diz oi.
publishTinamousStatus("Olá! Chave USB agora conectada. @ me com help para ajuda.");
was_connected = true;
return true;
}
// =================================================
// Loop para processamento mqtt.
// =================================================
void mqttLoop() {
// Chama de qualquer forma, não faz nada se já conectado.
connectToMqttServer();
mqttClient.loop();
}
// =================================================
// Publica mensagem de status na timeline Tinamous
// =================================================
void publishTinamousStatus(String message) {
Serial.println("Status: " + message);
mqttClient.publish("/Tinamous/V1/Status", message);
}
// =================================================
// Publica medições usando formato json simples
// =================================================
void publishTinamousJsonMeasurements(String json) {
Serial.println("Medição: " + json);
mqttClient.publish("/Tinamous/V1/Measurements/Json", json);
}
// =================================================
// Publica medições usando formato senml json
// =================================================
void publishTinamousSenMLMeasurements(String senml) {
Serial.println("Medição SenML: " + senml);
mqttClient.publish("/Tinamous/V1/Measurements/SenML", senml);
if (mqttClient.lastError() != 0) {
Serial.print("Erro MQTT: ");
Serial.print(mqttClient.lastError());
Serial.println();
}
Serial.println("Feito.");
}
// =================================================
// Mensagem recebida do servidor MQTT
// =================================================
void messageReceived(String &topic, String &payload) {
Serial.println("Mensagem do Tinamous no tópico: " + topic + " - " + payload);
// Se começa com @ é mensagem de status para este dispositivo.
if (payload.startsWith("@")) {
payload.toLowerCase();
if (handleStatusMessage(payload)) {
Serial.println("@ me mensagem de status tratada.");
return;
}
}
// Não recebeu comando esperado, então mensagem era para nós.
// Publica mensagem de ajuda.
publishTinamousStatus("Olá! Desculpe, não entendi a mensagem. @ me com help para ajuda.");
}
// =================================================
// Mensagem era Post de Status (provavelmente Alexa)
// =================================================
bool handleStatusMessage(String payload) {
char buffer[25];
// para 1..4 (mapeia para 0..3)
for (int port = 0; port < MAX_USB_PORTS; port++) {
sprintf(buffer, "turn on port-%01d", port + 1);
if (payload.indexOf(buffer) > 0) {
Serial.print("Ligar porta ");
Serial.println(port);
setUsb(port, true);
return true;
}
sprintf(buffer, "turn off port-%01d", port + 1);
if (payload.indexOf(buffer) > 0) {
Serial.print("Desligar porta ");
Serial.println(port);
setUsb(port, false);
return true;
}
}
// Nenhuma porta especificada, liga todas.
if (payload.indexOf("turn on") > 0) {
allOn();
return true;
}
if (payload.indexOf("turn off") > 0) {
allOff();
return true;
}
if (payload.indexOf("help") > 0) {
Serial.println("Enviando ajuda...");
publishTinamousStatus(
"Envie uma mensagem para mim (@" DEVICE_USERNAME ") então:"
"'Ligar Port-1' para ligar porta usb 1,"
"'Desligar Port-1' para desligar porta usb 1,"
"'Ligar' para ligar todas as portas usb,"
"'Desligar' para desligar todas as portas usb,"
" \n* Número da porta pode ser 1, 2, 3 ou 4."
);
return true;
}
Serial.print("Mensagem de status desconhecida: ");
Serial.println(payload);
return false;
}
UsbControl.ino Arduino
Este arquivo é responsável pelas iterações com a comutação de energia USB.
// ======================================
// Controle de energia da porta USB
// e indicação.
// ======================================
// Determina se uma ou mais portas estão alimentadas
bool hasPoweredPorts() {
for (int channel = 0; channel < MAX_USB_PORTS; channel++) {
if (usb_port_state[channel]) {
return true;
}
}
return false;
}
// Verifica se dispositivos USB têm falha (não podemos
// dizer qual na de 4 portas)
bool checkFault(int channel) {
if (!digitalRead(usb_fault_pin[channel])) {
// 4 portas tem indicador de falha único, não continua verificando
if (has_usb_fault) {
return true;
}
Serial.print("FALHA! usb: ");
Serial.println(channel);
// Desliga canal USB.
setUsb(channel, false);
// Faz LEDs vermelhos.
SetLeds(channel, true, false);
if (!has_usb_fault) {
// TODO: Enviar mensagem apenas uma vez!
//String message = "Falha detectada na Porta USB ";
//message = message + String(channel + 1);
//publishTinamousStatus(message);
has_usb_fault = true;
}
return true;
}
return false;
}
// Liga TODAS as portas USB
void allOn() {
for(int channel =0; channel < MAX_USB_PORTS; channel++) {
setUsb(channel, true);
}
}
// Desliga TODAS as portas USB
void allOff() {
for(int channel =0; channel < MAX_USB_PORTS; channel++) {
setUsb(channel, false); // Corrigido: era true no original
}
}
// ================================================
// Define estado de saída USB
// ================================================
void setUsb(int channel, bool on) {
Serial.print("Comutar canal USB ");
Serial.print(channel);
Serial.print(" para ");
Serial.println(on);
if (on) {
resetStats();
SetLeds(channel, on, true);
digitalWrite(usb_enable_pin[channel], LOW);
} else {
SetLeds(channel, on, true);
digitalWrite(usb_enable_pin[channel], HIGH);
}
usb_port_state[channel] = on;
String message = "Porta USB ";
message = message + String(channel + 1);
message = message + " agora ";
if (on) {
message = message + "habilitada.";
} else {
message = message + "desabilitada.";
}
publishTinamousStatus(message);
// força envio de corrente/tensão após um ou poucos segundos.
sentNextPublishAt(1);
// Se modo do canal é ciclar off depois on para
// sinal off, liga canal de volta após alguns segundos de atraso.
if (!on && usb_power_mode[channel] == 1) {
// Agenda canal para ligar novamente em n segundos.
usb_power_switch_on_at[channel] = millis() + 5000;
}
}
// ================================================
// Define LEDs de estado para indicar canal ligado/desligado
// Não estão conectados ao interruptor USB então
// podem rodar independentemente.
// ================================================
void SetLeds(int channel, bool on, bool green) {
if (!on) {
digitalWrite(led_pin[channel][0], LOW);
digitalWrite(led_pin[channel][1], LOW);
return;
}
if (led_pin[channel][0] == led_pin[channel][1]) {
// 4 Portas usa LED de cor única.
// Não temos como mostrar falhas (além de piscar LEDs).
digitalWrite(led_pin[channel][0], HIGH);
} else {
// 2 Portas usa LED bi-color e falhas individuais
// então mostra vermelho/verde baseado no status.
if (green) {
digitalWrite(led_pin[channel][0], HIGH);
digitalWrite(led_pin[channel][1], LOW);
} else {
digitalWrite(led_pin[channel][0], LOW);
digitalWrite(led_pin[channel][1], HIGH);
}
}
}
WiFiClient.ino Arduino
Este arquivo lida com conectividade WiFi.
// ======================================
// Manipulação WiFi
// ======================================
#include "Secrets.h"
char ssid[] = SECRET_SSID;
char pass[] = SECRET_PASS;
int status = WL_IDLE_STATUS;
void setupWiFi() {
Serial.println("Conectando ao WiFi...");
// verifica presença do shield:
if (WiFi.status() == WL_NO_SHIELD) {
Serial.println("Shield WiFi não presente");
// não continua:
while (true);
}
// tenta conectar à rede WiFi:
while (status != WL_CONNECTED) {
Serial.print("Tentando conectar ao SSID WPA: ");
Serial.println(ssid);
// Conecta à rede WPA/WPA2:
status = WiFi.begin(ssid, pass);
// espera 10 segundos para conexão:
delay(10000);
}
// você está conectado agora, então imprima os dados:
Serial.println("Você está conectado à rede");
printCurrentNet();
printWiFiData();
}
// ---------------------------------------
// WiFi
void printWiFiData() {
// imprime endereço IP do shield WiFi:
IPAddress ip = WiFi.localIP();
Serial.print("Endereço IP: ");
Serial.println(ip);
Serial.println(ip);
// imprime endereço MAC:
byte mac[6];
WiFi.macAddress(mac);
Serial.print("Endereço MAC: ");
Serial.print(mac[5], HEX);
Serial.print(":");
Serial.print(mac[4], HEX);
Serial.print(":");
Serial.print(mac[3], HEX);
Serial.print(":");
Serial.print(mac[2], HEX);
Serial.print(":");
Serial.print(mac[1], HEX);
Serial.print(":");
Serial.println(mac[0], HEX);
}
void printCurrentNet() {
// imprime SSID da rede à qual está conectado:
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// imprime endereço MAC do roteador ao qual está conectado:
byte bssid[6];
WiFi.BSSID(bssid);
Serial.print("BSSID: ");
Serial.print(bssid[5], HEX);
Serial.print(":");
Serial.print(bssid[4], HEX);
Serial.print(":");
Serial.print(bssid[3], HEX);
Serial.print(":");
Serial.print(bssid[2], HEX);
Serial.print(":");
Serial.print(bssid[1], HEX);
Serial.print(":");
Serial.println(bssid[0], HEX);
// imprime força do sinal recebido:
long rssi = WiFi.RSSI();
Serial.print("força do sinal (RSSI):");
Serial.println(rssi);
// imprime tipo de criptografia:
byte encryption = WiFi.encryptionType();
Serial.print("Tipo de Criptografia:");
Serial.println(encryption, HEX);
Serial.println();
}
String hostName = "www.google.com";
void doPing() {
Serial.print("Pingando ");
Serial.print(hostName);
Serial.print(": ");
int pingResult = WiFi.ping(hostName);
if (pingResult >= 0) {
Serial.print("SUCESSO! RTT = ");
Serial.print(pingResult);
Serial.println(" ms");
} else {
Serial.print("FALHOU! Código de erro: ");
Serial.println(pingResult);
}
}
void reconnectWiFi() {
// tenta reconectar à rede WiFi se a conexão foi perdida:
while (status != WL_CONNECTED) {
Serial.print("Tentando conectar ao SSID WPA: ");
Serial.println(ssid);
// Conecta à rede WPA/WPA2:
status = WiFi.begin(ssid, pass);
if (status == WL_CONNECTED) {
Serial.print("Você está reconectado à rede");
printCurrentNet();
printWiFiData();
return;
}
delay(5000);
}
}
Secrets.h Arduino
Você precisa atualizar isso com suas próprias configurações.
#define SECRET_SSID ""
#define SECRET_PASS ""
/************************* Configuração MQTT Tinamous *********************************/
#define MQTT_SERVER ".tinamous.com"
#define MQTT_SERVERPORT 8883
#define MQTT_USERNAME "."
#define MQTT_PASSWORD "A senha do dispositivo"
#define MQTT_CLIENT_ID "Um client id aleatório"
#define DEVICE_USERNAME ""
Peças Personalizadas e Gabinetes
Esta é a melhor aposta se você não sabe como vai conectar. Tem furos para o Arduino, bloco de terminais e USB micro adicional.
Esta é a versão com todos os conectores, mas não inclui as primeiras camadas de texto que algumas impressoras podem ter dificuldade.
Esta é a versão mais simples e mais rápida de imprimir.
Esquemáticos


Envie para OSHPark ou DirtyPCBs para fazer o seu próprio.
arduinostandaloneusbswitch-4port_q16AoF01Aq.brd
arduinostandaloneusbswitch-v2_Xd45dtjndI.sch

Repositório GitHub USB Power Switcher
Você quer: pasta Arduino/StandAlone/ e a versão de 4 portas.
https://github.com/ThingySticks/USBPowerSwitcher

Processo de manufatura
- Dominando a Instrução Switch em C#: Sintaxe, Exemplos e Boas Práticas
- TI Apresenta Carregadores de Bateria Buck-Boost BQ25790/BQ25792 Ultra-Compactos e Alta Eficiência
- Sensor Eficiente de Queda de Energia 230 VAC para Raspberry Pi – Baixo Custo, Compacto e Seguro
- Chave Inteligente de Energia AC Controlada por SMS com Raspberry Pi e Hologram
- Energia Eólica: Convertendo o Movimento do Ar em Eletricidade Limpa
- Dominando Martelos de Potência: Guia Completo para Ferraria Moderna
- Entendendo Prensas de Potência Automáticas: Características, Benefícios e Aplicações
- Entenda Mandris de Potência (Power Chucks): Definição, Usos e Benefícios
- Entendendo Mandris de Potência: Guia Completo para Usinagem de Precisão
- Aproveitando a Energia Hidrelétrica: Um Guia Completo