diff --git a/api/100J/HBY100-J.js b/api/100J/HBY100-J.js index 2666c89..68c5452 100644 --- a/api/100J/HBY100-J.js +++ b/api/100J/HBY100-J.js @@ -1,4 +1,137 @@ import request from '@/utils/request' + +// ================== 蓝牙协议封装类 ================== +class HBY100JProtocol { + constructor() { + this.deviceId = ''; // 4G 接口所需的 deviceId + this.isBleConnected = false; + this.bleDeviceId = ''; // 小程序/APP中连接蓝牙的 deviceId + + // 蓝牙服务与特征值 UUID + this.SERVICE_UUID = '0000AE30-0000-1000-8000-00805F9B34FB'; // 0xAE30 + this.WRITE_UUID = '0000AE03-0000-1000-8000-00805F9B34FB'; // 0xAE03 + this.NOTIFY_UUID = '0000AE02-0000-1000-8000-00805F9B34FB'; // 0xAE02 + + this.onNotifyCallback = null; + } + + setBleConnectionStatus(status, bleDeviceId = '') { + this.isBleConnected = status; + if (bleDeviceId) { + this.bleDeviceId = bleDeviceId; + } + } + + onNotify(callback) { + this.onNotifyCallback = callback; + } + + parseBleData(buffer) { + const view = new Uint8Array(buffer); + if (view.length < 3) return null; + + const header = view[0]; + const tail = view[view.length - 1]; + if (header !== 0xFB || tail !== 0xFF) return null; // 校验头尾 + + const funcCode = view[1]; + const data = view.slice(2, view.length - 1); + + let result = { funcCode, rawData: data }; + + switch (funcCode) { + case 0x01: result.resetType = data[0]; break; + case 0x02: break; + case 0x03: break; + case 0x04: result.batteryPercentage = data[16]; break; + case 0x06: result.voiceBroadcast = data[0]; break; + case 0x09: result.volume = data[0]; break; + case 0x0A: + result.strobeEnable = data[0]; + result.strobeMode = data[1]; + break; + case 0x0B: result.strobeFrequency = data[0]; break; + case 0x0C: + result.alarmEnable = data[0]; + result.alarmMode = data[1]; + break; + case 0x0D: + result.redBrightness = data[0]; + result.blueBrightness = data[1]; + result.yellowBrightness = data[2]; + break; + case 0x0E: + result.voiceBroadcast = data[0]; + result.alarmEnable = data[1]; + result.alarmMode = data[2]; + result.strobeEnable = data[3]; + result.strobeMode = data[4]; + result.strobeFrequency = data[5]; + result.volume = data[6]; + result.redBrightness = data[7]; + result.blueBrightness = data[8]; + result.yellowBrightness = data[9]; + break; + } + + if (this.onNotifyCallback) { + this.onNotifyCallback(result); + } + return result; + } + + sendBleData(funcCode, dataBytes = []) { + return new Promise((resolve, reject) => { + if (!this.isBleConnected || !this.bleDeviceId) { + return reject(new Error('蓝牙未连接')); + } + + const buffer = new ArrayBuffer(dataBytes.length + 3); + const view = new Uint8Array(buffer); + view[0] = 0xFA; // 数据头 + view[1] = funcCode; // 功能码 + for (let i = 0; i < dataBytes.length; i++) { + view[2 + i] = dataBytes[i]; + } + view[view.length - 1] = 0xFF; // 结尾 + + // 使用项目中统一的 BleHelper 发送数据 + import('@/utils/BleHelper.js').then(module => { + const bleTool = module.default.getBleTool(); + bleTool.sendData(this.bleDeviceId, buffer, this.SERVICE_UUID, this.WRITE_UUID) + .then(res => resolve(res)) + .catch(err => reject(err)); + }); + }); + } + + // 纯蓝牙指令发送方法 + deviceReset(type = 0) { return this.sendBleData(0x01, [type]); } + setVoiceBroadcast(enable) { return this.sendBleData(0x06, [enable]); } + setVolume(volume) { return this.sendBleData(0x09, [volume]); } + setStrobeMode(enable, mode) { return this.sendBleData(0x0A, [enable, mode]); } + setStrobeFrequency(frequency) { return this.sendBleData(0x0B, [frequency]); } + setForceAlarm(enable, mode) { return this.sendBleData(0x0C, [enable, mode]); } + setLightBrightness(red, blue = 0, yellow = 0) { return this.sendBleData(0x0D, [red, blue, yellow]); } + getCurrentWorkMode() { return this.sendBleData(0x0E, []); } +} + +// ================== 全局单例与状态管理 ================== +const protocolInstance = new HBY100JProtocol(); + +// 暴露给页面:更新蓝牙连接状态 +export function updateBleStatus(isConnected, bleDeviceId, deviceId) { + protocolInstance.setBleConnectionStatus(isConnected, bleDeviceId); + protocolInstance.deviceId = deviceId; +} + +// 暴露给页面:解析蓝牙接收到的数据 +export function parseBleData(buffer) { + return protocolInstance.parseBleData(buffer); +} + +// ================== API 接口 (拦截层) ================== + // 获取语音管理列表 export function deviceVoliceList(params) { return request({ @@ -39,8 +172,14 @@ export function deviceDetail(id) { method: 'get', }) } + // 爆闪模式 export function deviceStrobeMode(data) { + if (protocolInstance.isBleConnected) { + return protocolInstance.setStrobeMode(data.enable, data.mode).then(res => { + return { code: 200, msg: '操作成功(蓝牙)' }; + }); + } return request({ url: `/app/hby100j/device/strobeMode`, method: 'post', @@ -50,22 +189,39 @@ export function deviceStrobeMode(data) { // 强制报警 export function deviceForceAlarmActivation(data) { + if (protocolInstance.isBleConnected) { + return protocolInstance.setForceAlarm(data.voiceStrobeAlarm, data.mode).then(res => { + return { code: 200, msg: '操作成功(蓝牙)' }; + }); + } return request({ url: `/app/hby100j/device/forceAlarmActivation`, method: 'post', data:data }) } + // 爆闪频率 export function deviceStrobeFrequency(data) { + if (protocolInstance.isBleConnected) { + return protocolInstance.setStrobeFrequency(data.frequency).then(res => { + return { code: 200, msg: '操作成功(蓝牙)' }; + }); + } return request({ url: `/app/hby100j/device/strobeFrequency`, method: 'post', data:data }) } + // 灯光调节亮度 export function deviceLightAdjustment(data) { + if (protocolInstance.isBleConnected) { + return protocolInstance.setLightBrightness(data.brightness, data.brightness, data.brightness).then(res => { + return { code: 200, msg: '操作成功(蓝牙)' }; + }); + } return request({ url: `/app/hby100j/device/lightAdjustment`, method: 'post', @@ -75,14 +231,25 @@ export function deviceLightAdjustment(data) { // 调节音量 export function deviceUpdateVolume(data) { + if (protocolInstance.isBleConnected) { + return protocolInstance.setVolume(data.volume).then(res => { + return { code: 200, msg: '操作成功(蓝牙)' }; + }); + } return request({ url: `/app/hby100j/device/updateVolume`, method: 'post', data:data }) } + // 语音播放 export function deviceVoiceBroadcast(data) { + if (protocolInstance.isBleConnected) { + return protocolInstance.setVoiceBroadcast(data.voiceBroadcast).then(res => { + return { code: 200, msg: '操作成功(蓝牙)' }; + }); + } return request({ url: `/app/hby100j/device/voiceBroadcast`, method: 'post', diff --git a/pages/100J/HBY100-J.vue b/pages/100J/HBY100-J.vue index fa76ad2..5435443 100644 --- a/pages/100J/HBY100-J.vue +++ b/pages/100J/HBY100-J.vue @@ -229,8 +229,12 @@ deviceStrobeFrequency, deviceLightAdjustment, deviceUpdateVolume, - deviceVoiceBroadcast + deviceVoiceBroadcast, + updateBleStatus, + parseBleData } from '@/api/100J/HBY100-J.js' + import BleHelper from '@/utils/BleHelper.js'; + var bleTool = BleHelper.getBleTool(); var these = null; import Common from '@/utils/Common.js' const pagePath = "/pages/100/HBY100"; @@ -591,11 +595,37 @@ }); this.createThrottledFunctions(); + + // 注册蓝牙相关事件 + bleTool.addReceiveCallback(this.bleValueNotify, "HBY100J"); + bleTool.addDisposeCallback(this.bleStateBreak, "HBY100J"); + bleTool.addRecoveryCallback(this.bleStateRecovry, "HBY100J"); + bleTool.addStateBreakCallback(this.bleStateBreak, "HBY100J"); + bleTool.addStateRecoveryCallback(this.bleStateRecovry, "HBY100J"); + + // 尝试连接蓝牙 + if (data.data.deviceMac) { + // 假设 deviceMac 是蓝牙的 deviceId + bleTool.LinkBlue(data.data.deviceMac).then(() => { + console.log("100J 蓝牙连接成功"); + this.bleStateRecovry({deviceId: data.data.deviceMac}); + }).catch(err => { + console.log("100J 蓝牙连接失败,将使用4G", err); + }); + } }, onHide: function() { this.Status.pageHide = true; }, + onUnload() { + // 移除蓝牙事件监听 + bleTool.removeReceiveCallback("HBY100J"); + bleTool.removeDisposeCallback("HBY100J"); + bleTool.removeRecoveryCallback("HBY100J"); + bleTool.removeStateBreakCallback("HBY100J"); + bleTool.removeStateRecoveryCallback("HBY100J"); + }, onShow() { this.Status.pageHide = false; }, @@ -949,13 +979,26 @@ deviceRecovry(res) {}, deviceDispose(res) {}, - bleStateBreak() {}, - bleStateRecovry() {}, + bleStateBreak() { + updateBleStatus(false, '', this.deviceInfo.deviceId); + }, + bleStateRecovry(res) { + let bleDeviceId = res ? res.deviceId : ''; + updateBleStatus(true, bleDeviceId, this.deviceInfo.deviceId); + }, previewImg(img) {}, bleValueNotify: function(receive, device, path, recArr) { //订阅消息 - if (receive.deviceId !== this.formData.deviceId) { - return; + // 注意:这里 receive.deviceId 是蓝牙的 MAC 地址,而 this.formData.deviceId 是 4G 的 ID + // 所以这里需要修改判断逻辑,或者不判断直接解析 + + // 尝试解析蓝牙上报的数据 + if (receive.bytes) { + const parsedData = parseBleData(receive.bytes); + if (parsedData && parsedData.batteryPercentage !== undefined) { + this.deviceInfo.batteryPercentage = parsedData.batteryPercentage; + } } + if (this.deviceInfo.batteryPercentage <= 20) { this.showMsg("设备电量低"); } diff --git a/utils/BleHelper.js b/utils/BleHelper.js index 1124b62..2578eb2 100644 --- a/utils/BleHelper.js +++ b/utils/BleHelper.js @@ -1955,17 +1955,17 @@ class BleHelper { return; } // console.log("device=", device); - uni.writeBLECharacteristicValue({ - deviceId: device.deviceId, - serviceId: device.writeServiceId, - characteristicId: device.wirteCharactId, - value: buffer, - writeType: 'write', - success: () => { - console.log("✓ 蓝牙指令发送成功 - deviceId:", device - .deviceId); - succ(); - }, + uni.writeBLECharacteristicValue({ + deviceId: device.deviceId, + serviceId: device.writeServiceId, + characteristicId: device.wirteCharactId, + value: buffer, + writeType: 'write', + success: () => { + console.log("✓ 蓝牙指令发送成功 - deviceId:", device + .deviceId); + succ(); + }, fail: (ex) => { ex = this.getError(ex); console.error("✗ 蓝牙指令发送失败 - deviceId:", device