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.