// 设备命令 // TLV格式(16进制) // 二进制协议使用 TLV (Type-Length-Value)编码格式。 // - Type:固定长度, 一字节。 // - Length:可变长度。 0 或 1 个字节。 // - Value:二进制数据。 长度由 Length 字段决定。 数据本身可以上数字或者字符串。 const EnumOpen = { close: 0, open: 1 }; const EnumConnectType = { bt: 0, ble: 1, upnp: 2, mqtt: 3 } class BtCmd { // BtCmd._(); constructor() { } // 获取版本号 static queryVersion() { return this._build(CmdBase.queryVersion, [0x0]); } // 查询电量 电量值 0-9,0对应10%,9对应100%,10充电 static queryKwh() { return this._build(CmdKwh.queryKwh, [0x0]); } // 查询耳机电量 static queryKwhEarPhone() { return this._build(CmdEarPhone.queryEarPhoneKwh, [0x0]); } // 查询EQ音效 static queryEQ() { return this._build(CmdEarPhone.queryEQ, [0x0]); } // 设置EQ音效 static setEQ(list) { return this._build(CmdEarPhone.setEQ, list); } // B5耳机-低电耗模式 static queryLowPower() { return this._build(CmdEarPhone.queryLowPower, [0x0]); } static setLowPowerMode(isOpen) { return this._build(CmdEarPhone.setLowPowerMode, [isOpen]); } // B5耳机-自定义操作手势 static queryCtrlStatus() { return this._build(CmdEarPhone.queryCtrlStatus, [0x0]); } static setCtrlStatus(singleClick, doubleClick, longClick) { return this._build(CmdEarPhone.setCtrlStatus, [singleClick, doubleClick, longClick]); } // 查询低延时模式 static queryLowDelayMode() { return this._build(CmdEarPhone.queryLowDelayMode, [0x0]); } // 低延时模式 static setLowDelayMode(open, mode) { return this._build(CmdEarPhone.setLowDelayMode, [open, mode]); } // 低电量提示音 static queryLowKwhWarningTone() { return this._build(CmdKwh.queryLowKwhWarningTone, [0x00]); } static setLowKwhWarningTone(isNotify) { return this._build(CmdKwh.setLowKwhWarningTone, isNotify ? [0x01] : [0x00]); } // 蓝牙自动播放 static setAutoPlay(switchStatus) { return this._build(CmdBase.setAutoPlay, [switchStatus]); } static AutoPlay() { return this._build(CmdBase.getAutoPlay, [0x00]); } // 查询音量 static queryVolume() { return this._build(CmdBase.queryVolume, [0x00]); } static setVolume(volume) { return this._build(CmdBase.setVolume, [volume]); } // 查询闹钟 static queryAlarm() { return this._build(CmdRtc.queryAlarm, [0x00]); } // 设置闹钟 static setAlarm(switchStatus, weekCycle, hour, minutes, channel = 1) { const weeks = CmdWeek.week2Cmd(weekCycle); return this._build(CmdRtc.setAlarm, [switchStatus, weeks, hour, minutes, channel]); } // 查询休眠 static querySleep() { return this._build(CmdRtc.querySleep, [0x00]); } static querySleepAfterPlayPause() { return this._build(CmdRtc.querySleepAfterPlayPause, [0x00]); } static setSleepAfterPlayPause(time) { return this._build(CmdRtc.setSleepAfterPlayPause, [time]); } // 设置休眠 static setSleep(switchStatus, hour, minutes) { return this._build(CmdRtc.setSleep, [switchStatus, hour, minutes]); } // 设置时间 static setDevTime() { const now = new Date(); const y = now.getFullYear(); const year = Math.floor(y / 100); const _year = y % 100; const month = now.getMonth() + 1; // getMonth() 返回 0-11,所以需要加 1 const day = now.getDate(); const hour = now.getHours(); const minutes = now.getMinutes(); const seconds = now.getSeconds(); console.log(`setTime========${year},${_year},${month},${day},${hour},${minutes},${seconds}`); // console.log(`setTime======== 2, ${CmdRtc.setTime}`); let cmd = this._build(0x50, [year, _year, month, day, hour, minutes, seconds]); console.log(`setTime========${cmd}`); return cmd; } // 查询时间 static queryTime() { return this._build(CmdRtc.queryTime, [0x00]); } // 设置RGB static setRGB(r, g, b) { return this._build(CmdRgb.set, [r, g, b]); } // 查询RGB static queryRGB() { return this._build(CmdRgb.query, [0x0]); } static stringToUint8Array(str) { // 54 44 44 48 01 11 28 09 73 6d6172745f413246 // const encoder = new TextEncoder(); // const uint8Array = encoder.encode(str); // return uint8Array; return [0x73, 0x6d, 0x61, 0x72, 0x74, 0x5f, 0x41, 0x32, 0x46] } // 校验设备 static checkDevice() { let secretKey = this.stringToUint8Array(CmdBase.secretKey) // console.log(`checkDevice========${secretKey}`); return this._build(CmdBase.checkDevice, secretKey); } // 杰理语音开始回应 static jlStartVoiceResponse() { return this._build(CmdVoice.jlStartVoiceResponse); } // 杰理语音结束回应 static jlStopVoiceResponse() { return this._build(CmdVoice.jlStopVoiceResponse); } // 领芯语音 static lxStartVoiceResponse() { return this._build(CmdVoice.lxStartVoiceResponse); } // 杰理语音结束回应 static lxStopVoiceResponse() { return this._build(CmdVoice.lxStopVoiceResponse); } // b1开始语音回调 static b1StartVoiceResponse() { const data = [0x04, 0x80, 0x01, 0x00, 0x02]; return new Uint8Array(data); } // b1结束语音回调 static b1StopVoiceResponse() { const data = [0x05, 0x80, 0x01, 0x00, 0x02]; return new Uint8Array(data); } // 固定头部 static get _header() { return [0x54, 0x44, 0x44, 0x48]; } // 版本号 static get _version() { return 0x01; } /* 黑胶音箱的指令 */ // 壁纸指令 1开始, 0结束 static wallPaper(value) { return this._build(CmdBase.wallPaper, [value]); } // 壁纸指令 static wallPaperData(value) { return this._build(CmdBase.wallPaperData, [value]); } // 背景图指令 static backgroudImg(value) { return this._build(CmdBase.heijiaoBackImg, [value]); } // 背景图指令 static backgroudImgData(value) { return this._build(CmdBase.heijiaoBackImgData, [value]); } // OTA指令 static OTA(value) { return this._build(CmdBase.heiJiaoOta, [value]); } static OtaData(value) { return this._build(CmdBase.heiJiaoOtaData, [value]); } // 生成命令(固定头部+版本号+命令总长度+命令类型+) static _build(cmdType, otherCmd = [], isWriteChildCmdLength = true) { const cmd = []; // 固定头部 cmd.push(...this._header); // 版本号 cmd.push(this._version); // 命令类型 cmd.push(cmdType); if (isWriteChildCmdLength) { // 子命令长度 const childLength = this._int2Hex(otherCmd.length); cmd.push(childLength); } // 其他命令 if (otherCmd.length > 0) { for (const element of otherCmd) { cmd.push(this._int2Hex(element)); } } // 命令长度(位置在版本号之后) const length = cmd.length + 1; const l = this._int2Hex(length); cmd.splice(5, 0, l); return new Uint8Array(cmd); } // 打印cmd static printTLV(cmd, isSend = false) { let result = ""; const key = isSend ? "发送" : "接收"; if (isSend) { // console.log(`${key}原始-${cmd.toString()}`); } for (let i = 0; i < cmd.length; i++) { const cmdStr = `${this._int2HexString(cmd[i])}`.padStart(2, "0"); result += cmdStr; } if (isSend) { mqttAddDebugCmd(`发送蓝牙指令:${cmd} \n ${result}`); } console.log(`${key}解析- [${result}]`); } static _int2Hex(num) { let hexStr = num >>> 0; // 将 num 转换为无符号 32 位整数 hexStr = hexStr.toString(16); // 转换为 16 进制字符串 let i = parseInt(hexStr, 16); // 将 16 进制字符串转换回整数 // console.log(`${hexStr}==${i}==${num}`); return i; } static _int2HexString(value) { return value.toString(16).toUpperCase(); } } // 设备命令类型 const CmdBase = { secretKey: "smart_A2F", queryVersion: 0x30, checkDevice: 0x28, checkDeviceSuccess: 0x27, setAutoPlay: 0x24, getAutoPlay: 0x23, queryChannelAngle: 0x38, switchLed: 0x39, queryVolume: 0x32, setVolume: 0x33, wallPaper: 0x78, wallPaperData: 0x79, heiJiaoOta: 0x074, heiJiaoOtaData: 0x075, heijiaoBackImg: 0x76, heijiaoBackImgData: 0x77, newFlag: "MW-Mate X\\(4G_WIFI\\)|MW-2AX\\(WIFI-N\\)|MW-SR1\\(4G_WIFI\\)|MW-SR1\\(4G_WIFI_MEIZU01\\)", // volumeMax: (new RegExp(`^(${CmdBase.newFlag})$`, 'i').test(DeviceManager.instance.clientType || "")) ? 0x20 : 0xF, volumeMax: 15, parseVersion(version) { let ver; if (version <= 0) { ver = "1.0.0"; } else { const split = version.toString().split(""); if (split.length === 1) { split.unshift("0", "0"); } else if (split.length === 2) { split.unshift("0"); } ver = split.join("."); } console.log(`parseVersion======${version},,,,,,,${ver.toString()}`); return ver; } }; // 耳机相关指令 const CmdEarPhone = { queryLowDelayMode: 0xb2, setLowDelayMode: 0xb3, queryEQ: 0xb4, setEQ: 0xb5, queryEarPhoneKwh: 0xb1, queryCtrlStatus: 0xB6, setCtrlStatus: 0xB7, queryLowPower: 0xB8, setLowPowerMode: 0xB9 }; // 时间相关 const CmdRtc = { setTime: 0x50, queryTime: 0x51, setAlarm: 0x52, queryAlarm: 0x54, setSleep: 0x56, querySleep: 0x57, setSleepAfterPlayPause: 0x5a, querySleepAfterPlayPause: 0x5b }; // 设置设备颜色 const CmdRgb = { query: 0x80, set: 0x81 }; // 电量相关命令 const CmdKwh = { queryKwh: 0x22, setLowKwhWarningTone: 0x26, queryLowKwhWarningTone: 0x25 }; // 按键 const CmdKey = { previousSong: 0x0a, nextSong: 0x0b, previousChannel: 0x0c, nextChannel: 0x0d, type: 0x21, pressShort: 0x02, pressLongUp: 0x04, pressLong: 0x08, pressDouble: 0x09, next: 0x01, previous: 0x02, changeProgram: 0x03 }; // 语音 const CmdVoice = { startVoice: 0x01, jlStartVoice: 0x66, jlStopVoice: 0x68, jlStartVoiceResponse: 0x67, jlStopVoiceResponse: 0x69, jlReceiveVoiceData: 0x70, lxStartVoice: 0x71, lxStopVoice: 0x72, lxStartVoiceResponse: 0x40, lxStopVoiceResponse: 0x41, sjStartVoice: 0x23, sjStopVoice: 0x24 }; // 一周 const CmdWeek = { sunday: 0x01, monday: 0x02, tuesday: 0x04, wednesday: 0x08, thursday: 0x10, friday: 0x20, saturday: 0x40, weeks: [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40], week2Cmd(weekCycle) { let result = 0; for (let i = 0; i < weekCycle.length; i++) { const item = weekCycle[i]; if (item === EnumOpen.open) { result += this.weeks[i]; } } return result; }, cmd2Week(cmd) { const w = [0, 0, 0, 0, 0, 0, 0]; for (let i = this.weeks.length - 1; i >= 0; i--) { const week = this.weeks[i]; if (week <= cmd) { w[i] = EnumOpen.open; cmd -= week; } } return w; } }; module.exports = { BtCmd, CmdBase, CmdEarPhone, CmdRtc, CmdRgb, CmdKwh, CmdKey, CmdVoice, CmdWeek };