瀏覽代碼

feat: 蓝牙控制命令功能

kindring 1 年之前
父節點
當前提交
c586db9dc9
共有 6 個文件被更改,包括 425 次插入14 次删除
  1. 2 0
      data/lampType.js
  2. 101 12
      pages/light/light.js
  3. 279 0
      utils/light_cmd.js
  4. 30 1
      utils/mjs_buffer.js
  5. 12 0
      utils/mjs_curry.js
  6. 1 1
      utils/mjs_wxble.js

+ 2 - 0
data/lampType.js

@@ -11,4 +11,6 @@ export const bleInfo = {
     controlUuid: "0000ffe9-0000-1000-8000-00805f9b34fb",
     // 监听数据uuid
     notifyUuid: "0000ffe4-0000-1000-8000-00805f9b34fb",
+    // 控制uuid前几位
+    characteristicFirstUuid: "ff01",
 }

+ 101 - 12
pages/light/light.js

@@ -1,8 +1,10 @@
 // pages/light/light.js
 import { connectStateMap, connectStateTypes } from '../../data/devType.js'
-import { MAX_COLOR_TEMPERATURE, MIN_COLOR_TEMPERATURE, COLOR_TEMPERATURE_STEP } from '../../data/lampType.js'
+import { MAX_COLOR_TEMPERATURE, MIN_COLOR_TEMPERATURE, COLOR_TEMPERATURE_STEP, bleInfo } from '../../data/lampType.js'
 import { handle } from '../../utils/mjs_handle.js'
 import { calculateColor } from '../../utils/mjs_color.js'
+import light_cmd from '../../utils/light_cmd.js'
+import { _curry } from '../../utils/mjs_curry.js'
 import BLE from '../../utils/mjs_wxble.js'
 console.log(BLE);
 const ble = new BLE();
@@ -18,6 +20,10 @@ const tmpDevs = [
         deviceId: "23456"
     }
 ]
+// 蓝牙模块连接对象信息参数
+const connectBleParams = [];
+// 蓝牙服务信息
+let bleServices = [];
 Page({
 
     /**
@@ -29,6 +35,7 @@ Page({
         ble: {
             state: connectStateTypes.scaning,
             devName: "",
+            deviceId: "",
             init: false,
             // 控制uuid
             controlUuid: "",
@@ -51,23 +58,79 @@ Page({
             // 色彩
             bgc: "#3b3b3b"
         },
-        bleDevs: tmpDevs
+        bleDevs: tmpDevs,
     },
-    brightnessChangeHandle(e){
+    // 获取蓝牙发送数据对象
+    getBleSendHandle(){
+      // 固定值
+      let controlUuid = bleInfo.controlUuid;
+      let characteristicFirstUuid = bleInfo.characteristicFirstUuid;
+
+      let deviceId = this.data.ble.deviceId;
+      let serverUuid = '';
+      let characteristicUuid = '';
+      
+      let server = services.find(s=>s.uuid === controlUuid);
+      if(!server)
+      {
+        // return bleFail('获取服务失败', '该设备不支持该程序');
+        serverUuid = bleInfo.controlUuid;
+      }else
+      {
+        serverUuid = server.uuid;
+      }
+
+      //获取
+      let characteristic = server.characteristics.find(c=>
+        c.uuid.startsWith(characteristicFirstUuid)
+      );
+      if(!characteristic)
+      {
+        // return bleFail('获取服务失败', '该设备不支持该程序');
+        characteristicUuid = bleInfo.controlUuid;
+      }
+      else
+      {
+        characteristicUuid = characteristic.uuid;
+      }
+
+      return _curry(ble.sendData, deviceId, serverUuid, characteristicUuid);
+    },
+    // 亮度调节
+    async brightnessChangeHandle(e){
         console.log("亮度改变");
         console.log(e);
         this.setData({
           lamp: {...this.data.lamp, brightness: e.detail.value}
         })
         this.reComputeBgColor();
-      },
-      colorChangeHandle(e){
+        let fn = light_cmd.set_light(
+          this.getBleSendHandle(), 
+          this.data.lamp.brightness
+        );
+        let [_err,_res] = await handle(fn);
+        if(_err){
+          return this.bleFail('发送失败', _err.errMsg);
+        }
+        console.log(`亮度调节命令发送成功,亮度:${this.data.lamp.brightness}`);
+    },
+      async colorChangeHandle(e){
         console.log("色温改变");
         console.log(e);
         this.setData({
           lamp: {...this.data.lamp, colorTemperature: e.detail.value}
         })
         this.reComputeBgColor();
+
+        let fn = light_cmd.set_temp(
+          this.getBleSendHandle(), 
+          this.data.lamp.colorTemperature
+        );
+        let [_err,_res] = await handle(fn);
+        if(_err){
+          return this.bleFail('发送失败', _err.errMsg);
+        }
+        console.log(`亮度调节命令发送成功,亮度:${this.data.lamp.colorTemperature}`);
       },
       // 计算背景色
       reComputeBgColor(){
@@ -86,14 +149,27 @@ Page({
             lamp: {...this.data.lamp, bgc: newBgC}
         })
       },
-      fullModeSwitchHandle(e){
+      async fullModeSwitchHandle(e){
         // 全开模式切换
         console.log("全开模式切换");
         this.setData({
             lamp: {...this.data.lamp, fullOpen: !this.data.lamp.fullOpen}
         })
+
+        let fn;
+        let nextMode = light_cmd.light_worker_mode.DEFAULT;
+        if(this.data.lamp.fullOpen){
+          nextMode = light_cmd.light_worker_mode.FULL;
+        }
+
+        fn = light_cmd.set_mode(this.getBleSendHandle(), nextMode);
+        let [_err,_res] = await handle(fn);
+        if(_err){
+          return this.bleFail('发送失败', _err.errMsg);
+        }
+        console.log(`工作模式切换成功:${this.data.lamp.fullOpen}`);
       },
-      switchHandle(e){
+      async switchHandle(e){
         // 开关切换
         this.setData({
             lamp: {...this.data.lamp, switch: !this.data.lamp.switch}
@@ -102,16 +178,31 @@ Page({
             lamp: {...this.data.lamp, fullOpen: false}
         })
         this.reComputeBgColor();
+
+        let fn;
+        if(this.data.lamp.switch){
+            fn = light_cmd.open_light(this.getBleSendHandle());
+        }else{
+            fn = light_cmd.close_light(this.getBleSendHandle());
+        }
+        let [_err,_res] = await handle(fn);
+        if(_err){
+          return this.bleFail('发送失败', _err.errMsg);
+        }
+        console.log(`开关命令发送成功,开关:${this.data.lamp.switch}`);
     },
     
     bleFail(title,msg){
       this.setData({
         ble: {...this.data.ble, 
           state: connectStateTypes.unConnect, 
-          init: false
+          init: false,
+          devName: "",
+          deviceId: "",
         },
         bleDevs: []
       });
+      bleServices = [];
       wx.showModal({
         title: title,
         content: msg,
@@ -190,10 +281,8 @@ Page({
       // uuid FF01
       let [err,res] = await handle(ble.getServices());
       if(err){ return this.bleFail('获取服务失败', err.errMsg);}
-      res.forEach(val=>{
-        // 不同的服务有不同的功能
-        console.log(val);
-      })
+      // 保存服务信息;
+      bleServices = res;
   },
 
 

+ 279 - 0
utils/light_cmd.js

@@ -0,0 +1,279 @@
+// 工作模式
+// 默认工作模式
+// #define LIGHT_MODE_DEFAULT 0
+
+// 全亮模式(色温无效)
+// #define LIGHT_MODE_FULL 1
+// // 灯光控制命令起始码
+// typedef enum {
+//     // 下发命令
+//     START_CODE_CMD = 0x6c,
+//     // 响应命令
+//     START_CODE_RES = 0xc6,
+//     // 通知命令
+//     START_CODE_NOTIFY = 0x66
+// }light_cmd_start_code;
+
+// // 灯光控制命令码
+// typedef enum{
+//     CMD_OPEN = 0x01,
+//     CMD_CLOSE = 0x02,
+//     CMD_QUERY = 0x03,
+//     CMD_LIGTH = 0x04,
+//     CMD_TEMP = 0x05,
+//     CMD_FUN = 0x06,
+//     CMD_MODE = 0x07,
+//     CMD_CH = 0x08,
+//     CMD_HZ = 0x09,
+// }light_cmd_code;
+
+// // 灯光数据 色温, 亮度, 工作模式, 风扇
+// typedef struct {
+//     bool open;
+//     int temp;
+//     int light;
+//     int mode;
+//     int fan;
+// } light_data_t;
+
+// 命令结构体
+// typedef struct {
+//     light_cmd_start_code startCode;
+//     uint8_t len;
+//     light_cmd_code cmd;
+//     uint8_t sn;
+//     uint8_t *data;
+// } light_cmd_t;
+
+import { hex2ab, buf2hex, dec2hex, hexStr2Arr } from './mjs_buffer.js'
+export const light_cmd_start_code = {
+    START_CODE_CMD: 0x6c,
+    START_CODE_RES: 0xc6,
+    START_CODE_NOTIFY: 0x66
+}
+export const light_cmd_code = {
+    CMD_OPEN: 0x01,
+    CMD_CLOSE: 0x02,
+    CMD_QUERY: 0x03,
+    CMD_LIGTH: 0x04,
+    CMD_TEMP: 0x05,
+    CMD_FAN: 0x06,
+    CMD_MODE: 0x07,
+    CMD_CH: 0x08,
+    CMD_HZ: 0x09,
+}
+
+export const light_worker_mode = {
+    DEFAULT: 0,
+    FULL: 1
+}
+
+const CMD_ACTION = {
+}
+
+
+/**
+ * 数据结构体
+ * @param {number} cmd 命令码
+ * @param {number} sn 序列号
+ * 发送时间
+ */
+const cmdList = []
+
+// 解析命令码
+export function parseCmdData(data){
+    // 数据分割为 hex字符串数组 
+    let hexArr = [];
+    if(!data){
+        return -1;
+    }
+    hexArr = hexStr2Arr(data);
+    // 起始码
+    let startCode = parseInt(hexArr[0], 16);
+    // 长度
+    let len = parseInt(hexArr[1], 16);
+    // 命令码
+    let cmd = parseInt(hexArr[2], 16);
+    // 序列号
+    let sn = parseInt(hexArr[3], 16);
+    let cmdData = hexArr.slice(4);
+
+    switch (cmd) {
+        case light_cmd_code.CMD_OPEN:
+            console.log("开灯");
+            break;
+        case light_cmd_code.CMD_CLOSE:
+            console.log("关灯");
+            break;
+        case light_cmd_code.CMD_QUERY:
+            console.log("查询");
+            break;
+        case light_cmd_code.CMD_LIGTH:
+            console.log("设置亮度");
+            break;
+        case light_cmd_code.CMD_TEMP:
+            console.log("设置色温");
+            break;
+        case light_cmd_code.CMD_FAN:
+            console.log("设置风扇");
+            break;
+        case light_cmd_code.CMD_MODE:
+            console.log("设置模式");
+            break;
+        case light_cmd_code.CMD_CH:
+            console.log("设置通道");
+            break;
+        case light_cmd_code.CMD_HZ:
+            console.log("设置频率");
+            break;
+        default:
+            break;
+    }
+    // 触发对应的监听函数
+    if(CMD_ACTION[cmd]){
+        CMD_ACTION[cmd] && CMD_ACTION[cmd](cmdData);
+    }else{
+        console.log(`未找到命令${cmd}对应的监听函数`);
+    }
+    
+
+    // 移除命令
+    let index = cmdList.findIndex(item=>item.sn == sn);
+    if(index > -1){
+        cmdList.splice(index, 1);
+    }
+    // 返回数据
+    return {
+        startCode,
+        len,
+        cmd,
+        sn,
+        cmdData
+    }
+}
+
+/**
+ * 命令构建
+ * @param {function} sendFn 发送函数,从外部传入
+ * @param {*} cmd 对应命令
+ * @param {*} data hex数据字符串
+ */
+export function generateCmdData(cmd, data){
+    let cmdStr = ``;
+    let cmdLen = data.length || 0;
+    let sn = cmdList.length + 1;
+    // 拼接起始码
+    cmdStr += dec2hex(light_cmd_start_code.START_CODE_CMD);
+    // 拼接长度 转hex
+    cmdStr += dec2hex(cmdLen + 2);
+    // 拼接命令码
+    cmdStr += dec2hex(cmd);
+    // 拼接序列号
+    cmdStr += dec2hex(sn);
+    // 拼接数据
+    cmdStr += data;
+
+    // 记录命令
+    cmdList.push({
+        cmd,
+        sn,
+    })
+
+    return cmdStr;
+}
+
+/**
+ * 开灯
+ * @param {function} sendFn 发送函数,从外部传入
+ * @returns 
+ */
+export function open_light(sendFn){
+    let data = generateCmdData(light_cmd_code.CMD_OPEN);
+    return sendFn(data);
+}
+
+/**
+ * 关灯
+ * @param {function} sendFn 发送函数,从外部传入
+ * @returns 
+ */
+export function close_light(sendFn){
+    let data = generateCmdData(light_cmd_code.CMD_CLOSE);
+    return sendFn(data);
+}
+
+/**
+ * 查询灯光状态
+ * @param {function} sendFn 发送函数,从外部传入
+ * @returns 
+ */
+export function query_light(sendFn){
+    let data = generateCmdData(light_cmd_code.CMD_QUERY);
+    return sendFn(data);
+}
+
+/**
+ * 设置灯光
+ * @param {function} sendFn 发送函数,从外部传入
+ * @param {number} light 亮度
+ * @returns 
+ */
+export function set_light(sendFn, light){
+    let data = generateCmdData(light_cmd_code.CMD_LIGTH, dec2hex(light));
+    return sendFn(data);
+}
+
+/**
+ * 设置色温
+ * @param {function} sendFn 发送函数,从外部传入
+ * @param {number} temp 色温
+ * @returns 
+ */
+export function set_temp(sendFn, temp){
+    let data = generateCmdData(light_cmd_code.CMD_TEMP, dec2hex(temp));
+    return sendFn(data);
+}
+
+/**
+ * 调整风扇转速
+ * @param {function} sendFn 发送函数,从外部传入
+ * @param {number} fun 功能
+ * @returns 
+ */
+export function set_fun(sendFn, fanSpeed){
+    let data = generateCmdData(light_cmd_code.CMD_FAN, dec2hex(fanSpeed));
+    return sendFn(data);
+}
+
+/**
+ * 设置工作模式
+ * @param {function} sendFn 发送函数,从外部传入
+ * @param {number} mode 模式
+ * @returns 
+ */
+export function set_mode(sendFn, mode){
+    let data = generateCmdData(light_cmd_code.CMD_MODE, dec2hex(mode));
+    return sendFn(data);
+}
+
+
+export function registerHandle(cmd, handle){
+    CMD_ACTION[cmd] = handle;
+}
+
+
+export default {
+    light_worker_mode,
+    light_cmd_start_code,
+    light_cmd_code,
+    parseCmdData,
+    generateCmdData,
+    open_light,
+    close_light,
+    query_light,
+    set_light,
+    set_temp,
+    set_fun,
+    set_mode,
+    registerHandle
+}

+ 30 - 1
utils/mjs_buffer.js

@@ -11,6 +11,29 @@ export function hex2ab(hex){
   let buffer = typedArray.buffer
   return buffer
 }
+
+/**
+ * 十进制转十六进制
+ * @param {number} dec 要转换的十进制数
+ * @returns 转换后的十六进制字符串,如果是奇数位,前面补0
+ */
+export function dec2hex(dec)
+{
+  let res = dec.toString(16);
+  // 如果是奇数位,前面补0
+  if (res.length % 2) {res = '0' + res;}
+  return res;
+}
+
+// 十六进制字符串分割为数组
+export function hexStr2Arr(hexStr){
+  let arr = [];
+  for(let i=0;i<hexStr.length;i+=2){
+    arr.push(hexStr.substr(i,2))
+  }
+  return arr;
+}
+
 function hexStrToBuffer(str){
   // 填充首位
   if(str.length % 2){str=`0${str}`}
@@ -20,7 +43,13 @@ function hexStrToBuffer(str){
   }
 }
 
+
+
+
+
 export default {
   buf2hex,
-  hex2ab
+  hex2ab,
+  dec2hex,
+  hexStr2Arr
 }

+ 12 - 0
utils/mjs_curry.js

@@ -0,0 +1,12 @@
+export function _curry(fn){
+    let _arguments = Array.from(arguments);
+    let params = _arguments.splice(1);
+    return function(){
+        let __arguments = Array.from(arguments);
+        if(__arguments.length >= 1){
+            params.push(...__arguments);
+        }else{
+            return fn(...params,...arguments);
+        }
+    }
+}

+ 1 - 1
utils/mjs_wxble.js

@@ -165,7 +165,7 @@ class BLE{
   }
 
   // 向指定特征发送数据
-  sendData(devId,serviceId,characteristicId,hexStr){
+  sendData(devId, serviceId,characteristicId, hexStr){
     console.log(hexStr);
     hexStr = hex2ab(hexStr);
     console.log(hexStr);