From d573476c70ed3b68fffcd8ad363f1ba22c2361b7 Mon Sep 17 00:00:00 2001 From: Ricardo Carneiro <71648276+ricarneiro@users.noreply.github.com> Date: Tue, 12 May 2026 10:36:28 -0300 Subject: [PATCH] fix: conectar com BT 4.0 --- .claude/settings.local.json | 5 +- S3/{ => KVMote_ESP32S3}/KVMote_ESP32S3.ino | 1 + frontend/dist/index.html | 11 +-- internal/transport/ble_windows.go | 105 ++++++++++++++++----- 4 files changed, 89 insertions(+), 33 deletions(-) rename S3/{ => KVMote_ESP32S3}/KVMote_ESP32S3.ino (99%) diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 4f91c7f..b80f9a1 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -2,7 +2,10 @@ "permissions": { "allow": [ "Bash(go build:*)", - "Bash(git:*)" + "Bash(git:*)", + "Bash(cmd.exe *)", + "Bash(go env *)", + "Bash(go install *)" ] } } diff --git a/S3/KVMote_ESP32S3.ino b/S3/KVMote_ESP32S3/KVMote_ESP32S3.ino similarity index 99% rename from S3/KVMote_ESP32S3.ino rename to S3/KVMote_ESP32S3/KVMote_ESP32S3.ino index 9f48eb5..5948e72 100644 --- a/S3/KVMote_ESP32S3.ino +++ b/S3/KVMote_ESP32S3/KVMote_ESP32S3.ino @@ -263,6 +263,7 @@ void setup() { // BLE — NUS BLEDevice::init("KVMote"); + pServer = BLEDevice::createServer(); pServer->setCallbacks(new ServerCallbacks()); diff --git a/frontend/dist/index.html b/frontend/dist/index.html index 6292410..ec091a1 100644 --- a/frontend/dist/index.html +++ b/frontend/dist/index.html @@ -162,16 +162,11 @@
- +
-
-
- -
-
- -
+
+
diff --git a/internal/transport/ble_windows.go b/internal/transport/ble_windows.go index 22587c8..c1cf9ca 100644 --- a/internal/transport/ble_windows.go +++ b/internal/transport/ble_windows.go @@ -4,12 +4,24 @@ import ( "context" "errors" "fmt" + "os" "sync" "time" "tinygo.org/x/bluetooth" ) +func bleLog(msg string) { + line := fmt.Sprintf("[BLE] %s | %s\n", time.Now().Format("15:04:05.000"), msg) + fmt.Print(line) + f, err := os.OpenFile("kvmote_debug.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + return + } + defer f.Close() + f.WriteString(line) +} + var ( NusServiceUUID = bluetooth.NewUUID([16]byte{0x6e, 0x40, 0x00, 0x01, 0xb5, 0xa3, 0xf3, 0x93, 0xe0, 0xa9, 0xe5, 0x0e, 0x24, 0xdc, 0xca, 0x9e}) NusRxUUID = bluetooth.NewUUID([16]byte{0x6e, 0x40, 0x00, 0x02, 0xb5, 0xa3, 0xf3, 0x93, 0xe0, 0xa9, 0xe5, 0x0e, 0x24, 0xdc, 0xca, 0x9e}) @@ -45,15 +57,19 @@ func (t *RealBleTransport) Detect(ctx context.Context) (bool, error) { } foundChan := make(chan bluetooth.Address, 1) - err := t.adapter.Scan(func(adapter *bluetooth.Adapter, result bluetooth.ScanResult) { - if result.LocalName() == "KVMote" { - adapter.StopScan() - foundChan <- result.Address - } - }) - if err != nil { - return false, err - } + go func() { + t.adapter.Scan(func(adapter *bluetooth.Adapter, result bluetooth.ScanResult) { + hasUUID := result.HasServiceUUID(NusServiceUUID) + bleLog(fmt.Sprintf("visto: nome=%q hasNUS=%v addr=%s", result.LocalName(), hasUUID, result.Address.String())) + if result.LocalName() == "KVMote" || hasUUID { + adapter.StopScan() + select { + case foundChan <- result.Address: + default: + } + } + }) + }() select { case addr := <-foundChan: @@ -77,24 +93,65 @@ func (t *RealBleTransport) Connect(ctx context.Context) error { addr := t.address t.mu.Unlock() - fmt.Println("[BLE] Conectando...") - device, err := t.adapter.Connect(addr, bluetooth.ConnectionParams{}) + var device bluetooth.Device + var services []bluetooth.DeviceService + var err error + + for cycle := 1; cycle <= 3; cycle++ { + if cycle > 1 { + bleLog(fmt.Sprintf("Reconectando (ciclo %d)...", cycle)) + time.Sleep(1 * time.Second) + } + + bleLog(fmt.Sprintf("Conectando (ciclo %d)...", cycle)) + device, err = t.adapter.Connect(addr, bluetooth.ConnectionParams{}) + if err != nil { + bleLog(fmt.Sprintf(" Connect erro: %v", err)) + continue + } + + t.mu.Lock() + t.device = device + t.mu.Unlock() + + // Delay crucial para BT 4.0 estabilizar a conexão antes de pedir serviços + bleLog("Aguardando estabilização (2s)...") + time.Sleep(2 * time.Second) + + bleLog("DiscoverServices...") + services, err = device.DiscoverServices(nil) + if err != nil { + bleLog(fmt.Sprintf(" DiscoverServices erro: %v", err)) + // Tenta mais uma vez após um pequeno delay antes de desistir do ciclo + time.Sleep(1 * time.Second) + bleLog("DiscoverServices (retry)...") + services, err = device.DiscoverServices(nil) + if err != nil { + bleLog(fmt.Sprintf(" DiscoverServices retry erro: %v", err)) + go func() { defer func() { recover() }(); device.Disconnect() }() + continue + } + } + break + } if err != nil { - return err - } - - t.mu.Lock() - t.device = device - t.mu.Unlock() - - fmt.Println("[BLE] Buscando Serviço...") - services, err := device.DiscoverServices([]bluetooth.UUID{NusServiceUUID}) - if err != nil || len(services) == 0 { - return errors.New("serviço não encontrado") + return fmt.Errorf("erro ao descobrir serviços: %w", err) } - fmt.Println("[BLE] Buscando RX...") - chars, err := services[0].DiscoverCharacteristics([]bluetooth.UUID{NusRxUUID}) + bleLog(fmt.Sprintf("Serviços encontrados: %d", len(services))) + nusIdx := -1 + for i, s := range services { + bleLog(fmt.Sprintf(" [%d] %s", i, s.UUID().String())) + if s.UUID() == NusServiceUUID { + nusIdx = i + } + } + if nusIdx < 0 { + return errors.New("serviço NUS não encontrado") + } + + bleLog("Buscando característica RX...") + chars, err := services[nusIdx].DiscoverCharacteristics([]bluetooth.UUID{NusRxUUID}) if err != nil || len(chars) == 0 { return errors.New("característica não encontrada") }