Skip to content

ESP32使用小机云开源项目可以快速使用小机云蓝牙,目前支持arduino,python,idf。ESP32开源仓库

以下以ESP32C3+arduino示例进行说明ESP32如何快速使用小机云蓝牙。python和idf的使用过程类似。

在开始使用前可以先看一下《如何使用小机云蓝牙》一文,可以帮您了解一下小机云蓝牙的工作流程

更建议使用ESP32C3/S3,ESP32不支持使用小机云蓝牙

使用流程概述

  1. 准备项目信息
  2. 在代码中填入项目信息
  3. 获取您ESP32的蓝牙地MAC址。注意,ESP32有蓝牙MAC和WIFI MAC
  4. 在小机云控制台,选择您的蓝牙项目,在设备列表中,使用您的MAC地址(不要冒号)创建设备
  5. 查看小程序/APP下发的数据
  6. 上传您的数据到小程序/APP

开始使用ESP32

1. 准备项目信息

在电脑打开小机云控制台 xsgee.com。创建或选择您的蓝牙项目。在更多中查看项目详情。

我们需要准备三个信息,ProjectId,ProjectSecret,校验内容格式(KEY_CONTENT)

2. 填入项目信息

您只需要根据您的项目类型,把上面拿到的项目信息填入到您的代码中

arduino配置项目信息

c
//ProjectId
#define X_PROJECT_ID "xxxxxx"
//ProjectSecret
#define X_PROJECT_SECRET "xxxxx"
//校验内容格式
#define X_PROJECT_KEY "projectId.mac.myContent.timestamp"

python填入项目信息

python
PROJECT_ID = "1013b0e95e00e911"
PROJECT_SECRET = "AF441806D87DB58A17A627101AF33780"
PROJECT_KEY = "projectId.mac.myContent.timestamp"

idf填入项目信息

c++
#define CONFIG_PROJECT_ID "1013b0e95e00e911"
#define CONFIG_PROJECT_SECRET "AF441806D87DB58A17A627101AF33780"
#define CONFIG_PROJECT_KEY "projectId.mac.myContent.timestamp"

3. 获取您的蓝牙MAC

您可以通过下面方式获取您的蓝牙MAC

arduino打印蓝牙mac地址

c++
uint8_t *mac = BLEDevice::getAddress().getNative()
//注意是倒叙
Serial.printf("%02X%02X%02X%02X%02X%02X\n", mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]);

python获取并打印蓝牙mqc

python
ble = bluetooth.BLE()
# 获取 MAC 地址(字节格式)
mac_bytes = ble.config('mac')[1]

# 转换为常见的十六进制显示格式
mac_hex = ubinascii.hexlify(mac_bytes).decode()
# 或者使用 mac_bytes.hex()

print("MAC bytes:", mac_bytes)           # b'\xb8:\x1c...'
print("MAC hex:", mac_hex)               # "b83a1c..."

idf打印蓝牙MAC地址

c
uint8_t mac_addr[6];

// 读取蓝牙 MAC 地址
esp_read_mac(mac_addr, ESP_MAC_BT);

// 打印 MAC 地址
printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
       mac_addr[0], mac_addr[1], mac_addr[2],
       mac_addr[3], mac_addr[4], mac_addr[5]);

4. 创建设备

在您刚才选择的蓝牙项目中,进入项目-->设备列表-->创建设备。输入上面得到的MAC地址,选择任意分组,点击创建即可

5. 收发数据

arduino收发数据

c++
//xsgee-esp32-ble-arduino.ino
class MyBleCallbacks : public XBleCallbacks {
  void onData(uint8_t *data, size_t len) {
    String value_str = String((char *)data, len);
    XLOGI("Received:%s", value_str.c_str());
  }

  void onConnected() {
    XLOGI("Connected");
  }

  void onDisconnected() {
    XLOGI("Disconnected");
  }

  void onNotifyState(uint16_t isNotified) {
    XLOGI("NotifyStatus: %d" + isNotified);
  }

  void onAuth(bool isAuthed) {
    //蓝牙连接成功后会自动向应用发起校验
    XLOGI("AuthStatus: %d" + isAuthed);
    //校验成功后同步设备数据
    pageDataDriver.uploadData();
    delay(100);
    //同步设置状态
    pageDataDriver.uploadBoardState();
  }

  void onPageData(KV* pairs, uint8_t len) {
    //处理应用发下来的数据是一串字符串协议,例如$X#D#switch:0&57\r\n,提取出switch:0
    //这里已经转为key:value格式,pairs里面就是点击页面组件后发下来的key:value
    pageDataDriver.handler(pairs, len);
  }
};

//PageDataDriver.cpp
void PageDataDriver::handler(KV* pairs, uint8_t len) {
  for (uint8_t i = 0; i < len; i++) {
      if (pairs[i].key[0] == '\0') {
          continue;
      }

      const char* key = reinterpret_cast<const char*>(pairs[i].key);
      const char* value = reinterpret_cast<const char*>(pairs[i].value);
	  
      //处理应用发下来的数据,这里开始已经别名为switch,也就是这里说的关键字key
      //key后面会带一个value,switch的value是0或1,0表示关,1表示开
      if (strncmp(key, "switch", 6) == 0) {
          int v = value[0] - '0';
          XLOGD("switch value:%d", v);
          if (v) {
            // 硬件LED控制开
            digitalWrite(LED_PIN, HIGH);
            m_ledState = 1;
          } else {
            // 硬件LED控制关
            digitalWrite(LED_PIN, LOW);
            m_ledState = 0;
          }
      } else if (strncmp(key, "slider", 6) == 0) {
          int v = atoi(value);
          XLOGD("slider value:%d", v);
          analogWrite(PWM_PIN, v);
          m_pwm = v;
      }
  }

  uploadData();
}

void PageDataDriver::uploadData() {
  getTemperature();
  getButtonState();

  char tempValue[16];
  snprintf(tempValue, sizeof(tempValue), "%.2f", m_temperature);
  //随机颜色,格式为RRGGBB
  char colorStr[8]; 
  generateColor(colorStr);

  int kv_size = 5;
  //读硬件状态,组合成key-value数组 
  KV kvs[kv_size] = {
    KV("switch", std::to_string(m_ledState)),
    KV("slider", std::to_string(m_pwm)),
    KV("temperature", tempValue),
    KV("@IN1", std::to_string(m_buttonState)),
    KV("color", colorStr),
  };

  //sendKvCmd会把kvs数组还原成字条串发送给应用
  //注意:kv组合成字符串的长度应小于X_CMD_MAX_LEN - 6
  if(xBle.isConnected){
    xBle.sendKvCmd("D", kvs, kv_size);
  }
}

python收发数据

python
# main.py
class MyBleCallbacks(XBleCallbacks):
    """自定义BLE回调类"""
    
    def __init__(self):
        super().__init__()
        
    def onConnected(self):
        """连接成功回调"""
        print("isConnected!")
    
    def onDisconnected(self):
        """断开连接回调"""
        print("isDisconnected!")
    
    def onAuth(self, isAuth):
        """认证结果回调"""
        print(f"isAuth: {isAuth}")
        driver.uploadData()
        time.sleep_ms(50)
        driver.uploadBoardState()

    
    def onPageData(self, pairs, length):
        """页面数据回调,已经转成key-value格式,可以参数arduino onPageData的注释"""
        # for i, kv in enumerate(pairs):
        #     print(f"    [{i}] {kv.key} = {kv.value}")
        driver.handler(pairs)

 # pageDataDriver.py
	# 处理应用数据,可以参考arduino的注释
	def handler(self, pairs):
        try:
            for kv in pairs:
                key = kv.key
                value = kv.value
                if not key:
                    continue

                if key == "switch" and len(key) >= 6:
                    v = int(value[0]) if value else 0
                    print(f"switch value:{v}")
                    if v:
                        self.led.value(1)  # HIGH
                        self.m_ledState = 1
                    else:
                        self.led.value(0)  # LOW
                        self.m_ledState = 0

                elif key == "slider" and len(key) >= 6:
                    v = int(value) if value else 0
                    print(f"slider value:{v}")
                    self.pwm.duty(v * 1023 // 100)
                    self.m_pwm = v

            self.uploadData()
            
        except Exception as e:
            print(f"handler error: {e}")

    # 上传数据到应用,可以参考arduino的注释
    def uploadData(self):
        self.getTemperature()
        self.getButtonState()

        tempValue = f"{self.m_temperature:.2f}"
        colorStr = self.generateColor()

        kvs = [
            KV("switch", str(self.m_ledState)),
            KV("slider", str(self.m_pwm)),
            KV("temperature", tempValue),
            KV("@IN1", str(self.m_buttonState)),
            KV("color", colorStr)
        ]

        if self.ble.isConnected():
            self.ble.sendKvCmd("D", kvs)

如果您遇上无法搜索到设备等问题,可以看一下这篇文章,常见问题