BLE_API.md 6.1 KB

AI-Light BLE 接口文档

设备信息

项目
设备名称 AI-Light
Service UUID b8b7e001-7a6b-4f4f-9a8b-11c0ffee0001
Characteristic UUID b8b7e002-7a6b-4f4f-9a8b-11c0ffee0001
Characteristic 属性 READ / WRITE / NOTIFY

支持的模式

模式 说明 灯效
init 初始化状态 三色一起呼吸
thinking 思考中 绿→黄→红 连贯跑马灯
ai AI 处理中 三色柔和波浪
busy 忙碌状态 黄灯淡入淡出
success 成功状态 绿灯常亮
error 错误状态 红灯快速闪烁
alarm 警告状态 红黄交替警灯
traffic 交通灯模式 绿→黄→红 循环
off 关闭 全灭
red 红灯 红灯常亮
yellow 黄灯 黄灯常亮
green 绿灯 绿灯常亮
idle 空闲(自动转为 traffic) 同 traffic

超时规则

  • 普通模式运行 5分钟 → 自动进入 traffic
  • traffic 运行 10分钟 → 自动进入 off

Go 客户端示例

依赖

go mod init ailight-client
go get tinygo.org/x/bluetooth

完整代码

package main

import (
	"fmt"
	"os"
	"time"

	"tinygo.org/x/bluetooth"
)

var (
	serviceUUID  = bluetooth.NewUUID([16]byte{0xb8, 0xb7, 0xe0, 0x01, 0x7a, 0x6b, 0x4f, 0x4f, 0x9a, 0x8b, 0x11, 0xc0, 0xff, 0xee, 0x00, 0x01})
	modeCharUUID = bluetooth.NewUUID([16]byte{0xb8, 0xb7, 0xe0, 0x02, 0x7a, 0x6b, 0x4f, 0x4f, 0x9a, 0x8b, 0x11, 0xc0, 0xff, 0xee, 0x00, 0x01})
)

func main() {
	if len(os.Args) < 2 {
		fmt.Println("Usage: ailight-client <mode>")
		fmt.Println("Modes: init, thinking, ai, busy, success, error, alarm, traffic, off, red, yellow, green")
		os.Exit(1)
	}
	mode := os.Args[1]

	adapter := bluetooth.DefaultAdapter
	if err := adapter.Enable(); err != nil {
		fmt.Printf("Failed to enable BLE adapter: %v\n", err)
		os.Exit(1)
	}

	// 扫描并连接设备
	fmt.Println("Scanning for AI-Light...")
	found := false
	var device bluetooth.Device

	done := make(chan struct{})
	go func() {
		adapter.Scan(func(adapter *bluetooth.Adapter, scanResult bluetooth.ScanResult) {
			if scanResult.LocalName() == "AI-Light" {
				adapter.StopScan()
				found = true
				var err error
				device, err = adapter.Connect(scanResult.Address, bluetooth.ConnectionParams{})
				if err != nil {
					fmt.Printf("Failed to connect: %v\n", err)
					os.Exit(1)
				}
				close(done)
			}
		})
	}()

	select {
	case <-done:
		// 连接成功
	case <-time.After(10 * time.Second):
		fmt.Println("Connection timeout")
		os.Exit(1)
	}

	if !found {
		fmt.Println("Device not found")
		os.Exit(1)
	}

	fmt.Println("Connected to AI-Light")

	// 发现服务和特征
	services, err := device.DiscoverServices([]bluetooth.UUID{serviceUUID})
	if err != nil {
		fmt.Printf("Failed to discover services: %v\n", err)
		os.Exit(1)
	}

	if len(services) == 0 {
		fmt.Println("Service not found")
		os.Exit(1)
	}

	characteristics, err := services[0].DiscoverCharacteristics([]bluetooth.UUID{modeCharUUID})
	if err != nil {
		fmt.Printf("Failed to discover characteristics: %v\n", err)
		os.Exit(1)
	}

	if len(characteristics) == 0 {
		fmt.Println("Characteristic not found")
		os.Exit(1)
	}

	// 写入模式
	_, err = characteristics[0].WriteString(mode)
	if err != nil {
		fmt.Printf("Write failed: %v\n", err)
		os.Exit(1)
	}

	fmt.Printf("Sent mode: %s\n", mode)
	
	// 断开连接
	device.Disconnect()
	fmt.Println("Disconnected")
}

使用方式

# 编译
go build -o ailight-client main.go

# 切换模式
./ailight-client thinking
./ailight-client busy
./ailight-client success
./ailight-client error
./ailight-client traffic
./ailight-client off

封装为函数

package ailight

import (
	"fmt"
	"time"

	"tinygo.org/x/bluetooth"
)

var (
	serviceUUID  = bluetooth.NewUUID([16]byte{0xb8, 0xb7, 0xe0, 0x01, 0x7a, 0x6b, 0x4f, 0x4f, 0x9a, 0x8b, 0x11, 0xc0, 0xff, 0xee, 0x00, 0x01})
	modeCharUUID = bluetooth.NewUUID([16]byte{0xb8, 0xb7, 0xe0, 0x02, 0x7a, 0x6b, 0x4f, 0x4f, 0x9a, 0x8b, 0x11, 0xc0, 0xff, 0xee, 0x00, 0x01})
)

// SetMode 设置灯效模式
func SetMode(mode string) error {
	adapter := bluetooth.DefaultAdapter
	if err := adapter.Enable(); err != nil {
		return fmt.Errorf("enable adapter: %w", err)
	}

	// 扫描设备
	var device bluetooth.Device
	found := make(chan bool, 1)

	go func() {
		adapter.Scan(func(adapter *bluetooth.Adapter, scanResult bluetooth.ScanResult) {
			if scanResult.LocalName() == "AI-Light" {
				adapter.StopScan()
				var err error
				device, err = adapter.Connect(scanResult.Address, bluetooth.ConnectionParams{})
				found <- err == nil
			}
		})
	}()

	select {
	case ok := <-found:
		if !ok {
			return fmt.Errorf("connect failed")
		}
	case <-time.After(10 * time.Second):
		return fmt.Errorf("scan timeout")
	}
	defer device.Disconnect()

	// 发现服务
	services, err := device.DiscoverServices([]bluetooth.UUID{serviceUUID})
	if err != nil || len(services) == 0 {
		return fmt.Errorf("service not found")
	}

	// 发现特征
	characteristics, err := services[0].DiscoverCharacteristics([]bluetooth.UUID{modeCharUUID})
	if err != nil || len(characteristics) == 0 {
		return fmt.Errorf("characteristic not found")
	}

	// 写入模式
	_, err = characteristics[0].WriteString(mode)
	if err != nil {
		return fmt.Errorf("write failed: %w", err)
	}

	return nil
}

调用示例

package main

import (
	"fmt"
	"ailight"
)

func main() {
	// AI 开始思考
	ailight.SetMode("thinking")
	
	// 执行任务...
	
	// 任务完成
	ailight.SetMode("success")
	
	// 出错
	ailight.SetMode("error")
	
	// 关闭
	ailight.SetMode("off")
}

平台支持

平台 支持情况 备注
Linux ✅ 完整支持 需要 BlueZ
Windows ⚠️ 部分支持 需要额外配置
Raspberry Pi ✅ 完整支持 推荐用于部署

注意事项

  1. 连接稳定性:每次发送指令需要重新扫描和连接,建议封装连接池
  2. 超时处理:扫描和连接都设置了 10 秒超时
  3. 并发控制:BLE 连接不支持并发,需要加锁
  4. 重连机制:建议实现自动重连逻辑