从微信小程序到 Home Assistant:VCX-Knob 智能马桶蓝牙桥接服务开发实践

2025年12月10日10 次阅读0 人喜欢
技术nodejsHome Assistant蓝牙智能家居

从微信小程序到 Home Assistant:VCX-Knob 智能马桶蓝牙桥接服务开发实践

项目背景

最近在整理一个微信小程序项目,这个项目用于控制 VCX-Knob 智能马桶。小程序通过蓝牙低功耗(BLE)与设备通信,实现了水温调节、工作模式切换、自动按摩等丰富的功能。

但作为一个 Home Assistant 用户,我更希望能够将这些设备直接集成到智能家居系统中。微信小程序虽然功能完善,但无法与 Home Assistant 直接通信。于是,我决定开发一个 Node.js 桥接服务,将蓝牙设备的功能暴露给 Home Assistant。

技术挑战

1. 蓝牙协议逆向

首先要做的是理解微信小程序中的蓝牙通信协议。通过分析小程序源码,我发现了以下关键信息:

  • 设备名称VCX-Knob
  • 服务 UUID0000FFA0-0000-1000-8000-00805F9B34FB
  • 特征值 UUID
    • 写入:0000FFA1-0000-1000-8000-00805F9B34FB
    • 通知:0000FFA2-0000-1000-8000-00805F9B34FB

2. 指令格式解析

所有指令都采用固定的十六进制格式:

复制代码
AA 08 02 [指令码] [数据1] [数据2] [数据3] [校验和]
  • AA 08 02:固定头部
  • [指令码]:功能操作码(如大冲 07、小冲 17、睡眠 18 等)
  • [数据1-3]:参数数据(温度等级、模式等)
  • [校验和]:所有字节的十六进制和

3. 状态数据解析

设备返回的状态数据也采用类似的格式:

复制代码
AA 08 88 [类型码] [数据1] [数据2] [数据3]

根据不同的类型码(01-06),数据包含不同的信息:

  • 类型 01:基础状态(冲水、座座、泡泡、空气、雷达等开关状态)
  • 类型 02:温度和参数(水温、风温、座温等级,水压、氛围灯亮度等)
  • 类型 03:百分比和档位(空气百分比、进水百分比、雷达档位等)
  • 类型 04-06:力度、冲水参数、传感器参数等

架构设计

核心模块

项目采用模块化设计,包含以下几个核心模块:

  1. BLE 客户端 (ble-client.js)

    • 负责蓝牙设备的连接、扫描、指令发送
    • 处理状态数据的接收和解析
    • 自动重连机制
  2. 指令管理 (commands.js)

    • 定义所有指令码常量
    • 提供指令生成函数(简单开关、温度设置等)
    • 指令格式验证和转换
  3. Home Assistant 客户端 (ha-client.js)

    • REST API 调用(更新实体状态)
    • WebSocket 连接(实时监听状态变化)
    • 实体管理和状态同步
  4. MQTT 客户端 (mqtt-client.js)

    • MQTT 消息发布/订阅
    • Home Assistant 自动发现
    • 作为备选方案支持

两种连接模式

为了满足不同用户的需求,我设计了两种连接模式:

直接连接模式(推荐)

javascript 复制代码
CONNECTION_MODE=direct
HA_API_URL=http://homeassistant:8123
HA_ACCESS_TOKEN=your_token

优势

  • 无需独立的 MQTT Broker
  • 直接使用 Home Assistant 的 API
  • 配置更简单
  • WebSocket 实时通信

实现

  • 使用 REST API 更新实体状态
  • 使用 WebSocket API 监听用户操作
  • 状态变化立即同步

MQTT 模式

javascript 复制代码
CONNECTION_MODE=mqtt
MQTT_BROKER_URL=mqtt://localhost:1883

优势

  • 支持 Home Assistant 自动发现
  • 无需手动配置实体
  • 更符合 MQTT 生态

关键技术实现

1. 蓝牙连接管理

使用 @abandonware/noble 库实现蓝牙通信:

javascript 复制代码
import noble from '@abandonware/noble';

class BLEClient {
  async connect(peripheral) {
    await peripheral.connectAsync();
    const services = await peripheral.discoverServicesAsync([serviceUUID]);
    const characteristics = await service.discoverCharacteristicsAsync([
      writeUUID, notifyUUID
    ]);
    
    // 订阅通知
    await notifyCharacteristic.subscribeAsync();
    notifyCharacteristic.on('data', this.onCharacteristicData);
  }
}

2. 状态数据解析

状态数据需要按位解析,例如基础状态:

javascript 复制代码
parseBasicStatus(byte1, byte2, byte3) {
  const byte1Bits = parseInt(byte1, 16).toString(2).padStart(8, '0');
  return {
    flush: byte1Bits[7] === '1',      // bit7: 冲水状态
    seat: byte1Bits[6] === '1',       // bit6: 座座状态
    bubble: byte1Bits[5] === '1',     // bit5: 泡泡状态
    air: byte1Bits[4] === '1',        // bit4: 空气状态
    // ...
  };
}

3. Home Assistant 集成

直接连接模式通过 REST API 和 WebSocket 实现:

javascript 复制代码
// 更新实体状态
async updateEntityState(entityId, state, attributes) {
  const response = await fetch(`${apiUrl}/api/states/${entityId}`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ state, attributes })
  });
}

// WebSocket 监听状态变化
ws.send(JSON.stringify({
  type: 'subscribe_events',
  event_type: 'state_changed'
}));

实体设计

为了在 Home Assistant 中更好地控制设备,我设计了以下实体类型:

  • 开关:大冲、小冲、睡眠、泡泡、空气净化、氛围灯等
  • 传感器:水温、风温、座温、空气百分比等
  • 选择器:工作模式(臀洗/妇洗/烘干/座温)
  • 按钮:停止、自动按摩、泡泡复位
  • 数字输入:温度等级设置(0-3)

开发过程中的坑

1. 原生模块编译问题

@abandonware/noble 需要编译原生 C++ 代码,在使用 pnpm 时遇到了构建脚本被忽略的问题。

解决方案

bash 复制代码
# 手动构建
cd node_modules/.pnpm/@abandonware+noble@*/node_modules/@abandonware/noble
npm run install

2. 状态数据包不完整

蓝牙数据传输可能出现分包情况,需要实现数据缓冲和重组。

解决方案

javascript 复制代码
onCharacteristicData(data) {
  this.statusBuffer += hexString;
  // 检查完整数据包
  while (this.statusBuffer.includes('AA0888')) {
    const packet = extractPacket(this.statusBuffer);
    this.parseStatusData(packet);
  }
}

3. Home Assistant 实体创建

直接连接模式无法通过 API 自动创建实体,需要手动配置。

解决方案

  • 提供配置模板文件 (homeassistant-config.yaml)
  • 创建详细的配置指南 (HA_SETUP.md)
  • 启动时检查实体是否存在并提示用户

项目亮点

  1. 完整的协议实现:支持所有功能指令和状态解析
  2. 灵活的连接方式:支持直接连接和 MQTT 两种模式
  3. 完善的错误处理:自动重连、状态恢复、错误提示
  4. 详细的文档:README、安装指南、配置说明一应俱全
  5. 代码质量:模块化设计、清晰的注释、错误处理

使用体验

启动服务后,Home Assistant 中会自动出现智能马桶的所有控制选项。可以通过 UI 切换工作模式、调节温度、控制各种功能,实现了真正的智能家居集成。

总结

这个项目展示了如何:

  • 逆向分析蓝牙通信协议
  • 使用 Node.js 实现蓝牙桥接服务
  • 集成 Home Assistant 智能家居系统
  • 处理实际开发中的各种技术挑战

通过这个项目,不仅实现了功能需求,还深入理解了蓝牙通信、智能家居集成等技术细节。对于想要将非标准设备集成到 Home Assistant 的开发者来说,这是一个很好的参考案例。

相关资源

  • 项目文档完整,包含详细的安装和配置指南
  • 支持 macOS、Linux 平台
  • 代码开源,可扩展性强

希望这个项目能够帮助到有类似需求的开发者!

从微信小程序到 Home Assistant:VCX-Knob 智能马桶蓝牙桥接服务开发实践 | 博客