wx-starlock/stores/bluetooth.js

2360 lines
76 KiB
JavaScript
Raw Normal View History

/**
* @description 蓝牙数据持久化
*/
import { defineStore } from 'pinia'
import crc from 'crc'
import { sm4 } from 'sm-crypto'
import { md5 } from 'js-md5'
2024-08-24 14:25:05 +08:00
import { getServerDatetime } from '@/api/check'
import { getUserNoListRequest, updateLockUserNoRequest } from '@/api/key'
2024-08-30 15:56:04 +08:00
import { updateElectricQuantityRequest } from '@/api/room'
2024-09-02 09:28:00 +08:00
import { reportOpenDoorRequest } from '@/api/lockRecords'
import { updateTimezoneOffsetRequest } from '@/api/user'
2024-10-24 15:44:42 +08:00
import log from '@/utils/log'
import { useUserStore } from '@/stores/user'
// 定时器
let timer
// 特性值回调
let characteristicValueCallback = null
// 搜索次数
let searchNumber = 10
// 搜索提示标志
let searchTipFlag = true
// 命令ID
const cmdIds = {
// 获取公钥
getPublicKey: 0x3090,
// 获取私钥
getCommKey: 0x3091,
// 获取锁状态
getLockStatus: 0x3040,
// 新增用户
addUser: 0x3001,
// 开门
openDoor: 0x3005,
// 重置设备
resetDevice: 0x3004,
// 清理用户
2025-02-06 11:37:41 +08:00
cleanUser: 0x300c,
// 扩展命令
expandCmd: 0x3030
}
// 子命令ID
const subCmdIds = {
// 设置开锁密码
setLockPassword: 3,
// 重置开锁密码
2025-02-08 18:31:14 +08:00
resetLockPassword: 19,
// 注册卡片
registerCard: 24,
// 注册卡片确认
registerCardConfirm: 22,
// 注册卡片取消
registerCardCancel: 25
}
export const useBluetoothStore = defineStore('ble', {
state() {
return {
/*
2025-02-06 11:37:41 +08:00
* 蓝牙状态
* -1 未知初始状态
* 0 正常
* 1 系统蓝牙未打开
* 2 小程序蓝牙功能被禁用
* 3 系统蓝牙未打开且小程序蓝牙功能被禁用
*/
bluetoothStatus: -1,
// 设备列表
deviceList: [],
// 当前锁信息
currentLockInfo: {},
// 消息序号
2024-08-22 16:37:15 +08:00
messageCount: 1,
// 是否初始化蓝牙
2024-08-24 14:25:05 +08:00
isInitBluetooth: false,
// 服务器时间
serverTimestamp: 0,
// 设备keyID
keyId: '0',
// 刚绑定的设备名称
bindedDeviceNameList: []
}
},
actions: {
// 保存刚绑定的设备名称
updateBindedDeviceName(name) {
2025-02-06 11:37:41 +08:00
if (!this.bindedDeviceNameList.includes(name)) {
this.bindedDeviceNameList.push(name)
}
},
// 更新keyId
updateKeyId(keyId) {
this.keyId = keyId
},
2024-08-24 14:25:05 +08:00
// 二进制转字符串
uint8ArrayToString(uint8Array) {
let str = ''
for (let i = 0; i < uint8Array.length; i++) {
if (uint8Array[i] !== 0) {
2025-02-06 11:37:41 +08:00
str += String.fromCharCode(uint8Array[i])
2024-08-24 14:25:05 +08:00
}
}
return str
},
// 更新服务端时间戳
async updateServerTimestamp() {
const { code, data, message } = await getServerDatetime({})
2025-02-07 16:28:45 +08:00
let timestamp = new Date().getTime()
2025-02-06 11:37:41 +08:00
if (code === 0) {
this.serverTimestamp = parseInt(data.date / 1000, 10)
2025-02-07 16:28:45 +08:00
timestamp = data.date
2024-08-24 14:25:05 +08:00
}
2025-02-07 16:28:45 +08:00
return { code, data: { ...data, timestamp }, message }
2024-08-24 14:25:05 +08:00
},
// 关闭全部蓝牙监听并关闭蓝牙模拟
closeAllBluetooth() {
uni.offBluetoothAdapterStateChange()
uni.closeBluetoothAdapter({
success(res) {
console.log('关闭蓝牙模块', res)
}
})
},
2024-08-22 16:37:15 +08:00
// 初始化并监听
async initAndListenBluetooth(tipFlag) {
2024-08-22 16:37:15 +08:00
// 初始化蓝牙
const initResult = await this.initBluetooth(tipFlag)
2024-08-22 16:37:15 +08:00
if (initResult) {
// 更新蓝牙初始化状态
this.updateInitBluetooth(true)
// 监听蓝牙连接状态
this.onBluetoothConnectStatus()
// 监听设备特征值变化
this.onBluetoothCharacteristicValueChange()
return true
}
2025-02-06 11:37:41 +08:00
return false
2024-08-22 16:37:15 +08:00
},
// 更新是否初始化蓝牙字段
updateInitBluetooth(value) {
this.isInitBluetooth = value
},
// 初始化蓝牙模块
initBluetooth(tipFlag = true) {
const that = this
// 初始化蓝牙模块
return new Promise(resolve => {
uni.openBluetoothAdapter({
success() {
that.bluetoothStatus = 0
console.log('蓝牙初始化成功')
2024-08-22 16:37:15 +08:00
resolve(true)
},
fail(err) {
console.log('蓝牙初始化失败', err)
// 系统蓝牙未打开
2025-02-06 11:37:41 +08:00
if (err.errCode === 10001) {
if (that.bluetoothStatus === 2) {
that.bluetoothStatus = 3
} else {
that.bluetoothStatus = 1
}
}
// 小程序蓝牙功能被禁用
2025-02-06 11:37:41 +08:00
if (err.errno === 103) {
if (that.bluetoothStatus === 1) {
that.bluetoothStatus = 3
} else {
that.bluetoothStatus = 2
}
}
2024-08-22 16:37:15 +08:00
// 蓝牙已经初始化
2025-02-06 11:37:41 +08:00
if (err.errMsg === 'openBluetoothAdapter:fail already opened') {
2024-08-22 16:37:15 +08:00
resolve(true)
return
}
2025-02-06 11:37:41 +08:00
if (err.errno === 3 && tipFlag) {
uni.showModal({
title: '提示',
content: '蓝牙功能需要附近设备权限,请前往设置开启微信的附近设备权限后再试',
showCancel: false,
confirmText: '确定',
success(res) {
if (res.confirm) {
uni.openAppAuthorizeSetting({
2025-02-06 11:37:41 +08:00
success(res) {
console.log(res)
}
})
}
}
})
}
2024-08-22 16:37:15 +08:00
resolve(false)
}
})
})
},
// 监听蓝牙状态变化
onBluetoothState() {
const that = this
2025-02-06 11:37:41 +08:00
uni.onBluetoothAdapterStateChange(res => {
console.log('蓝牙状态改变', res)
2025-02-06 11:37:41 +08:00
if (that.bluetoothStatus === 3 && res.available) {
that.bluetoothStatus = 2
} else if (that.bluetoothStatus === 2 && !res.available) {
that.bluetoothStatus = 3
} else if (that.bluetoothStatus === 1 && res.available) {
that.bluetoothStatus = 0
2025-02-06 11:37:41 +08:00
} else if (that.bluetoothStatus === 0 && !res.available) {
that.bluetoothStatus = 1
} else if (that.bluetoothStatus === -1) {
2025-02-06 11:37:41 +08:00
if (res.available) {
that.bluetoothStatus = 0
} else {
that.bluetoothStatus = 1
}
}
})
},
// 监听蓝牙设备连接状态
onBluetoothConnectStatus() {
const that = this
uni.onBLEConnectionStateChange(function (res) {
2025-02-06 11:37:41 +08:00
if (res.deviceId === that.currentLockInfo.deviceId) {
console.log('设备连接状态改变', res)
that.updateCurrentLockInfo({
...that.currentLockInfo,
connected: res.connected
})
}
})
},
// 解析特征值
parsingCharacteristicValue(binaryData) {
2024-10-24 15:44:42 +08:00
const $user = useUserStore()
const that = this
// 0x20 明文 0x22 SM4事先约定密钥 0x23 SM4设备指定密钥
2025-02-06 11:37:41 +08:00
if (binaryData[7] === 0x20) {
if (binaryData[12] * 256 + binaryData[13] === cmdIds.getPublicKey) {
if (binaryData[14] === 0) {
that.updateCurrentLockInfo({
...that.currentLockInfo,
2024-08-24 14:25:05 +08:00
publicKey: [...binaryData.slice(15, 31)]
})
}
characteristicValueCallback({
code: binaryData[14]
})
}
2025-02-06 11:37:41 +08:00
} else if (binaryData[7] === 0x22) {
// 截取入参
const cebBinaryData = binaryData.slice(12, binaryData.length - 2)
// 解密
const key = new Uint8Array(16)
for (let i = 0; i < that.currentLockInfo.name.length; i++) {
key[i] = that.currentLockInfo.name.charCodeAt(i)
}
const decrypted = sm4.decrypt(cebBinaryData, key, { mode: 'ecb', output: 'array' })
console.log('ecb解密后的数据', decrypted)
2025-02-06 11:37:41 +08:00
if (decrypted[0] * 256 + decrypted[1] === cmdIds.getCommKey) {
if (decrypted[2] === 0) {
that.updateCurrentLockInfo({
...that.currentLockInfo,
commKey: decrypted.slice(3, 19),
2024-08-24 14:25:05 +08:00
signKey: decrypted.slice(19, 35),
pwdTimestamp: this.arrayToTimestamp(decrypted.slice(35, 39)) * 1000
})
console.log('commKey', Array.from(that.currentLockInfo.commKey))
console.log('signKey', Array.from(that.currentLockInfo.signKey))
}
characteristicValueCallback({
code: decrypted[2]
})
}
} else {
const cebBinaryData = binaryData.slice(12, binaryData.length - 2)
2025-02-06 11:37:41 +08:00
const decrypted = sm4.decrypt(cebBinaryData, that.currentLockInfo.commKey, {
mode: 'ecb',
output: 'array'
})
console.log('ecb解密后的数据', decrypted)
const cmdId = decrypted[0] * 256 + decrypted[1]
switch (cmdId) {
case cmdIds.getLockStatus:
if (decrypted[2] === 0) {
const lockConfig = {
2024-08-24 14:25:05 +08:00
vendor: that.uint8ArrayToString(decrypted.slice(3, 23)),
product: decrypted[23],
2024-08-24 14:25:05 +08:00
model: that.uint8ArrayToString(decrypted.slice(24, 44)),
fwVersion: that.uint8ArrayToString(decrypted.slice(44, 64)),
hwVersion: that.uint8ArrayToString(decrypted.slice(64, 84)),
serialNum0: that.uint8ArrayToString(decrypted.slice(84, 100)),
serialNum1: that.uint8ArrayToString(decrypted.slice(100, 116)),
btDeviceName: that.uint8ArrayToString(decrypted.slice(116, 132)),
electricQuantity: decrypted[132],
electricQuantityStandby: decrypted[133],
restoreCount: decrypted[134] * 256 + decrypted[135],
restoreDate: this.arrayToTimestamp(decrypted.slice(136, 140)),
icPartNo: that.uint8ArrayToString(decrypted.slice(140, 150)),
indate: this.arrayToTimestamp(decrypted.slice(150, 154)),
mac: that.uint8ArrayToString(decrypted.slice(154, 174)),
timezoneOffset: new Date().getTimezoneOffset() * 60
}
that.updateCurrentLockInfo({
...that.currentLockInfo,
2024-08-24 14:25:05 +08:00
featureValue: that.uint8ArrayToString(decrypted.slice(175, 175 + decrypted[174])),
2025-02-06 11:37:41 +08:00
featureSettingValue: that.uint8ArrayToString(
decrypted.slice(
176 + decrypted[174],
176 + decrypted[174] + decrypted[175 + decrypted[174]]
)
),
featureSettingParams: Array.from(
decrypted.slice(176 + decrypted[174] + decrypted[175 + decrypted[174]])
),
lockConfig
})
console.log('获取锁状态成功', that.currentLockInfo.lockConfig)
}
characteristicValueCallback({
code: decrypted[2]
})
break
case cmdIds.addUser:
that.updateCurrentLockInfo({
...that.currentLockInfo,
2025-02-06 11:37:41 +08:00
token: decrypted.slice(42, 46)
})
2025-02-06 11:37:41 +08:00
if (decrypted[46] === 0) {
that.updateCurrentLockInfo({
...that.currentLockInfo,
lockUserNo: decrypted[47] * 256 + decrypted[48]
})
}
console.log('添加用户结果', decrypted[46], that.currentLockInfo.token)
characteristicValueCallback({
code: decrypted[46]
})
break
case cmdIds.expandCmd:
const subCmdId = decrypted[3]
2025-02-06 11:37:41 +08:00
// eslint-disable-next-line default-case
switch (subCmdId) {
case subCmdIds.resetLockPassword:
that.updateCurrentLockInfo({
...that.currentLockInfo,
2025-02-06 11:37:41 +08:00
token: decrypted.slice(5, 9)
})
characteristicValueCallback({
code: decrypted[2]
})
2025-02-06 11:37:41 +08:00
if (decrypted[2] === 0) {
that.updateCurrentLockInfo({
...that.currentLockInfo,
encrpyKey: decrypted.slice(9, 17)
})
}
break
case subCmdIds.setLockPassword:
that.updateCurrentLockInfo({
...that.currentLockInfo,
2025-02-06 11:37:41 +08:00
token: decrypted.slice(5, 9)
})
characteristicValueCallback({
code: decrypted[2],
data: {
status: decrypted[11]
}
})
break
2025-02-08 18:31:14 +08:00
case subCmdIds.registerCard:
that.updateCurrentLockInfo({
...that.currentLockInfo,
token: decrypted.slice(5, 9)
})
characteristicValueCallback({
code: decrypted[2],
data: {
status: decrypted[9],
cardNo: decrypted[10] * 256 + decrypted[11]
}
})
break
case subCmdIds.registerCardConfirm:
uni.$emit('registerCardConfirm', {
status: decrypted[5],
cardNumber: decrypted[6] * 256 + decrypted[7]
})
break
}
break
2024-08-30 15:56:04 +08:00
case cmdIds.openDoor:
that.updateCurrentLockInfo({
...that.currentLockInfo,
2025-02-06 11:37:41 +08:00
token: decrypted.slice(2, 6)
2024-08-30 15:56:04 +08:00
})
2024-09-02 14:22:19 +08:00
console.log('开门', decrypted[6], that.currentLockInfo.token)
2024-10-24 15:44:42 +08:00
log.info({
code: decrypted[6],
message: `锁端返回状态码`,
data: {
lockName: this.currentLockInfo.name,
lockId: this.currentLockInfo.lockId,
uid: $user.userInfo.uid,
nickname: $user.userInfo.nickname,
mobile: $user.userInfo.mobile,
email: $user.userInfo.email
}
})
2024-08-30 15:56:04 +08:00
characteristicValueCallback({
code: decrypted[6]
})
2025-02-06 11:37:41 +08:00
if (decrypted[6] === 0) {
2024-10-24 15:44:42 +08:00
log.info({
code: decrypted[6],
message: `开门成功`,
data: {
lockName: this.currentLockInfo.name,
lockId: this.currentLockInfo.lockId,
uid: $user.userInfo.uid,
nickname: $user.userInfo.nickname,
mobile: $user.userInfo.mobile,
email: $user.userInfo.email
}
})
2024-08-30 15:56:04 +08:00
updateElectricQuantityRequest({
lockId: that.currentLockInfo.lockId,
electricQuantity: decrypted[7],
electricQuantityStandby: decrypted[9]
}).then(res => {
2025-02-06 11:37:41 +08:00
if (res.code === 0) {
2024-08-30 15:56:04 +08:00
that.updateCurrentLockInfo({
...that.currentLockInfo,
electricQuantityDate: res.data.electricQuantityDate
})
}
})
2024-09-02 09:28:00 +08:00
reportOpenDoorRequest({
lockId: that.currentLockInfo.lockId,
2025-02-06 11:37:41 +08:00
keyId: that.keyId
2024-09-02 09:28:00 +08:00
}).then(res => {
console.log('上报开门结果', res)
})
updateTimezoneOffsetRequest({
timezoneOffset: new Date().getTimezoneOffset() * 60
}).then(res => {
console.log('上报时区结果', res)
})
2024-08-30 15:56:04 +08:00
}
2024-09-02 14:22:19 +08:00
break
default:
that.updateCurrentLockInfo({
...that.currentLockInfo,
2025-02-06 11:37:41 +08:00
token: decrypted.slice(2, 6)
})
console.log('默认结果', decrypted[6], that.currentLockInfo.token)
characteristicValueCallback({
code: decrypted[6]
})
break
}
}
},
// 监听蓝牙设备特征值改变
onBluetoothCharacteristicValueChange() {
const that = this
// 完整数据
let completeArray
// 完整内容数据长度
let length
console.log('开始监听特征值改变')
uni.onBLECharacteristicValueChange(function (res) {
2025-02-06 11:37:41 +08:00
if (res.deviceId === that.currentLockInfo.deviceId) {
let binaryData = new Uint8Array(res.value)
2025-02-06 11:37:41 +08:00
if (
binaryData[0] === 0xef &&
binaryData[1] === 0x01 &&
binaryData[2] === 0xee &&
binaryData[3] === 0x02
) {
length = binaryData[8] * 256 + binaryData[9]
2025-02-06 11:37:41 +08:00
if (length + 14 > binaryData.length) {
completeArray = binaryData
} else {
that.parsingCharacteristicValue(binaryData)
}
2025-02-06 11:37:41 +08:00
} else if (completeArray) {
const combinedArray = new Uint8Array(completeArray.length + binaryData.length)
combinedArray.set(completeArray, 0)
combinedArray.set(binaryData, completeArray.length)
completeArray = combinedArray
if (length + 14 === completeArray.length) {
that.parsingCharacteristicValue(completeArray)
completeArray = null
}
}
}
})
},
// 开始搜索蓝牙设备
getBluetoothDevices() {
const that = this
2025-02-06 11:37:41 +08:00
if (this.bluetoothStatus !== 0) {
console.log('搜索未执行', this.bluetoothStatus)
this.getBluetoothStatus()
return
}
this.deviceList = []
uni.startBluetoothDevicesDiscovery({
2025-02-06 11:37:41 +08:00
success() {
setTimeout(() => {
that.searchBluetoothDevices()
}, 300)
},
2025-02-06 11:37:41 +08:00
async fail(res) {
console.log('开始搜索失败', res)
2025-02-06 11:37:41 +08:00
if (res.errno === 1509008) {
uni.showModal({
title: '提示',
content: '安卓手机蓝牙功能需要定位权限,请前往设置开启微信的定位权限后再试',
showCancel: false,
success(res) {
if (res.confirm) {
uni.openAppAuthorizeSetting({
2025-02-06 11:37:41 +08:00
success(res) {
console.log(res)
}
})
}
uni.navigateBack()
}
})
}
2025-02-06 11:37:41 +08:00
if (res.errCode === 10000) {
// 重新初始化蓝牙适配器
await that.initBluetooth()
that.getBluetoothDevices()
}
}
})
},
// 定时查询蓝牙设备
searchBluetoothDevices() {
const that = this
2025-02-06 11:37:41 +08:00
if (this.bluetoothStatus !== 0) {
console.log('搜索未执行', this.bluetoothStatus)
this.getBluetoothStatus()
return
}
timer = setInterval(() => {
uni.getBluetoothDevices({
success(res) {
searchNumber--
2025-02-06 11:37:41 +08:00
if (searchNumber === 0 && searchTipFlag) {
uni.showModal({
title: '提示',
2025-02-06 11:37:41 +08:00
content:
'长时间未搜索到任何设备,请确认微信的附近设备权限开启后再试(鸿蒙系统在设置-隐私-定位服务中开启位置信息权限)',
showCancel: false,
success() {
uni.openAppAuthorizeSetting({
2025-02-06 11:37:41 +08:00
success(res) {
console.log(res)
}
})
uni.navigateBack()
}
})
}
const deviceList = res.devices
2025-02-06 11:37:41 +08:00
if (deviceList.length !== 0) {
searchTipFlag = false
}
that.deviceList = []
2025-02-06 11:37:41 +08:00
for (let i = 0; i < deviceList.length; i++) {
if (deviceList[i]?.advertisServiceUUIDs) {
const uuid = deviceList[i]?.advertisServiceUUIDs[0]
2025-02-06 11:37:41 +08:00
if (uuid && uuid.slice(2, 8) === '758824' && uuid.slice(30, 32) === '00') {
that.deviceList.push(deviceList[i])
}
}
}
console.log('设备列表', that.deviceList)
},
2025-02-06 11:37:41 +08:00
async fail(res) {
console.log('获取设备列表失败', res)
2025-02-06 11:37:41 +08:00
if (res.errCode === 10000) {
// 重新初始化蓝牙适配器
await that.initBluetooth()
}
}
})
}, 1000)
},
// 停止搜索蓝牙设备
stopGetBluetoothDevices() {
searchNumber = 10
searchTipFlag = true
clearInterval(timer)
uni.stopBluetoothDevicesDiscovery()
},
// 蓝牙状态提示
2025-02-06 11:37:41 +08:00
async getBluetoothStatus() {
2024-09-14 10:26:06 +08:00
if (this.bluetoothStatus === 1) {
const initResult = await this.initBluetooth()
if (!initResult) {
uni.showModal({
title: '提示',
content: '蓝牙尚未打开,请先打开蓝牙',
showCancel: false,
2025-02-06 11:37:41 +08:00
success(res) {
2024-09-14 10:26:06 +08:00
if (res.confirm) {
wx.openSystemBluetoothSetting({
2025-02-06 11:37:41 +08:00
success(res) {
2024-09-14 10:26:06 +08:00
console.log(res)
}
})
}
}
2024-09-14 10:26:06 +08:00
})
}
} else if (this.bluetoothStatus === 2 || this.bluetoothStatus === 3) {
uni.showModal({
title: '提示',
content: '小程序蓝牙功能被禁用,请打开小程序蓝牙权限',
showCancel: false,
confirmText: '去设置',
2025-02-06 11:37:41 +08:00
success(res) {
2024-09-14 10:26:06 +08:00
if (res.confirm) {
uni.openSetting()
}
}
})
}
},
// 检查小程序设置
checkSetting() {
const that = this
2025-02-06 11:37:41 +08:00
return new Promise(resolve => {
2024-08-22 16:37:15 +08:00
uni.getSetting({
async success(res) {
const bluetooth = res.authSetting['scope.bluetooth']
2025-02-06 11:37:41 +08:00
if (that.bluetoothStatus === -1) {
if (bluetooth !== false) {
2024-08-22 16:37:15 +08:00
that.bluetoothStatus = 0
} else {
that.bluetoothStatus = 2
}
2025-02-06 11:37:41 +08:00
} else if (that.bluetoothStatus === 0 && bluetooth === false) {
that.bluetoothStatus = 2
2025-02-06 11:37:41 +08:00
} else if (that.bluetoothStatus === 1 && bluetooth === false) {
2024-08-22 16:37:15 +08:00
that.bluetoothStatus = 3
2025-02-06 11:37:41 +08:00
} else if (that.bluetoothStatus === 2 && bluetooth !== false) {
2024-08-22 16:37:15 +08:00
that.bluetoothStatus = 0
await that.initBluetooth()
2025-02-06 11:37:41 +08:00
} else if (that.bluetoothStatus === 3 && bluetooth !== false) {
2024-08-22 16:37:15 +08:00
that.bluetoothStatus = 1
}
2024-08-22 16:37:15 +08:00
console.log('蓝牙权限', bluetooth, that.bluetoothStatus)
resolve(bluetooth)
},
fail() {
resolve(false)
}
2024-08-22 16:37:15 +08:00
})
})
},
// 连接蓝牙设备+获取设备服务+获取设备特征值
connectBluetoothDevice(number = 0) {
const that = this
2025-02-06 11:37:41 +08:00
return new Promise(resolve => {
if (that.bluetoothStatus !== 0) {
console.log('连接未执行', that.bluetoothStatus)
that.getBluetoothStatus()
resolve(false)
return
}
uni.createBLEConnection({
deviceId: that.currentLockInfo.deviceId,
2024-09-07 17:28:39 +08:00
timeout: 10000,
success(res) {
console.log('连接成功', res)
// 获取设备服务
uni.getBLEDeviceServices({
deviceId: that.currentLockInfo.deviceId,
2025-02-06 11:37:41 +08:00
success(res) {
let serviceId
2025-02-06 11:37:41 +08:00
for (let i = 0; i < res.services.length; i++) {
if (res.services[i].uuid.indexOf('FFF0') !== -1) {
serviceId = res.services[i].uuid
}
}
// 获取设备对应服务的特征值
uni.getBLEDeviceCharacteristics({
deviceId: that.currentLockInfo.deviceId,
2025-02-06 11:37:41 +08:00
serviceId,
success(res) {
let notifyCharacteristicId
let writeCharacteristicId
2025-02-06 11:37:41 +08:00
for (let i = 0; i < res.characteristics.length; i++) {
const characteristic = res.characteristics[i]
2025-02-06 11:37:41 +08:00
if (characteristic.properties.notify) {
notifyCharacteristicId = characteristic.uuid
}
2025-02-06 11:37:41 +08:00
if (characteristic.properties.write) {
writeCharacteristicId = characteristic.uuid
}
}
that.updateCurrentLockInfo({
...that.currentLockInfo,
serviceId,
notifyCharacteristicId,
writeCharacteristicId
})
that.notifyBluetoothCharacteristicValueChange()
resolve(true)
},
fail(res) {
2025-02-06 11:37:41 +08:00
if (res.errCode === 10006) {
uni.showToast({
title: '连接失败,请靠近设备并保持设备处于唤醒状态',
icon: 'none'
})
}
console.log('获取设备特征值失败', res)
resolve(false)
}
})
},
fail(res) {
2025-02-06 11:37:41 +08:00
if (res.errCode === 10006) {
uni.showToast({
title: '连接失败,请靠近设备并保持设备处于唤醒状态',
icon: 'none'
})
}
console.log('获取设备服务失败', res)
resolve(false)
}
})
},
async fail(res) {
console.log('连接失败', res)
2025-02-06 11:37:41 +08:00
if (res.errno === 1509007) {
resolve(true)
return
}
2025-02-06 11:37:41 +08:00
if (res.errno === 1509001 && number < 1) {
// 超时直接返回
resolve(false)
return
}
2025-02-06 11:37:41 +08:00
if (number < 1) {
// 重新连接
resolve(await that.connectBluetoothDevice(number + 1))
}
}
})
})
},
// 更新当前锁信息
updateCurrentLockInfo(lockInfo) {
console.log('更新当前锁信息', lockInfo)
this.currentLockInfo = lockInfo
},
// 订阅设备特征值改变
notifyBluetoothCharacteristicValueChange() {
const that = this
uni.notifyBLECharacteristicValueChange({
state: true,
deviceId: that.currentLockInfo.deviceId,
serviceId: that.currentLockInfo.serviceId,
characteristicId: that.currentLockInfo.notifyCharacteristicId,
success(res) {
console.log('订阅成功', res)
},
fail(res) {
console.log('订阅失败', res)
}
})
},
// 断开蓝牙连接
closeBluetoothConnection() {
const that = this
uni.closeBLEConnection({
deviceId: that.currentLockInfo.deviceId,
success(res) {
console.log('断开连接成功', res)
},
fail(res) {
console.log('断开连接失败', res)
}
})
},
// 周数组转换
convertWeekdaysToNumber(weekDay) {
let weekStr = '00000000'
2025-02-06 11:37:41 +08:00
// eslint-disable-next-line no-restricted-syntax
for (const day of weekDay) {
2025-02-06 11:37:41 +08:00
const index = day % 7 // 将周日的索引转换为0
weekStr = weekStr.substring(0, index) + '1' + weekStr.substring(index + 1)
}
// 倒序 weekStr
weekStr = weekStr.split('').reverse().join('')
2025-02-06 14:59:10 +08:00
return parseInt(weekStr, 2)
},
// 查找设备并连接
async searchAndConnectDevice() {
const that = this
let timer1
let timer2
2025-02-06 11:37:41 +08:00
return new Promise(resolve => {
uni.startBluetoothDevicesDiscovery({
2025-02-06 11:37:41 +08:00
success() {
2024-09-27 10:29:15 +08:00
let searchFlag = false
timer2 = setTimeout(async () => {
uni.stopBluetoothDevicesDiscovery()
clearInterval(timer1)
if (!searchFlag) {
uni.showModal({
title: '提示',
2025-02-06 11:37:41 +08:00
content:
'长时间未搜索到任何设备,请确认微信的附近设备权限开启后再试(鸿蒙系统在设置-隐私-定位服务中开启位置信息权限)',
2024-09-27 10:29:15 +08:00
showCancel: false,
2025-02-06 11:37:41 +08:00
success() {
2024-09-27 10:29:15 +08:00
uni.openAppAuthorizeSetting({
2025-02-06 11:37:41 +08:00
success(res) {
2024-09-27 10:29:15 +08:00
console.log(res)
}
})
}
})
2024-10-24 15:44:42 +08:00
resolve({ code: -22 })
} else {
resolve({ code: -4 })
2024-09-27 10:29:15 +08:00
}
}, 10500)
timer1 = setInterval(() => {
2025-02-06 11:37:41 +08:00
uni.getBluetoothDevices({
success(res) {
const deviceList = res.devices
if (searchFlag === false && res.devices.length > 0) {
searchFlag = true
}
for (let i = 0; i < deviceList.length; i++) {
if (deviceList[i]?.name === that.currentLockInfo.name) {
const uuid = deviceList[i]?.advertisServiceUUIDs[0]
console.log('设备UUID', uuid, uuid.slice(2, 8), uuid.slice(30, 32))
if (
uuid &&
uuid.slice(2, 8) === '758824' &&
(uuid.slice(30, 32) === '01' ||
that.bindedDeviceNameList.includes(that.currentLockInfo.name))
) {
uni.stopBluetoothDevicesDiscovery()
clearTimeout(timer2)
clearInterval(timer1)
resolve({
code: 0,
data: {
deviceId: deviceList[i].deviceId
}
})
break
} else if (
uuid &&
uuid.slice(2, 8) === '758824' &&
uuid.slice(30, 32) === '00'
) {
uni.stopBluetoothDevicesDiscovery()
clearTimeout(timer2)
clearInterval(timer1)
uni.hideLoading()
uni.showToast({
title: '锁已被重置,请重新绑定',
icon: 'none'
})
resolve({
code: -2
})
break
} else {
uni.stopBluetoothDevicesDiscovery()
clearTimeout(timer2)
clearInterval(timer1)
resolve({
code: -3
})
break
}
}
}
2025-02-06 11:37:41 +08:00
},
async fail(res) {
console.log('获取设备列表失败', res)
if (res.errCode === 10000) {
// 重新初始化蓝牙适配器
await that.initBluetooth()
}
}
})
}, 1000)
},
2025-02-06 11:37:41 +08:00
async fail(res) {
console.log('开始搜索失败', res)
2025-02-06 11:37:41 +08:00
if (res.errCode === 10000) {
// 重新初始化蓝牙适配器
await that.initBluetooth()
that.searchAndConnectDevice()
2025-02-06 11:37:41 +08:00
} else if (res.errno === 1509008) {
uni.showModal({
title: '提示',
content: '安卓手机蓝牙功能需要定位权限,请前往设置开启微信的定位权限后再试',
showCancel: false,
success(res) {
if (res.confirm) {
uni.openAppAuthorizeSetting({
2025-02-06 11:37:41 +08:00
success(res) {
console.log(res)
}
})
}
}
})
2024-09-04 09:27:18 +08:00
resolve({
2024-10-24 15:44:42 +08:00
code: -23
2024-09-04 09:27:18 +08:00
})
} else {
2024-09-04 09:27:18 +08:00
resolve({
code: -1
})
}
}
})
})
},
// 检查是否已添加为用户
2024-09-02 14:22:19 +08:00
async checkLockUser(flag = false) {
console.log('检查是否已添加为用户', this.currentLockInfo.lockUserNo)
2025-02-06 11:37:41 +08:00
if (this.currentLockInfo.lockUserNo === 0 || flag) {
const timestamp = parseInt(new Date().getTime() / 1000, 10)
const password = (Math.floor(Math.random() * 900000) + 100000).toString()
console.log('用户未添加,开始添加用户')
const addUserParams = {
name: this.currentLockInfo.name,
keyId: this.keyId,
authUid: this.currentLockInfo.senderUserId.toString(),
uid: this.currentLockInfo.uid.toString(),
openMode: 1,
keyType: 0,
2025-02-06 11:37:41 +08:00
startDate:
this.currentLockInfo.startDate === 0
? timestamp
: parseInt(this.currentLockInfo.startDate / 1000, 10),
expireDate:
this.currentLockInfo.endDate === 0
? 0xffffffff
: parseInt(this.currentLockInfo.endDate / 1000, 10),
useCountLimit: this.currentLockInfo.keyType === 3 ? 1 : 0xffff,
isRound: this.currentLockInfo.keyType === 4 ? 1 : 0,
2025-02-06 11:37:41 +08:00
weekRound:
this.currentLockInfo.keyType === 4
? this.convertWeekdaysToNumber(this.currentLockInfo.weekDays)
: 0,
startHour:
this.currentLockInfo.keyType === 4
? new Date(this.currentLockInfo.startDate).getHours()
: 0,
startMin:
this.currentLockInfo.keyType === 4
? new Date(this.currentLockInfo.startDate).getMinutes()
: 0,
endHour:
this.currentLockInfo.keyType === 4
? new Date(this.currentLockInfo.endDate).getHours()
: 0,
endMin:
this.currentLockInfo.keyType === 4
? new Date(this.currentLockInfo.endDate).getMinutes()
: 0,
role: 0,
password
}
const { code: addUserCode } = await this.addLockUser(addUserParams)
console.log('添加用户蓝牙结果', addUserCode, addUserParams)
2025-02-06 11:37:41 +08:00
if (addUserCode === 0) {
const { code } = await updateLockUserNoRequest({
keyId: this.keyId,
lockUserNo: this.currentLockInfo.lockUserNo
})
console.log('添加用户请求结果', code)
return true
2025-02-06 11:37:41 +08:00
}
if (addUserCode === 0x0c) {
console.log('用户达上限,开始清理用户')
const { code: requestCode, data: requestData } = await getUserNoListRequest({
lockId: this.currentLockInfo.lockId
})
console.log('获取用户列表请求结果', requestCode, requestData)
2025-02-06 11:37:41 +08:00
if (requestCode !== 0) return false
const userNoList = requestData.userNos
const { code: cleanCode } = await this.cleanLockUser({
name: this.currentLockInfo.name,
keyId: this.keyId,
authUid: this.currentLockInfo.senderUserId.toString(),
uid: this.currentLockInfo.uid.toString(),
2025-02-06 11:37:41 +08:00
userNoList
})
console.log('清理用户蓝牙结果', cleanCode)
2025-02-06 11:37:41 +08:00
if (cleanCode === 0) {
return await this.checkLockUser()
}
return false
}
2025-02-06 11:37:41 +08:00
return addUserCode === 0x0f
}
2025-02-06 11:37:41 +08:00
return true
},
// 写入特征值
async writeBLECharacteristicValue(binaryData) {
const that = this
console.log('设备ID', that.currentLockInfo.deviceId)
console.log('设备名称:', that.currentLockInfo.name)
console.log('设备主服务:', that.currentLockInfo.serviceId)
console.log('设备写入特征值:', that.currentLockInfo.writeCharacteristicId)
console.log('设备写入数据:', Array.from(binaryData))
// 次数
const count = Math.ceil(binaryData.length / 20)
2025-02-06 11:37:41 +08:00
for (let i = 0; i < count; i++) {
const writeData = binaryData.slice(
i * 20,
i === count - 1 ? binaryData.length : (i + 1) * 20
)
uni.writeBLECharacteristicValue({
deviceId: that.currentLockInfo.deviceId,
serviceId: that.currentLockInfo.serviceId,
characteristicId: that.currentLockInfo.writeCharacteristicId,
value: writeData.buffer,
fail(res) {
console.log('写入失败', res)
}
})
}
},
/*
2025-02-06 11:37:41 +08:00
* 生成包头
* encryptionType 加密类型 0明文1AES1282SM4事先约定密钥3SM4设备指定密钥
* originalLength 原始数据长度
* */
createPackageHeader(encryptionType, originalLength) {
// 头部数据
let headArray = new Uint8Array(12)
// 固定包头
2025-02-06 11:37:41 +08:00
headArray[0] = 0xef
headArray[1] = 0x01
2025-02-06 11:37:41 +08:00
headArray[2] = 0xee
headArray[3] = 0x02
// 包类型 发送
headArray[4] = 0x01
// 包序号
headArray[5] = this.messageCount / 256
headArray[6] = this.messageCount % 256
this.messageCount++
// 包标识
2025-02-06 11:37:41 +08:00
if (encryptionType === 0) {
headArray[7] = 0x20
2025-02-06 11:37:41 +08:00
} else if (encryptionType === 2) {
headArray[7] = 0x22
} else {
headArray[7] = 0x23
}
// 数据长度
2025-02-06 11:37:41 +08:00
if (encryptionType === 0) {
headArray[8] = originalLength / 256
headArray[9] = originalLength % 256
} else {
const length = Math.ceil(originalLength / 16) * 16
headArray[8] = length / 256
headArray[9] = length % 256
}
headArray[10] = originalLength / 256
headArray[11] = originalLength % 256
return headArray
},
// 生成包尾 头部数据+内容数据
2025-02-06 14:59:10 +08:00
createPackageEnd(headArray, contentArray) {
// 拼接头部和内容
2025-02-06 14:59:10 +08:00
let mergerArray = new Uint8Array(headArray.length + contentArray.length)
mergerArray.set(headArray)
2025-02-06 14:59:10 +08:00
mergerArray.set(contentArray, headArray.length)
// crc加密
const crcResult = crc.crc16kermit(mergerArray)
// 拼接crc
let newArray = new Uint8Array(mergerArray.length + 2)
newArray.set(mergerArray)
newArray.set([crcResult / 256, crcResult % 256], mergerArray.length)
return newArray
},
// 获取公钥
async getPublicKey(name) {
// 确认蓝牙状态正常
2025-02-06 11:37:41 +08:00
if (this.bluetoothStatus !== 0) {
console.log('写入未执行', this.bluetoothStatus)
this.getBluetoothStatus()
return {
code: -1
}
}
// 确认设备连接正常
2025-02-06 11:37:41 +08:00
if (!this.currentLockInfo.connected) {
2025-02-06 14:59:10 +08:00
const searchResult = await this.searchAndConnectDevice()
if (searchResult.code !== 0) {
return searchResult
2024-09-04 09:27:18 +08:00
}
this.updateCurrentLockInfo({
...this.currentLockInfo,
2025-02-06 14:59:10 +08:00
deviceId: searchResult.data.deviceId
})
console.log('设备ID', this.currentLockInfo.deviceId)
const result = await this.connectBluetoothDevice()
console.log('连接结果', result)
2025-02-06 11:37:41 +08:00
if (!result) {
return {
code: -1
}
}
}
const headArray = this.createPackageHeader(0, 42)
2025-02-06 14:59:10 +08:00
const contentArray = new Uint8Array(42)
2025-02-06 14:59:10 +08:00
contentArray[0] = cmdIds.getPublicKey / 256
contentArray[1] = cmdIds.getPublicKey % 256
2025-02-06 11:37:41 +08:00
for (let i = 0; i < name.length; i++) {
2025-02-06 14:59:10 +08:00
contentArray[i + 2] = name.charCodeAt(i)
}
2025-02-06 14:59:10 +08:00
const packageArray = this.createPackageEnd(headArray, contentArray)
await this.writeBLECharacteristicValue(packageArray)
return this.getWriteResult()
},
// 获取私钥
async getCommKey(name, keyId, authUid, nowTime) {
// 确认蓝牙状态正常
2025-02-06 11:37:41 +08:00
if (this.bluetoothStatus !== 0) {
console.log('写入未执行', this.bluetoothStatus)
this.getBluetoothStatus()
return {
code: -1
}
}
// 确认设备连接正常
2025-02-06 11:37:41 +08:00
if (!this.currentLockInfo.connected) {
2025-02-06 14:59:10 +08:00
const searchResult = await this.searchAndConnectDevice()
if (searchResult.code !== 0) {
return searchResult
2024-09-04 09:27:18 +08:00
}
this.updateCurrentLockInfo({
...this.currentLockInfo,
2025-02-06 14:59:10 +08:00
deviceId: searchResult.data.deviceId
})
console.log('设备ID', this.currentLockInfo.deviceId)
const result = await this.connectBluetoothDevice()
console.log('连接结果', result)
2025-02-06 11:37:41 +08:00
if (!result) {
return {
code: -1
}
}
}
const length = 2 + 40 + 40 + 20 + 4 + 1 + 16
const headArray = this.createPackageHeader(2, length)
2025-02-06 14:59:10 +08:00
const contentArray = new Uint8Array(length)
2025-02-06 14:59:10 +08:00
contentArray[0] = cmdIds.getCommKey / 256
contentArray[1] = cmdIds.getCommKey % 256
for (let i = 0; i < name.length; i++) {
2025-02-06 14:59:10 +08:00
contentArray[i + 2] = name.charCodeAt(i)
}
2025-02-06 11:37:41 +08:00
for (let i = 0; i < keyId.length; i++) {
2025-02-06 14:59:10 +08:00
contentArray[i + 42] = keyId.charCodeAt(i)
}
2025-02-06 11:37:41 +08:00
for (let i = 0; i < authUid.length; i++) {
2025-02-06 14:59:10 +08:00
contentArray[i + 82] = authUid.charCodeAt(i)
}
2025-02-06 14:59:10 +08:00
contentArray.set(this.timestampToArray(nowTime), 102)
2025-02-06 14:59:10 +08:00
contentArray[106] = 16
2025-02-06 11:37:41 +08:00
const md5Array = this.md5Encrypte(
authUid + keyId,
2025-02-06 14:59:10 +08:00
contentArray.slice(102, 106),
2025-02-06 11:37:41 +08:00
this.currentLockInfo.publicKey
)
2025-02-06 14:59:10 +08:00
contentArray.set(md5Array, 107)
2025-02-06 14:59:10 +08:00
const cebArray = sm4.encrypt(contentArray, contentArray.slice(2, 18), {
2025-02-06 11:37:41 +08:00
mode: 'ecb',
output: 'array'
})
const packageArray = this.createPackageEnd(headArray, cebArray)
await this.writeBLECharacteristicValue(packageArray)
return this.getWriteResult()
},
// md5加密
md5Encrypte(text, token, key) {
const length = text.length + 4 + 16
const md5Array = new Uint8Array(length)
for (let i = 0; i < text.length; i++) {
md5Array[i] = text.charCodeAt(i)
}
2025-02-06 11:37:41 +08:00
md5Array.set(token, text.length)
md5Array.set(key, text.length + 4)
2025-02-06 11:37:41 +08:00
const md5Text = md5(md5Array)
return new Uint8Array(md5Text.match(/.{1,2}/g).map(byte => parseInt(byte, 16)))
},
// 获取锁状态
async getLockStatus(data) {
// 确认蓝牙状态正常
2025-02-06 11:37:41 +08:00
if (this.bluetoothStatus !== 0) {
console.log('写入未执行', this.bluetoothStatus)
this.getBluetoothStatus()
return {
code: -1
}
}
// 确认设备连接正常
2025-02-06 11:37:41 +08:00
if (!this.currentLockInfo.connected) {
2025-02-06 14:59:10 +08:00
const searchResult = await this.searchAndConnectDevice()
if (searchResult.code !== 0) {
return searchResult
2024-09-04 09:27:18 +08:00
}
this.updateCurrentLockInfo({
...this.currentLockInfo,
2025-02-06 14:59:10 +08:00
deviceId: searchResult.data.deviceId
})
console.log('设备ID', this.currentLockInfo.deviceId)
const result = await this.connectBluetoothDevice()
console.log('连接结果', result)
2025-02-06 11:37:41 +08:00
if (!result) {
return {
code: -1
}
}
}
const { name, uid, nowTime, localTime } = data
const length = 2 + 40 + 20 + 4 + 4
const headArray = this.createPackageHeader(3, length)
2025-02-06 14:59:10 +08:00
const contentArray = new Uint8Array(length)
contentArray[0] = cmdIds.getLockStatus / 256
contentArray[1] = cmdIds.getLockStatus % 256
for (let i = 0; i < name.length; i++) {
2025-02-06 14:59:10 +08:00
contentArray[i + 2] = name.charCodeAt(i)
}
for (let i = 0; i < uid.length; i++) {
2025-02-06 14:59:10 +08:00
contentArray[i + 42] = uid.charCodeAt(i)
}
2025-02-06 14:59:10 +08:00
contentArray.set(this.timestampToArray(nowTime), 62)
contentArray.set(this.timestampToArray(localTime), 66)
2025-02-06 14:59:10 +08:00
const cebArray = sm4.encrypt(contentArray, this.currentLockInfo.commKey, {
2025-02-06 11:37:41 +08:00
mode: 'ecb',
output: 'array'
})
const packageArray = this.createPackageEnd(headArray, cebArray)
await this.writeBLECharacteristicValue(packageArray)
return this.getWriteResult(this.getLockStatus, data)
},
// 时间戳转二进制
timestampToArray(timestamp) {
const array = new Uint8Array(4)
array[0] = (timestamp & 0xff000000) >> 24
array[1] = (timestamp & 0xff0000) >> 16
array[2] = (timestamp & 0xff00) >> 8
2025-02-06 11:37:41 +08:00
array[3] = timestamp & 0xff
return array
},
2024-08-24 14:25:05 +08:00
// 二进制转时间戳
arrayToTimestamp(array) {
const timestamp = (array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3]
return timestamp >>> 0
},
// 添加用户
async addLockUser(data) {
// 确认蓝牙状态正常
2025-02-06 11:37:41 +08:00
if (this.bluetoothStatus !== 0) {
console.log('写入未执行', this.bluetoothStatus)
this.getBluetoothStatus()
return {
code: -1
}
}
// 确认设备连接正常
2025-02-06 11:37:41 +08:00
if (!this.currentLockInfo.connected) {
2025-02-06 14:59:10 +08:00
const searchResult = await this.searchAndConnectDevice()
if (searchResult.code !== 0) {
return searchResult
2024-09-04 09:27:18 +08:00
}
this.updateCurrentLockInfo({
...this.currentLockInfo,
2025-02-06 14:59:10 +08:00
deviceId: searchResult.data.deviceId
})
console.log('设备ID', this.currentLockInfo.deviceId)
const result = await this.connectBluetoothDevice()
console.log('连接结果', result)
2025-02-06 11:37:41 +08:00
if (!result) {
return {
code: -1
}
}
}
2025-02-06 11:37:41 +08:00
const {
name,
authUid,
uid,
keyId,
openMode,
keyType,
startDate,
expireDate,
useCountLimit,
isRound,
weekRound,
startHour,
startMin,
endHour,
endMin,
role,
password
} = data
const length =
2 + 40 + 20 + 40 + 20 + 1 + 1 + 4 + 4 + 2 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 20 + 4 + 1 + 16
const headArray = this.createPackageHeader(3, length)
2025-02-06 14:59:10 +08:00
const contentArray = new Uint8Array(length)
2025-02-06 14:59:10 +08:00
contentArray[0] = cmdIds.addUser / 256
contentArray[1] = cmdIds.addUser % 256
2025-02-06 11:37:41 +08:00
for (let i = 0; i < name.length; i++) {
2025-02-06 14:59:10 +08:00
contentArray[i + 2] = name.charCodeAt(i)
}
2025-02-06 11:37:41 +08:00
for (let i = 0; i < authUid.length; i++) {
2025-02-06 14:59:10 +08:00
contentArray[i + 42] = authUid.charCodeAt(i)
}
2025-02-06 11:37:41 +08:00
for (let i = 0; i < keyId.length; i++) {
2025-02-06 14:59:10 +08:00
contentArray[i + 62] = keyId.charCodeAt(i)
}
2025-02-06 11:37:41 +08:00
for (let i = 0; i < uid.length; i++) {
2025-02-06 14:59:10 +08:00
contentArray[i + 102] = uid.charCodeAt(i)
}
2025-02-06 14:59:10 +08:00
contentArray[122] = openMode
contentArray[123] = keyType
2025-02-06 14:59:10 +08:00
contentArray.set(this.timestampToArray(startDate), 124)
contentArray.set(this.timestampToArray(expireDate), 128)
2025-02-06 14:59:10 +08:00
contentArray[132] = useCountLimit / 256
contentArray[133] = useCountLimit % 256
2025-02-06 14:59:10 +08:00
contentArray[134] = isRound
contentArray[135] = weekRound
contentArray[136] = startHour
contentArray[137] = startMin
contentArray[138] = endHour
contentArray[139] = endMin
contentArray[140] = role
2025-02-06 11:37:41 +08:00
for (let i = 0; i < password.length; i++) {
2025-02-06 14:59:10 +08:00
contentArray[i + 141] = password.charCodeAt(i)
}
2025-02-06 14:59:10 +08:00
contentArray.set(this.currentLockInfo.token || this.timestampToArray(startDate), 161)
2025-02-06 14:59:10 +08:00
contentArray[165] = 16
2025-02-06 11:37:41 +08:00
const md5Array = this.md5Encrypte(
authUid + keyId,
this.currentLockInfo.token || this.timestampToArray(startDate),
this.currentLockInfo.publicKey
)
2025-02-06 14:59:10 +08:00
contentArray.set(md5Array, 166)
2025-02-06 14:59:10 +08:00
const cebArray = sm4.encrypt(contentArray, this.currentLockInfo.commKey, {
2025-02-06 11:37:41 +08:00
mode: 'ecb',
output: 'array'
})
const packageArray = this.createPackageEnd(headArray, cebArray)
await this.writeBLECharacteristicValue(packageArray, false)
return this.getWriteResult(this.addLockUser, data)
},
// 获取写入结果
getWriteResult(request, params) {
2024-10-24 15:44:42 +08:00
const $user = useUserStore()
return new Promise(resolve => {
const getWriteResultTimer = setTimeout(() => {
2024-10-24 15:44:42 +08:00
log.info({
code: -1,
message: `操作失败,蓝牙操作超时`,
data: {
lockName: this.currentLockInfo.name,
lockId: this.currentLockInfo.lockId,
uid: $user.userInfo.uid,
nickname: $user.userInfo.nickname,
mobile: $user.userInfo.mobile,
email: $user.userInfo.email
}
})
resolve({ code: -1 })
}, 20000)
2025-02-06 11:37:41 +08:00
characteristicValueCallback = async data => {
// code 6 token过期,重新获取
2025-02-06 11:37:41 +08:00
if (data.code === 6) {
2024-10-24 15:44:42 +08:00
log.info({
code: 0,
message: `开门中更换过期token开始重试`,
data: {
lockName: this.currentLockInfo.name,
lockId: this.currentLockInfo.lockId,
uid: $user.userInfo.uid,
nickname: $user.userInfo.nickname,
mobile: $user.userInfo.mobile,
email: $user.userInfo.email
}
})
clearTimeout(getWriteResultTimer)
resolve(await request(params))
} else {
clearTimeout(getWriteResultTimer)
resolve(data)
}
}
})
},
// 开门
async openDoor(data) {
2024-10-24 15:44:42 +08:00
const $user = useUserStore()
try {
log.info({
code: 0,
message: `开始开门`,
data: {
lockName: this.currentLockInfo.name,
lockId: this.currentLockInfo.lockId,
uid: $user.userInfo.uid,
nickname: $user.userInfo.nickname,
mobile: $user.userInfo.mobile,
email: $user.userInfo.email
}
})
2024-10-24 15:44:42 +08:00
// 确认蓝牙状态正常
2025-02-06 11:37:41 +08:00
if (this.bluetoothStatus !== 0) {
2024-10-24 15:44:42 +08:00
console.log('写入未执行', this.bluetoothStatus)
this.getBluetoothStatus()
2025-02-06 11:37:41 +08:00
if (this.bluetoothStatus === -1) {
2024-10-24 15:44:42 +08:00
log.info({
code: -25,
message: `开门失败,未知蓝牙状态, ${this.bluetoothStatus}`,
data: {
lockName: this.currentLockInfo.name,
lockId: this.currentLockInfo.lockId,
uid: $user.userInfo.uid,
nickname: $user.userInfo.nickname,
mobile: $user.userInfo.mobile,
email: $user.userInfo.email
}
})
2025-02-06 11:37:41 +08:00
} else if (this.bluetoothStatus === 1) {
2024-10-24 15:44:42 +08:00
log.info({
code: -20,
message: `开门失败,蓝牙未开启, ${this.bluetoothStatus}`,
data: {
lockName: this.currentLockInfo.name,
lockId: this.currentLockInfo.lockId,
uid: $user.userInfo.uid,
nickname: $user.userInfo.nickname,
mobile: $user.userInfo.mobile,
email: $user.userInfo.email
}
})
2025-02-06 11:37:41 +08:00
} else if (this.bluetoothStatus === 2) {
2024-10-24 15:44:42 +08:00
log.info({
code: -21,
message: `开门失败,小程序蓝牙权限被禁用, ${this.bluetoothStatus}`,
data: {
lockName: this.currentLockInfo.name,
lockId: this.currentLockInfo.lockId,
uid: $user.userInfo.uid,
nickname: $user.userInfo.nickname,
mobile: $user.userInfo.mobile,
email: $user.userInfo.email
}
})
2025-02-06 11:37:41 +08:00
} else if (this.bluetoothStatus === 3) {
2024-10-24 15:44:42 +08:00
log.info({
code: -26,
message: `开门失败,蓝牙未开启且小程序蓝牙功能被禁用, ${this.bluetoothStatus}`,
data: {
lockName: this.currentLockInfo.name,
lockId: this.currentLockInfo.lockId,
uid: $user.userInfo.uid,
nickname: $user.userInfo.nickname,
mobile: $user.userInfo.mobile,
email: $user.userInfo.email
}
})
}
return {
code: -1
}
}
2024-10-24 15:44:42 +08:00
log.info({
code: 0,
message: `开门中,蓝牙权限正常, ${this.bluetoothStatus}`,
data: {
lockName: this.currentLockInfo.name,
lockId: this.currentLockInfo.lockId,
uid: $user.userInfo.uid,
nickname: $user.userInfo.nickname,
mobile: $user.userInfo.mobile,
email: $user.userInfo.email
}
})
// 确认设备连接正常
2025-02-06 11:37:41 +08:00
if (!this.currentLockInfo.connected) {
2025-02-06 14:59:10 +08:00
const searchResult = await this.searchAndConnectDevice()
if (searchResult.code === 0) {
2024-10-24 15:44:42 +08:00
log.info({
2025-02-06 14:59:10 +08:00
code: searchResult.code,
2024-10-24 15:44:42 +08:00
message: `开门中,已搜索到设备`,
data: {
lockName: this.currentLockInfo.name,
lockId: this.currentLockInfo.lockId,
uid: $user.userInfo.uid,
nickname: $user.userInfo.nickname,
mobile: $user.userInfo.mobile,
email: $user.userInfo.email
}
})
2025-02-06 14:59:10 +08:00
} else if (searchResult.code === -1) {
2024-10-24 15:44:42 +08:00
log.info({
2025-02-06 14:59:10 +08:00
code: searchResult.code,
2024-10-24 15:44:42 +08:00
message: `开门失败,搜索失败`,
data: {
lockName: this.currentLockInfo.name,
lockId: this.currentLockInfo.lockId,
uid: $user.userInfo.uid,
nickname: $user.userInfo.nickname,
mobile: $user.userInfo.mobile,
email: $user.userInfo.email
}
})
2025-02-06 14:59:10 +08:00
} else if (searchResult.code === -2) {
2024-10-24 15:44:42 +08:00
log.info({
2025-02-06 14:59:10 +08:00
code: searchResult.code,
2024-10-24 15:44:42 +08:00
message: `开门失败,锁已被重置`,
data: {
lockName: this.currentLockInfo.name,
lockId: this.currentLockInfo.lockId,
uid: $user.userInfo.uid,
nickname: $user.userInfo.nickname,
mobile: $user.userInfo.mobile,
email: $user.userInfo.email
}
})
2025-02-06 14:59:10 +08:00
} else if (searchResult.code === -3) {
2024-10-24 15:44:42 +08:00
log.info({
2025-02-06 14:59:10 +08:00
code: searchResult.code,
2024-10-24 15:44:42 +08:00
message: `开门失败设备已找到但uuid异常`,
data: {
lockName: this.currentLockInfo.name,
lockId: this.currentLockInfo.lockId,
uid: $user.userInfo.uid,
nickname: $user.userInfo.nickname,
mobile: $user.userInfo.mobile,
email: $user.userInfo.email
}
})
2025-02-06 14:59:10 +08:00
} else if (searchResult.code === -4) {
2024-10-24 15:44:42 +08:00
log.info({
2025-02-06 14:59:10 +08:00
code: searchResult.code,
2024-10-24 15:44:42 +08:00
message: `开门失败,未搜索到操作设备`,
data: {
lockName: this.currentLockInfo.name,
lockId: this.currentLockInfo.lockId,
uid: $user.userInfo.uid,
nickname: $user.userInfo.nickname,
mobile: $user.userInfo.mobile,
email: $user.userInfo.email
}
})
2025-02-06 14:59:10 +08:00
} else if (searchResult.code === -22) {
2024-10-24 15:44:42 +08:00
log.info({
2025-02-06 14:59:10 +08:00
code: searchResult.code,
2024-10-24 15:44:42 +08:00
message: `开门失败,微信附近设备权限未开启`,
data: {
lockName: this.currentLockInfo.name,
lockId: this.currentLockInfo.lockId,
uid: $user.userInfo.uid,
nickname: $user.userInfo.nickname,
mobile: $user.userInfo.mobile,
email: $user.userInfo.email
}
})
2025-02-06 14:59:10 +08:00
} else if (searchResult.code === -23) {
2024-10-24 15:44:42 +08:00
log.info({
2025-02-06 14:59:10 +08:00
code: searchResult.code,
2024-10-24 15:44:42 +08:00
message: `开门失败,微信定位权限未开启`,
data: {
lockName: this.currentLockInfo.name,
lockId: this.currentLockInfo.lockId,
uid: $user.userInfo.uid,
nickname: $user.userInfo.nickname,
mobile: $user.userInfo.mobile,
email: $user.userInfo.email
}
})
}
2025-02-06 14:59:10 +08:00
if (searchResult.code !== 0) {
2024-10-24 15:44:42 +08:00
return { code: -1 }
}
this.updateCurrentLockInfo({
...this.currentLockInfo,
2025-02-06 14:59:10 +08:00
deviceId: searchResult.data.deviceId
2024-10-24 15:44:42 +08:00
})
console.log('设备ID', this.currentLockInfo.deviceId)
const result = await this.connectBluetoothDevice()
2025-02-06 11:37:41 +08:00
if (result) {
2024-10-24 15:44:42 +08:00
log.info({
code: 0,
message: `开门中,设备连接成功`,
data: {
lockName: this.currentLockInfo.name,
lockId: this.currentLockInfo.lockId,
uid: $user.userInfo.uid,
nickname: $user.userInfo.nickname,
mobile: $user.userInfo.mobile,
email: $user.userInfo.email
}
})
} else {
log.info({
code: -1,
message: `开门失败,设备连接失败`,
data: {
lockName: this.currentLockInfo.name,
lockId: this.currentLockInfo.lockId,
uid: $user.userInfo.uid,
nickname: $user.userInfo.nickname,
mobile: $user.userInfo.mobile,
email: $user.userInfo.email
}
})
}
console.log('连接结果', result)
2025-02-06 11:37:41 +08:00
if (!result) {
2024-10-24 15:44:42 +08:00
return {
code: -1
}
}
}
2024-10-24 15:44:42 +08:00
log.info({
code: 0,
message: `开门中,设备已连接`,
data: {
lockName: this.currentLockInfo.name,
lockId: this.currentLockInfo.lockId,
uid: $user.userInfo.uid,
nickname: $user.userInfo.nickname,
mobile: $user.userInfo.mobile,
email: $user.userInfo.email
}
})
2024-10-24 15:44:42 +08:00
// 检查是否已添加为用户
const checkResult = await this.checkLockUser()
if (!checkResult) {
log.info({
code: -1,
message: `开门失败,用户添加失败`,
data: {
lockName: this.currentLockInfo.name,
lockId: this.currentLockInfo.lockId,
uid: $user.userInfo.uid,
nickname: $user.userInfo.nickname,
mobile: $user.userInfo.mobile,
email: $user.userInfo.email
}
})
return {
code: -1
}
}
2024-10-24 15:44:42 +08:00
log.info({
code: 0,
message: `开门中,用户已添加`,
data: {
lockName: this.currentLockInfo.name,
lockId: this.currentLockInfo.lockId,
uid: $user.userInfo.uid,
nickname: $user.userInfo.nickname,
mobile: $user.userInfo.mobile,
email: $user.userInfo.email
}
})
2024-10-24 15:44:42 +08:00
const { name, uid, openMode, openTime, onlineToken } = data
const length = 2 + 40 + 20 + 1 + 4 + 4 + 1 + 16 + 16
const headArray = this.createPackageHeader(3, length)
2025-02-06 14:59:10 +08:00
const contentArray = new Uint8Array(length)
contentArray[0] = cmdIds.openDoor / 256
contentArray[1] = cmdIds.openDoor % 256
2025-02-06 11:37:41 +08:00
for (let i = 0; i < name.length; i++) {
2025-02-06 14:59:10 +08:00
contentArray[i + 2] = name.charCodeAt(i)
2024-10-24 15:44:42 +08:00
}
2024-10-24 15:44:42 +08:00
for (let i = 0; i < uid.length; i++) {
2025-02-06 14:59:10 +08:00
contentArray[i + 42] = uid.charCodeAt(i)
2024-10-24 15:44:42 +08:00
}
2025-02-06 14:59:10 +08:00
contentArray[62] = openMode
2025-02-06 14:59:10 +08:00
contentArray.set(this.timestampToArray(openTime), 63)
2024-10-24 15:44:42 +08:00
console.log('开门时token', this.currentLockInfo.token)
2025-02-06 14:59:10 +08:00
contentArray.set(this.currentLockInfo.token || this.timestampToArray(openTime), 67)
2025-02-06 14:59:10 +08:00
contentArray[71] = 16
2025-02-06 11:37:41 +08:00
const md5Array = this.md5Encrypte(
name + uid,
this.currentLockInfo.token || this.timestampToArray(openTime),
this.currentLockInfo.signKey
)
2025-02-06 14:59:10 +08:00
contentArray.set(md5Array, 72)
2024-10-24 15:44:42 +08:00
for (let i = 0; i < onlineToken.length; i++) {
2025-02-06 14:59:10 +08:00
contentArray[i + 88] = onlineToken.charCodeAt(i)
2024-10-24 15:44:42 +08:00
}
2025-02-06 14:59:10 +08:00
const cebArray = sm4.encrypt(contentArray, this.currentLockInfo.commKey, {
2025-02-06 11:37:41 +08:00
mode: 'ecb',
output: 'array'
})
2024-10-24 15:44:42 +08:00
const packageArray = this.createPackageEnd(headArray, cebArray)
log.info({
code: 0,
message: `开门中,开始写入`,
data: {
lockName: this.currentLockInfo.name,
lockId: this.currentLockInfo.lockId,
uid: $user.userInfo.uid,
nickname: $user.userInfo.nickname,
mobile: $user.userInfo.mobile,
email: $user.userInfo.email
}
})
this.writeBLECharacteristicValue(packageArray)
return this.getWriteResult(this.openDoor, data)
} catch (e) {
log.error({
code: -1,
error: e,
message: `开门失败,未知错误`
})
return {
code: -1
}
}
},
// 清理用户
async cleanLockUser(data) {
// 确认蓝牙状态正常
2025-02-06 11:37:41 +08:00
if (this.bluetoothStatus !== 0) {
console.log('写入未执行', this.bluetoothStatus)
this.getBluetoothStatus()
return {
code: -1
}
}
// 确认设备连接正常
2025-02-06 11:37:41 +08:00
if (!this.currentLockInfo.connected) {
2025-02-06 14:59:10 +08:00
const searchResult = await this.searchAndConnectDevice()
if (searchResult.code !== 0) {
return searchResult
2024-09-04 09:27:18 +08:00
}
this.updateCurrentLockInfo({
...this.currentLockInfo,
2025-02-06 14:59:10 +08:00
deviceId: searchResult.data.deviceId
})
console.log('设备ID', this.currentLockInfo.deviceId)
const result = await this.connectBluetoothDevice()
console.log('连接结果', result)
2025-02-06 11:37:41 +08:00
if (!result) {
return {
code: -1
}
}
}
const { name, authUid, keyId, uid, userNoList } = data
const length = 2 + 40 + 20 + 40 + 20 + 2 + userNoList.length + 4 + 1 + 16
const headArray = this.createPackageHeader(3, length)
2025-02-06 14:59:10 +08:00
const contentArray = new Uint8Array(length)
2025-02-06 14:59:10 +08:00
contentArray[0] = cmdIds.cleanUser / 256
contentArray[1] = cmdIds.cleanUser % 256
for (let i = 0; i < name.length; i++) {
2025-02-06 14:59:10 +08:00
contentArray[i + 2] = name.charCodeAt(i)
}
for (let i = 0; i < authUid.length; i++) {
2025-02-06 14:59:10 +08:00
contentArray[i + 42] = authUid.charCodeAt(i)
}
for (let i = 0; i < keyId.length; i++) {
2025-02-06 14:59:10 +08:00
contentArray[i + 62] = keyId.charCodeAt(i)
}
for (let i = 0; i < uid.length; i++) {
2025-02-06 14:59:10 +08:00
contentArray[i + 102] = uid.charCodeAt(i)
}
2025-02-06 14:59:10 +08:00
contentArray[122] = userNoList.length / 256
contentArray[123] = userNoList.length % 256
for (let i = 0; i < userNoList.length; i++) {
2025-02-06 14:59:10 +08:00
contentArray[i + 124] = userNoList[i]
}
2025-02-06 14:59:10 +08:00
contentArray.set(
2025-02-06 11:37:41 +08:00
this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]),
124 + userNoList.length
)
2025-02-06 14:59:10 +08:00
contentArray[128 + userNoList.length] = 16
2025-02-06 11:37:41 +08:00
const md5Array = this.md5Encrypte(
authUid + keyId,
this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]),
this.currentLockInfo.publicKey
)
2025-02-06 14:59:10 +08:00
contentArray.set(md5Array, 129 + userNoList.length)
2025-02-06 14:59:10 +08:00
const cebArray = sm4.encrypt(contentArray, this.currentLockInfo.commKey, {
2025-02-06 11:37:41 +08:00
mode: 'ecb',
output: 'array'
})
const packageArray = this.createPackageEnd(headArray, cebArray)
await this.writeBLECharacteristicValue(packageArray)
return this.getWriteResult(this.cleanLockUser, data)
},
// 恢复出厂设置
async resetDevice(data) {
// 确认蓝牙状态正常
2025-02-06 11:37:41 +08:00
if (this.bluetoothStatus !== 0) {
console.log('写入未执行', this.bluetoothStatus)
this.getBluetoothStatus()
return {
code: -1
}
}
// 确认设备连接正常
2025-02-06 11:37:41 +08:00
if (!this.currentLockInfo.connected) {
2025-02-06 14:59:10 +08:00
const searchResult = await this.searchAndConnectDevice()
if (searchResult.code !== 0) {
return searchResult
2024-09-04 09:27:18 +08:00
}
this.updateCurrentLockInfo({
...this.currentLockInfo,
2025-02-06 14:59:10 +08:00
deviceId: searchResult.data.deviceId
})
console.log('设备ID', this.currentLockInfo.deviceId)
const result = await this.connectBluetoothDevice()
console.log('连接结果', result)
2025-02-06 11:37:41 +08:00
if (!result) {
return {
code: -1
}
}
}
// 检查是否已添加为用户
const checkResult = await this.checkLockUser()
if (!checkResult) {
return {
code: -1
}
}
2025-02-06 11:37:41 +08:00
const { name, authUid } = data
const length = 2 + 40 + 20 + 4 + 1 + 16
const headArray = this.createPackageHeader(3, length)
2025-02-06 14:59:10 +08:00
const contentArray = new Uint8Array(length)
2025-02-06 14:59:10 +08:00
contentArray[0] = cmdIds.resetDevice / 256
contentArray[1] = cmdIds.resetDevice % 256
2025-02-06 11:37:41 +08:00
for (let i = 0; i < name.length; i++) {
2025-02-06 14:59:10 +08:00
contentArray[i + 2] = name.charCodeAt(i)
}
2025-02-06 11:37:41 +08:00
for (let i = 0; i < authUid.length; i++) {
2025-02-06 14:59:10 +08:00
contentArray[i + 42] = authUid.charCodeAt(i)
}
2025-02-06 14:59:10 +08:00
contentArray.set(this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), 62)
contentArray[66] = 16
2025-02-06 11:37:41 +08:00
const md5Array = this.md5Encrypte(
name,
this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]),
this.currentLockInfo.publicKey
)
2025-02-06 14:59:10 +08:00
contentArray.set(md5Array, 67)
2025-02-06 14:59:10 +08:00
const cebArray = sm4.encrypt(contentArray, this.currentLockInfo.commKey, {
2025-02-06 11:37:41 +08:00
mode: 'ecb',
output: 'array'
})
const packageArray = this.createPackageEnd(headArray, cebArray)
await this.writeBLECharacteristicValue(packageArray)
return this.getWriteResult(this.resetDevice, data)
},
// 重置开锁密码
async resetLockPassword(data) {
// 确认蓝牙状态正常
2025-02-06 11:37:41 +08:00
if (this.bluetoothStatus !== 0) {
console.log('写入未执行', this.bluetoothStatus)
this.getBluetoothStatus()
return {
code: -1
}
}
// 确认设备连接正常
2025-02-06 11:37:41 +08:00
if (!this.currentLockInfo.connected) {
2025-02-06 14:59:10 +08:00
const searchResult = await this.searchAndConnectDevice()
if (searchResult.code !== 0) {
return searchResult
2024-09-04 09:27:18 +08:00
}
this.updateCurrentLockInfo({
...this.currentLockInfo,
2025-02-06 14:59:10 +08:00
deviceId: searchResult.data.deviceId
})
console.log('设备ID', this.currentLockInfo.deviceId)
const result = await this.connectBluetoothDevice()
console.log('连接结果', result)
2025-02-06 11:37:41 +08:00
if (!result) {
return {
code: -1
}
}
}
// 检查是否已添加为用户
const checkResult = await this.checkLockUser()
if (!checkResult) {
return {
code: -1
}
}
const { keyId, uid } = data
const length = 2 + 1 + 1 + 40 + 20 + 4 + 1 + 16
const headArray = this.createPackageHeader(3, length)
2025-02-06 14:59:10 +08:00
const contentArray = new Uint8Array(length)
2025-02-06 14:59:10 +08:00
contentArray[0] = cmdIds.expandCmd / 256
contentArray[1] = cmdIds.expandCmd % 256
// 子命令
2025-02-06 14:59:10 +08:00
contentArray[2] = subCmdIds.resetLockPassword
2025-02-06 14:59:10 +08:00
contentArray[3] = length - 4
for (let i = 0; i < keyId.length; i++) {
2025-02-06 14:59:10 +08:00
contentArray[i + 4] = keyId.charCodeAt(i)
}
for (let i = 0; i < uid.length; i++) {
2025-02-06 14:59:10 +08:00
contentArray[i + 44] = uid.charCodeAt(i)
}
2025-02-06 14:59:10 +08:00
contentArray.set(this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), 64)
2025-02-06 14:59:10 +08:00
contentArray[68] = 16
2025-02-06 11:37:41 +08:00
const md5Array = this.md5Encrypte(
keyId + uid,
this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]),
this.currentLockInfo.signKey
)
2025-02-06 14:59:10 +08:00
contentArray.set(md5Array, 69)
2025-02-06 14:59:10 +08:00
const cebArray = sm4.encrypt(contentArray, this.currentLockInfo.commKey, {
2025-02-06 11:37:41 +08:00
mode: 'ecb',
output: 'array'
})
const packageArray = this.createPackageEnd(headArray, cebArray)
await this.writeBLECharacteristicValue(packageArray)
return this.getWriteResult(this.resetLockPassword, data)
},
// 设置密码
async setLockPassword(data) {
// 确认蓝牙状态正常
2025-02-06 11:37:41 +08:00
if (this.bluetoothStatus !== 0) {
console.log('写入未执行', this.bluetoothStatus)
this.getBluetoothStatus()
return {
code: -1
}
}
// 确认设备连接正常
2025-02-06 11:37:41 +08:00
if (!this.currentLockInfo.connected) {
2025-02-06 14:59:10 +08:00
const searchResult = await this.searchAndConnectDevice()
if (searchResult.code !== 0) {
return searchResult
2024-09-04 09:27:18 +08:00
}
this.updateCurrentLockInfo({
...this.currentLockInfo,
2025-02-06 14:59:10 +08:00
deviceId: searchResult.data.deviceId
})
console.log('设备ID', this.currentLockInfo.deviceId)
const result = await this.connectBluetoothDevice()
console.log('连接结果', result)
2025-02-06 11:37:41 +08:00
if (!result) {
return {
code: -1
}
}
}
// 检查是否已添加为用户
const checkResult = await this.checkLockUser()
if (!checkResult) {
return {
code: -1
}
}
2025-02-06 11:37:41 +08:00
const { keyId, uid, pwdNo, operate, isAdmin, pwd, userCountLimit, startTime, endTime } = data
const length = 2 + 1 + 1 + 40 + 20 + 2 + 1 + 1 + 20 + 2 + 4 + 4 + 4 + 1 + 16
const headArray = this.createPackageHeader(3, length)
2025-02-06 14:59:10 +08:00
const contentArray = new Uint8Array(length)
2025-02-06 14:59:10 +08:00
contentArray[0] = cmdIds.expandCmd / 256
contentArray[1] = cmdIds.expandCmd % 256
// 子命令
2025-02-06 14:59:10 +08:00
contentArray[2] = subCmdIds.setLockPassword
2025-02-06 14:59:10 +08:00
contentArray[3] = length - 3
for (let i = 0; i < keyId.length; i++) {
2025-02-06 14:59:10 +08:00
contentArray[i + 4] = keyId.charCodeAt(i)
}
for (let i = 0; i < uid.length; i++) {
2025-02-06 14:59:10 +08:00
contentArray[i + 44] = uid.charCodeAt(i)
}
2025-02-06 14:59:10 +08:00
contentArray[64] = pwdNo / 256
contentArray[65] = pwdNo % 256
2025-02-06 14:59:10 +08:00
contentArray[66] = operate
contentArray[67] = isAdmin
for (let i = 0; i < pwd.length; i++) {
2025-02-06 14:59:10 +08:00
contentArray[i + 68] = pwd.charCodeAt(i)
}
2025-02-06 14:59:10 +08:00
contentArray[88] = userCountLimit / 256
contentArray[89] = userCountLimit % 256
2025-02-06 14:59:10 +08:00
contentArray.set(this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), 90)
2025-02-06 14:59:10 +08:00
contentArray.set(this.timestampToArray(startTime), 94)
contentArray.set(this.timestampToArray(endTime), 98)
2025-02-06 14:59:10 +08:00
contentArray[102] = 16
2025-02-06 11:37:41 +08:00
const md5Array = this.md5Encrypte(
keyId + uid,
this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]),
this.currentLockInfo.signKey
)
2025-02-06 14:59:10 +08:00
contentArray.set(md5Array, 103)
2025-02-06 14:59:10 +08:00
const cebArray = sm4.encrypt(contentArray, this.currentLockInfo.commKey, {
2025-02-06 11:37:41 +08:00
mode: 'ecb',
output: 'array'
})
const packageArray = this.createPackageEnd(headArray, cebArray)
await this.writeBLECharacteristicValue(packageArray)
return this.getWriteResult(this.setLockPassword, data)
2025-02-08 18:31:14 +08:00
},
parseTimeToList(timeString) {
let timeList = [0, 0, 0, 0]
if (timeString.includes(':')) {
let timeParts = timeString.split(':')
timeList[2] = parseInt(timeParts[0], 10)
timeList[3] = parseInt(timeParts[1], 10)
}
return new Uint8Array(timeList)
},
// 注册卡片
async registerCard(data) {
// 确认蓝牙状态正常
if (this.bluetoothStatus !== 0) {
console.log('写入未执行', this.bluetoothStatus)
this.getBluetoothStatus()
return {
code: -1
}
}
// 确认设备连接正常
if (!this.currentLockInfo.connected) {
const searchResult = await this.searchAndConnectDevice()
if (searchResult.code !== 0) {
return searchResult
}
this.updateCurrentLockInfo({
...this.currentLockInfo,
deviceId: searchResult.data.deviceId
})
console.log('设备ID', this.currentLockInfo.deviceId)
const result = await this.connectBluetoothDevice()
console.log('连接结果', result)
if (!result) {
return {
code: -1
}
}
}
// 检查是否已添加为用户
const checkResult = await this.checkLockUser()
if (!checkResult) {
return {
code: -1
}
}
const {
keyId,
uid,
cardNo,
operate,
isAdmin,
userCountLimit,
isForce,
isRound,
weekDays,
startDate,
endDate,
startTime,
endTime
} = data
const length = 2 + 1 + 1 + 40 + 20 + 2 + 2 + 1 + 1 + 1 + 4 + 1 + 1 + 4 + 4 + 4 + 4 + 1 + 16
const headArray = this.createPackageHeader(3, length)
const contentArray = new Uint8Array(length)
contentArray[0] = cmdIds.expandCmd / 256
contentArray[1] = cmdIds.expandCmd % 256
// 子命令
contentArray[2] = subCmdIds.registerCard
contentArray[3] = length - 3
for (let i = 0; i < keyId.length; i++) {
contentArray[i + 4] = keyId.charCodeAt(i)
}
for (let i = 0; i < uid.length; i++) {
contentArray[i + 44] = uid.charCodeAt(i)
}
contentArray[64] = (cardNo || 0) / 256
contentArray[65] = (cardNo || 0) % 256
contentArray[66] = (userCountLimit || 0xffff) / 256
contentArray[67] = (userCountLimit || 0xffff) % 256
contentArray[68] = operate
contentArray[69] = isAdmin || 0
contentArray[70] = isForce || 0
contentArray.set(this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), 71)
contentArray[75] = isRound
contentArray[76] = this.convertWeekdaysToNumber(weekDays)
contentArray.set(this.timestampToArray(startDate), 77)
contentArray.set(this.timestampToArray(endDate), 81)
if (isRound) {
contentArray.set(this.parseTimeToList(startTime), 85)
contentArray.set(this.parseTimeToList(endTime), 89)
} else {
contentArray.set(new Uint8Array([0, 0, 0, 0]), 85)
contentArray.set(new Uint8Array([0, 0, 0, 0]), 89)
}
contentArray[93] = 16
const md5Array = this.md5Encrypte(
keyId + uid,
this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]),
this.currentLockInfo.signKey
)
contentArray.set(md5Array, 94)
const cebArray = sm4.encrypt(contentArray, this.currentLockInfo.commKey, {
mode: 'ecb',
output: 'array'
})
const packageArray = this.createPackageEnd(headArray, cebArray)
await this.writeBLECharacteristicValue(packageArray)
return this.getWriteResult(this.registerCard, data)
},
async registerCardCancel(data) {
const { keyId, uid } = data
const length = 2 + 1 + 1 + 40 + 20 + 4 + 1 + 16
const headArray = this.createPackageHeader(3, length)
const contentArray = new Uint8Array(length)
contentArray[0] = cmdIds.expandCmd / 256
contentArray[1] = cmdIds.expandCmd % 256
// 子命令
contentArray[2] = subCmdIds.registerCardCancel
contentArray[3] = length - 3
for (let i = 0; i < keyId.length; i++) {
contentArray[i + 4] = keyId.charCodeAt(i)
}
for (let i = 0; i < uid.length; i++) {
contentArray[i + 44] = uid.charCodeAt(i)
}
contentArray.set(this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), 64)
contentArray[68] = 16
const md5Array = this.md5Encrypte(
keyId + uid,
this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]),
this.currentLockInfo.signKey
)
contentArray.set(md5Array, 69)
const cebArray = sm4.encrypt(contentArray, this.currentLockInfo.commKey, {
mode: 'ecb',
output: 'array'
})
const packageArray = this.createPackageEnd(headArray, cebArray)
await this.writeBLECharacteristicValue(packageArray)
return this.getWriteResult(this.registerCardCancel, data)
}
}
})