12 KiB
12 KiB
yack-mini 开发指南
微信小程序蓝牙网关项目,采集 BLE 设备数据透传上报至 yack 平台。
项目定位
- 名称:yack-mini
- 技术栈:原生微信小程序
- 目标:轻量化蓝牙网关,透传数据至 yack
- 与 yack-app 区别:yack-app 是全功能移动端(UniApp),yack-mini 是轻量蓝牙网关(原生小程序)
架构概览
┌─────────────┐ BLE ┌──────────────────┐ wxs ┌─────────────────┐
│ BLE 设备 │ ←──────→ │ yack-mini │ ←──────→ │ yack 平台 │
│ (传感器) │ │ (微信小程序) │ MQTT │ (数据存储) │
└─────────────┘ └──────────────────┘ └─────────────────┘
项目结构
miniprogram/
├── app.js # 应用入口
├── app.json # 全局配置
├── app.wxss # 全局样式
├── project.config.json # 项目配置(需修改 appid)
├── sitemap.json # 站点地图
├── env.config.js # 环境配置(API/MQTT 地址)
│
├── pages/
│ ├── login/ # 登录页(首次使用时获取 userId)
│ │ ├── login.js
│ │ ├── login.wxml
│ │ ├── login.wxss
│ │ └── login.json
│ │
│ ├── index/ # 首页(设备列表)
│ │ ├── index.js
│ │ ├── index.wxml
│ │ ├── index.wxss
│ │ └── index.json
│ │
│ └── device/
│ ├── scan/ # 扫描设备页
│ │ ├── scan.js
│ │ ├── scan.wxml
│ │ ├── scan.wxss
│ │ └── scan.json
│ │
│ └── detail/ # 设备详情/实时数据页
│ ├── detail.js
│ ├── detail.wxml
│ ├── detail.wxss
│ └── detail.json
│
├── services/ # 核心服务模块
│ ├── ble.js # 蓝牙采集模块
│ │ • initBluetooth() # 初始化蓝牙适配器
│ │ • scanDevices(uuids, timeout) # 扫描设备
│ │ • stopScan() # 停止扫描
│ │ • connectDevice(id, serviceId) # 连接设备
│ │ • onData(callback) # 订阅数据通知(非 subscribeData)
│ │ • onStateChange(cb) # 状态变化回调
│ │ • writeCommand(hex) # 写入指令
│ │ • disconnect() # 断开连接
│ │ • closeBluetooth() # 关闭蓝牙适配器
│ │ • getState() # 获取当前状态
│ │ • isConnected() # 是否已连接
│ │
│ └── mqtt-client.js # MQTT 连接模块
│ • connect(options) # 连接 Broker
│ • publish(topic, msg, opts) # 发布消息
│ • subscribe(topic, cb, opts) # 订阅主题
│ • unsubscribe(topic) # 取消订阅
│ • onMessage(cb) # 消息回调
│ • onStateChange(cb) # 状态变化回调
│ • disconnect() # 断开连接
│ • getState() # 获取当前状态
│ • isConnected() # 是否已连接
│
├── utils/
│ ├── hex.js # 十六进制工具
│ │ • arrayBufferToHex(buf) # ArrayBuffer → Hex
│ │ • hexToArrayBuffer(hex) # Hex → ArrayBuffer
│ │
│ ├── storage.js # 本地存储
│ │ • getToken/setToken/removeToken # Token 管理
│ │ • getUserInfo/setUserInfo/removeUserInfo # 用户信息
│ │ • getDeviceList/saveDeviceList # 设备列表
│ │ • addDevice(device) # 添加设备(非 saveDevice)
│ │ • removeDevice/updateDevice/getDevice
│ │ • cachePendingData/getPendingData/clearPendingData # 离线缓存
│ │ • clearAll() # 清除所有数据
│ │
│ ├── request.js # HTTP 请求模块(仅登录使用)
│ │ • login(username, password, code, uuid) # 登录
│ │ • getInfo() # 获取用户信息
│ │ • captchaImage() # 获取验证码
│ │
│ └── auth.js # MQTT 凭证生成
│ • generateClientId(serialNumber, productId, userId) # 生成 clientId
│ • getMqttCredentials(serialNumber, productId, productSecret) # 获取凭证
│ • getMqttCredentialsFromDevice(device) # 从设备配置获取凭证
│ • buildPropertyPostTopic(productId, serialNumber) # 构建上报 Topic
│ • buildFunctionGetTopic(productId, serialNumber) # 构建指令 Topic
│ • buildPropertyGetTopic(productId, serialNumber) # 构建读取 Topic
│ • checkLoginStatus() # 检查登录状态
│ • getCurrentUserId() # 获取当前用户 ID
│
├── components/ # 公共组件
│ └── device-card/ # 设备卡片组件
│
├── libs/ # 第三方库
│ └── mqtt.min.js # MQTT 客户端(预置,非 npm 安装)
│
└── assets/ # 静态资源
└── images/
登录机制说明
设计原则
登录仅用于首次获取 userId,后续无需重复登录。
- userId 用于生成 MQTT clientId,是设备上报数据的必要参数
- 登录成功后,userId 永久保存在本地
- 后续启动直接读取本地 userId,无需网络请求
- Token 不参与后续业务逻辑(仅登录时使用)
登录流程
首次启动:
检查本地 userId → 无 → 显示登录页 → 输入账号密码 → 获取 userId → 保存本地 → 进入设备列表
后续启动:
检查本地 userId → 有 → 直接进入设备列表(无需登录)
退出登录
如需切换账号,在设置页或设备列表页提供"退出登录"按钮,调用:
const storage = require('../../utils/storage.js');
// 退出登录
function logout() {
storage.clearAll(); // 清除本地所有数据
wx.reLaunch({ url: '/pages/login/login' }); // 跳转登录页
}
关键技术实现
1. 蓝牙 BLE 采集(services/ble.js)
// 核心流程
wx.openBluetoothAdapter() // 初始化
→ wx.startBluetoothDevicesDiscovery() // 扫描
→ wx.createBLEConnection() // 连接
→ wx.getBLEDeviceServices() // 获取服务
→ wx.getBLEDeviceCharacteristics() // 获取特征值
→ wx.notifyBLECharacteristicValueChange() // 启用通知
→ wx.onBLECharacteristicValueChange() // 监听数据
使用示例:
const { bleService } = require('../../services/ble.js');
// 初始化并连接
await bleService.initBluetooth();
bleService.onData((data) => {
console.log('收到数据:', data.hex); // hex 字符串
});
const devices = await bleService.scanDevices([], 5000);
await bleService.connectDevice(devices[0].deviceId);
2. MQTT 连接(services/mqtt-client.js)
库文件:使用预置的 libs/mqtt.min.js(非 npm 安装)
连接配置:
{
clientId: 'S&{设备编号}&{产品ID}&{用户ID}', // 简单认证
username: '{设备编号}',
password: '{产品密钥}',
clean: true,
keepalive: 30
}
协议:wxs://domain.com:8084/mqtt(微信小程序专用)
使用示例:
const { mqttClient } = require('../../services/mqtt-client.js');
const auth = require('../../utils/auth.js');
// 获取凭证
const credentials = auth.getMqttCredentialsFromDevice(device);
// 连接
await mqttClient.connect({
clientId: credentials.clientId,
username: credentials.username,
password: credentials.password,
});
// 发布数据
const topic = auth.buildPropertyPostTopic(device.productId, device.serialNumber);
await mqttClient.publish(topic, hexData, { qos: 1 });
// 订阅指令
const cmdTopic = auth.buildFunctionGetTopic(device.productId, device.serialNumber);
await mqttClient.subscribe(cmdTopic, (topic, message) => {
console.log('收到指令:', message);
});
3. 数据透传格式
| 场景 | 上报格式 | Topic |
|---|---|---|
| Modbus-RTU | Hex 字符串(原始帧) | /{productId}/{sn}/property/post |
| 其他协议 | Hex 字符串(原始数据) | 同上(平台脚本解析) |
示例:
// Modbus 帧上报
mqttClient.publish('/1/BLE001/property/post', '010304009A005B8B7C');
// 私有协议数据上报
mqttClient.publish('/1/BLE002/property/post', '009A005B');
yack 平台配置
产品配置
-
创建产品
- 产品名称:蓝牙传感器
- 协议:
MODBUS-RTU或JSON(取决于设备协议)
-
定义物模型
- 属性:temperature、humidity 等
- 标识符:与 Modbus 配置/脚本解析对应
-
Modbus 配置(
iot_modbus_config,仅 Modbus 设备)- 从站地址、功能码、寄存器地址、数据类型
-
规则脚本(
iot_script,仅非 Modbus 设备)- 脚本用途:数据流处理(1)
- 触发事件:设备上报(1)
- 脚本内容:解析 hex 数据,输出物模型 JSON
设备配置
- 设备编号:小程序 clientId 中的
{设备编号} - 产品密钥:作为 MQTT password
开发规范
代码规范
-
命名规范
- 文件名:小写 + 连字符(
device-card.js) - 变量名:小驼峰(
deviceId) - 常量:大写 + 下划线(
SERVICE_UUID) - 私有方法:下划线前缀(
_handleData())
- 文件名:小写 + 连字符(
-
注释规范
/** * 扫描蓝牙设备 * @param {Array<string>} serviceUUIDs - 服务 UUID 列表 * @returns {Promise<Array>} 设备列表 */ async scanDevices(serviceUUIDs) { ... } -
错误处理
- 所有异步操作使用 try-catch
- 用户友好错误提示(
wx.showToast)
包体积控制
目标:主包 < 1.5MB
策略:
- 不使用 UI 框架(原生组件)
- mqtt.js 已压缩并预置在 libs 目录
- 图片使用 CDN 或压缩
- 分包加载(如有需要)
调试与测试
微信开发者工具
- 真机调试:蓝牙功能必须在真机上测试
- MQTT 调试:使用
wxs://协议,确保域名配置正确
平台验证
- yack 控制台查看设备数据
- 检查
iot_device_log表 - 查看规则脚本日志
部署流程
-
微信公众平台配置
- 服务器域名:添加
socket 合法域名(wxs://...) - 业务域名:如需 H5 页面
- 服务器域名:添加
-
项目配置
- 修改
project.config.json中的appid - 修改
env.config.js中的 API 和 MQTT 地址 - 将
ENV改为'production'
- 修改
-
代码上传
- 微信开发者工具 → 上传代码
- 设置版本号、备注
-
提交审核
- 填写功能说明
- 蓝牙权限说明
扩展路径
-
新增 Modbus 设备
- 平台配置 Modbus 参数
- 小程序扫描新设备(可能需更新 Service UUID)
-
新增私有协议设备
- 平台编写规则脚本
- 小程序适配 BLE 特征值
-
设备控制(下发指令)
- 订阅
/function/get或/property/get - 通过
bleService.writeCommand()发送
- 订阅
相关文档
- 微信小程序蓝牙 API
- mqtt.js 文档
- yack 协议解析
- [Modbus 配置表](sql/yack-init.sql 中
iot_modbus_config)