Desenvolvimento de interface
gráfica com linguagem GO. Você pode rodar no Linux, IOS, Android, ou seja, ele
roda em todo lugar sem modificação! É desse assunto que vamos falar no vídeo de
hoje, no qual vamos controlar um ESP32 com C++ do Arduino IDE, o que te
possibilita criar automações poderosíssimas.
Vou, então, te apresentar um
exemplo de user interface com Fyne feito em linguagem Go, isso em uma aplicação
com ESP32.
Quer comprar seu ESP32?
Compre nesse link e receba em 10 dias: https://s.click.aliexpress.com/e/_d8KYBUq
RECURSOS USADOS
- ESP32
- 6 Leds
- 6 Resistores 330 ohm
- Protoboard
- Jumpers
- Computador (servidor windows)
CLIENTE - SERVIDOR
MONTAGEM
INSTALAÇÃO DO AMBIENTE
- Instalação do Ambiente Plugins VSC
- Instalação do Ambiente FYNE
Variável de Ambiente GOPATH
Verificando a Variável de Ambiente GOPAT
Testando Golang
CÓDIGO SERVER
Fluxograma
Código Servidor
Imports e Variáveis
package main // Imports necessários import ( "bufio" "fmt" "net" "strings" "time" "fyne.io/fyne" "fyne.io/fyne/app" "fyne.io/fyne/dialog" "fyne.io/fyne/layout" "fyne.io/fyne/widget" ) // Objeto de conexão http com o ESP var ESP32 net.Conn // Label que indica o estado de conexão do ESP var lblConn *widget.Label // Label que indica o estado de envio de comandos var lblEnviando *widget.Label // Variável auxiliar var aguardaConfirmação = false
main
func main() { // Iniciamos o ponteiro que receberá a conexão do ESP como nulo ESP32 = nil // Criamos uma goroutine que inicia a conexão com o ESP go conexaoESP32() // Construímos a janela principal initWindow() }
conexaoESP32
// Função que inicia as conexões com o ESP func conexaoESP32() { // Porta de conexão PORT := ":8001" // Inicia o listen // Possui 2 retornos, o primeiro é o objeto Listen e o segundo é o erro caso exista l, err := net.Listen("tcp4", PORT) // Se acontecer algum erro, aborta o programa if err != nil { fmt.Println(err) return } fmt.Println("Listen ok") // Antes de sair da função, fechamos o listen defer l.Close() fmt.Println("Waiting for connections...")
for { // Aguarda conexões (Accept) // Possui 2 retornos, o primeiro é o objeto referente a conexão com o client e o segundo é o erro caso exista ESP32, err = l.Accept() if err != nil { fmt.Println(err) break } // Chamamos a função que recebe as mensagens do client que se conectou handleConnection() } // Caso ocorra algum erro, reiniciamos o servidor go conexaoESP32() }
handleConnection
// Função que recebe as mensagems do ESP func handleConnection() { // Ao terminar a função, fecha a conexão com o ESP defer ESP32.Close() // Ao terminar a função, indica ESP desconectado defer lblConn.SetText("Desconectado") // Se o ESP não foi instanciado, aborta função if ESP32 == nil { fmt.Println("handleConnection aborted") return } // Seta o texto da label indicando ESP conectado lblConn.SetText("Conectado") // Exibe mensagem informando o IP do client que se conectou no servidor fmt.Printf("Serving %s\n", ESP32.RemoteAddr().String())
// Loop infinito for { // Declaramos uma variável que receberá as mensagens do ESP msg := "" // Variável que receberá a mensagem de erro var err error // Goroutine que recebe a mensagem do ESP go func() { msg, err = bufio.NewReader(ESP32).ReadString('\n') }() // Aguardamos a mensagem até 3 segundos de timeout start := time.Now() for msg == "" { if time.Second*3 < time.Since(start) { // Se atingiu 3 segundos, abortamos a função fmt.Println("Timeout, desconectando...") return } }
// Se ocorreu algum erro // Exibimos e abortamos a função if err != nil { fmt.Println(err) break } // Retiramos o espaço da mensagem msg = strings.TrimSpace(string(msg)) // Se a mensagem corresponde a "STOP" if msg == "STOP" { // Abortamos a função break } // Se estamos aguardando uma confirmação if aguardaConfirmação && msg == "OK" { // Indicamos pela label de estado de envio "OK" lblEnviando.SetText("OK") // Mudamos o estado da variável auxiliar para false aguardaConfirmação = false } else { // Se não for nenhuma mensagem esperada, exibimos para debug fmt.Println(msg) } } }
initWindow
// Função que constrói a janela principal func initWindow() { // Iniciamos uma aplicação app := app.New() // Iniciamos uma janela w := app.NewWindow("Hello") // Criamos a label responsável por indicar o estado de conexão do ESP lblConn = widget.NewLabel("Desconectado") // Criamos a label responsável por indicar o estado de envio de comandos para o ESP lblEnviando = widget.NewLabel("Status do envio") // Variáveis auxiliares que indicam os estados dos leds statusLed1 := false statusLed2 := false statusLed3 := false statusLed4 := false statusLed5 := false statusLed6 := false // Label de boas vindas labelTitle := widget.NewLabel("Hello Fyne!")
// Criamos o botão que envia ON/OFF referente ao led 1 btnLed1 := widget.NewButton("Led 1", func() { var msg = "" if ESP32 == nil { msg = "Erro ao enviar comando (Desconectado)" } else { statusLed1 = !statusLed1 if statusLed1 { msg = enviaComando("ON1") } else { msg = enviaComando("OFF1") } } d := dialog.NewInformation("Envio de comando", msg, w) d.Show() })
Criamos os 6 botões conforme o
código acima
Mudando apenas o nome do
botão, os comandos enviados e a variável statusLed
// Criamos o botão que fecha o programa btnQuit := widget.NewButton("Quit", func() { app.Quit() }) // Inserimos a label "Hello Fyne" dentro de um container // Para podermos centralizá-la lblTitleHContainer := fyne.NewContainerWithLayout(layout.NewHBoxLayout(), layout.NewSpacer(), labelTitle, layout.NewSpacer())
// Setamos o conteúdo da janela principal // Separando todos os elementos por vírgula // A ordem em que eles são adicionados é a ordem que aparecerão na janela verticalmente w.SetContent(widget.NewVBox( lblConn, lblEnviando, layout.NewSpacer(), lblTitleHContainer, layout.NewSpacer(), btnLed1, btnLed2, btnLed3, btnLed4, btnLed5, btnLed6, btnQuit, )) // Centralizamos a janela na tela w.CenterOnScreen() // Setamos o tamanho fixo da janela w.Resize(fyne.NewSize(300, 400)) // Mostramos/executamos a janela w.ShowAndRun() }
EnviaComando
// Função que envia um comando para o ESP // Retorna a mensagem a ser exibida na janela func enviaComando(cmd string) string { // Indica na label que estamos enviando o comando lblEnviando.SetText("Enviando...") // Envia o comando _, err := ESP32.Write([]byte(cmd)) // Se ocorreu algum erro if err != nil { // Exibe mensagens lblConn.SetText("Desconectado") lblEnviando.SetText("Falhou") fmt.Println(err.Error()) // Retornamos uma mensagem a ser exibida pela janela principal return "Erro ao enviar comando" } // Se não ocorreu nenhum erro // Setamos a variável auxiliar como true aguardaConfirmação = true // Retornamos uma mensagem a ser exibida pela janela principal return "O comando " + cmd + " foi enviado" }
CÓDIGO CLIENT
Fluxograma
Declarações e variáveis
// Bibliotecas necessárias #include <WiFi.h> #include <WiFiMulti.h> // Dados de acesso a rede wifi #define SSID "SSID" #define PASSWORD "SENHA" // Dados de conexão com o servidor go const uint16_t port = 8001; // porta const char * host = "192.168.0.103"; // ip // Objeto utilizado para conexão com a rede WiFiMulti wiFiMulti; // Objeto utilizado para conexão com o servidor WiFiClient client; // Relé usado como exemplo const int led1 = 23, led2 = 22, led3 = 21, led4 = 32, led5 = 33, led6 = 25;
Setup
void setup() { // Inicia velocidade da serial Serial.begin(115200); // Seta os pinos dos leds como pinos de saída pinMode(led1, OUTPUT); pinMode(led2, OUTPUT); pinMode(led3, OUTPUT); pinMode(led4, OUTPUT); pinMode(led5, OUTPUT); pinMode(led6, OUTPUT); // Conecta WiFi setupWiFi(); // Conecta com o servidor Serial.print("Connecting to "); Serial.println(host); if(client.connect(host, port)) Serial.println("Conectado com o servidor Go"); else Serial.println("Erro ao conectar com o servidor Go"); }
Loop
void loop() { // Verifica se existem mensagens a serem lidas if (client.available() > 0) { // Efetua a leitura das mensagens String cmd = client.readStringUntil('\r'); Serial.println(cmd); // Executa o comando de acordo com a mensagem executeCommand(cmd); } // Verifica se a conexão está ativa verifyConnection(); // Enviamos um "OK" indicando que o ESP está ativo client.print("OK\n"); // A cada 1 segundo delay(1000); }
executeCommand
// Função que atua nos leds de acordo com o comando void executeCommand(String cmd) { if(cmd == "ON1") digitalWrite(led1, HIGH); else if(cmd == "OFF1") digitalWrite(led1, LOW); else if(cmd == "ON2") digitalWrite(led2, HIGH); else if(cmd == "OFF2") digitalWrite(led2, LOW); else if(cmd == "ON3") digitalWrite(led3, HIGH); else if(cmd == "OFF3") digitalWrite(led3, LOW); else if(cmd == "ON4") digitalWrite(led4, HIGH); else if(cmd == "OFF4") digitalWrite(led4, LOW); else if(cmd == "ON5") digitalWrite(led5, HIGH); else if(cmd == "OFF5") digitalWrite(led5, LOW); else if(cmd == "ON6") digitalWrite(led6, HIGH); else if(cmd == "OFF6") digitalWrite(led6, LOW); }
verifyConnection
// Função que verifica se caiu a conexão com o servidor, se sim, efetua a reconexão void verifyConnection() { if(!client.connected()) { client.stop(); Serial.println("Desconectado, reconectando..."); if(client.connect(host, port)) Serial.println("Conectado com o servidor Go"); else Serial.println("Erro ao conectar com o servidor Go"); } }
setupWiFi
// Função que inicia o WiFi void setupWiFi() { // Modo Access Point wiFiMulti.addAP(SSID, PASSWORD); Serial.println(); Serial.print("Waiting for WiFi... "); while(wiFiMulti.run() != WL_CONNECTED) { Serial.print("."); delay(500); } Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); }
1 Comentários
Fernando, meu amigo, desculpe minha ignorância, eu me interessei muito pelo assunto, tenho condições de implementar tudo (soft + hard) mas não consegui entender do que se trata. Qual é a finalidade disso tudo? É uma automação de que função, processo ou atividade?
ResponderExcluirNovamente peço desculpas por minha deficiência, porém você é uma fonte rica demais para eu desprezar a chance de evoluir minhas habilidades com seus conhecimentos. Por favor me esclareça em gleinerteruel@gmail.com.