keer_zu 发表于 2025-5-25 03:53

通过蓝牙和esp32通信

可以连接和写入:

PC端python:

import asyncio
import json
from bleak import BleakClient, discover

class BluetoothInterface:
    def __init__(self, device_name="ESP32-led", tx_uuid=None, rx_uuid=None):
      """
      初始化蓝牙接口
      
      :param device_name: 目标设备名称,默认"ESP32-led"
      :param tx_uuid: 发送数据的Characteristic UUID
      :param rx_uuid: 接收数据的Characteristic UUID
      """
      self.device_name = device_name
      self.tx_uuid = tx_uuid or "00001101-0000-1000-8000-00805F9B34FB"
      self.rx_uuid = rx_uuid or "00001101-0000-1000-8000-00805F9B34FB"
      self.client = None
      self.connected = False
      self.receive_callback = None

    async def connect(self):
      """连接到蓝牙设备"""
      devices = await discover()
      for d in devices:
            if d.name == self.device_name:
                self.device_address = d.address
                break
      else:
            raise Exception(f"未找到设备: {self.device_name}")

      self.client = BleakClient(self.device_address)
      try:
            await self.client.connect()
            self.connected = True
            print("蓝牙连接成功")
      except Exception as e:
            print(f"连接失败: {str(e)}")
            self.connected = False

    async def disconnect(self):
      """断开蓝牙连接"""
      if self.connected:
            await self.client.disconnect()
            self.connected = False
            print("蓝牙已断开")

    async def send_data(self, data):
      """发送JSON数据"""
      if not self.connected:
            raise Exception("未连接设备")
      
      try:
            json_str = json.dumps(data) + "\r\n"# 添加帧结束符
            await self.client.write_gatt_char(self.tx_uuid, json_str.encode('utf-8'))
            print(f"发送数据: {json_str.strip()}")
      except Exception as e:
            print(f"发送失败: {str(e)}")

    def register_receive_callback(self, callback):
      """注册数据接收回调函数"""
      self.receive_callback = callback

    async def _receive_loop(self):
      """内部接收循环"""
      while self.connected:
            try:
                data = await self.client.read_gatt_char(self.rx_uuid)
                cleaned_data = data.decode('utf-8').strip('\x0d\x0a')
                if cleaned_data:
                  json_data = json.loads(cleaned_data)
                  if self.receive_callback:
                        self.receive_callback(json_data)
            except Exception as e:
                print(f"接收错误: {str(e)}")
                await asyncio.sleep(1)

    async def start_receive(self):
      """启动数据接收"""
      if self.connected:
            asyncio.create_task(self._receive_loop())

async def main():
    # 配置UUID(根据实际设备修改)
    DEVICE_NAME = "ESP32-led"
    TX_UUID = "0000ffe1-0000-1000-8000-00805f9b34fb"# 替换为实际发送UUID
    RX_UUID = "0000ffe1-0000-1000-8000-00805f9b34fb"# 替换为实际接收UUID

    interface = BluetoothInterface(
      device_name=DEVICE_NAME,
      tx_uuid=TX_UUID,
      rx_uuid=RX_UUID
    )

    await interface.connect()
    interface.register_receive_callback(print)# 打印接收数据

    try:
      await interface.start_receive()
      
      while True:
            status = input("请输入状态(start/listening/thinking/speaking/stop): ").strip()
            score = input("请输入评分(0-10): ").strip()
            
            # 构造数据包
            data_packet = {
                "status": status,
                "score": score
            }
            
            # 发送数据
            await interface.send_data(data_packet)
            await asyncio.sleep(0.5)# 防止快速发送导致丢包
            
    except KeyboardInterrupt:
      print("\n程序终止")
    finally:
      await interface.disconnect()

if __name__ == "__main__":
    # 运行主程序
    asyncio.run(main())

esp32:
#include <ArduinoJson.h>
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

// 根据实际硬件定义LED引脚
#ifndef LED_BUILTIN
#define LED_BUILTIN 2// ESP32默认LED引脚
#endif

// 配置与Python端一致的UUID
#define SERVICE_UUID      "00001101-0000-1000-8000-00805F9B34FB"// 服务UUID
#define CHARACTERISTIC_UUID_RX "0000ffe1-0000-1000-8000-00805F9B34FB"// 接收特征UUID

BLEServer* pServer = NULL;
BLECharacteristic* pRxCharacteristic;

// 接收数据缓冲区
String receivedData = "";

class MyServerCallbacks : public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
    Serial.println("设备已连接");
};

void onDisconnect(BLEServer* pServer) {
    Serial.println("设备已断开");
}
};

void blue_setup() {
Serial.begin(115200);

// 创建BLE设备
BLEDevice::init("ESP32-led");

// 创建服务器
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());

// 创建服务
BLEService* pService = pServer->createService(SERVICE_UUID);

// 创建接收特征(修改此处UUID)
pRxCharacteristic = pService->createCharacteristic(
    CHARACTERISTIC_UUID_RX,
    BLECharacteristic::PROPERTY_WRITE_NR   // 支持无响应写入
);

// 启动服务
pService->start();

// 开始广播
pServer->getAdvertising()->start();
Serial.println("等待Python设备连接...");
}



void processReceivedData(String data) {
// 去除可能的多余字符
data.trim();

// 解析JSON
DynamicJsonDocument doc(2048);// 使用DynamicJsonDocument替代(更灵活)
DeserializationError error = deserializeJson(doc, data);

if (error) {
    Serial.println("JSON解析错误: " + String(error.c_str()));
    return;
}

// 提取字段
String status = doc["status"].as<String>();
int score = doc["score"].as<int>();

// 验证数据有效性
if (status.isEmpty() || score < 0 || score > 10) {
    Serial.println("数据验证失败");
    return;
}

// 处理有效数据
Serial.print("收到指令: ");
Serial.print("Status=");
Serial.print(status);
Serial.print(", Score=");
Serial.println(score);

// 根据状态执行操作示例
if (status == "start") {
    digitalWrite(LED_BUILTIN, HIGH);
    Serial.println("疗愈开始");
} else if (status == "stop") {
    digitalWrite(LED_BUILTIN, LOW);
    Serial.println("疗愈停止");
}

// 其他状态处理...
}

// BLE写入回调
class RxCharacteristicCallbacks : public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
    String rxValue = pCharacteristic->getValue().c_str();// 直接转换为String
   
    if (rxValue.length() > 0) {
      receivedData += rxValue;
      Serial.println(rxValue);
    }
}
};

void initCallbacks() {
pRxCharacteristic->setCallbacks(new RxCharacteristicCallbacks());
}

void data_process() {
// 处理接收数据
if (receivedData.length() > 0) {
    Serial.println("on data recv\n");
    // 检查帧结束符
    if (receivedData.endsWith("\r\n")) {
      processReceivedData(receivedData);
      receivedData = "";
    }
}
delay(10);// 避免空循环占用过高CPU
}



页: [1]
查看完整版本: 通过蓝牙和esp32通信