1016 lines
33 KiB
JavaScript
Raw Normal View History

2024-10-12 14:35:58 +08:00
import { defineStore } from 'pinia'
2024-10-21 09:58:17 +08:00
import { sm4 } from 'sm-crypto'
2024-10-12 14:35:58 +08:00
import { buildNumber, configs, version } from '@/starCloud/env'
import {
addCustomPassword,
getLockDetail,
getLockNetTokenRequest,
getOfflinePassword,
getServerDatetime,
getStarCloudToken,
getUserNoListRequest,
starCloudCreateUser,
2024-10-21 09:58:17 +08:00
updateLockUserNoRequest,
updatePassword
2024-10-12 14:35:58 +08:00
} from '@/starCloud/api'
import { getStorage, setStorage } from '@/starCloud/storage'
import {
closeBLEConnection,
onBLECharacteristicValueChange,
Result,
searchAndConnectDevice,
writeBLECharacteristicValue
} from '@/starCloud/basic'
import {
arrayToTimestamp,
convertWeekdaysToNumber,
createPackageEnd,
md5Encrypt,
timestampToArray,
uint8ArrayToString
} from '@/starCloud/format'
/**
* 锁信息
* @typedef {Object} lockInfo
* @property {Number} keyId - 钥匙ID
* @property {Number} lockId - 锁ID
* @property {String} lockName - 锁名称
* @property {String} lockAlias - 锁别名
* @property {Number} electricQuantity - 电量
* @property {Number} electricQuantityStandby - 备用电量
* @property {Number} electricQuantityDate - 电量更新时间
* @property {String} fwVersion - 固件版本
* @property {String} hwVersion - 硬件版本
* @property {Number} keyType - 钥匙类型
* @property {Number} passageMode - 常开模式
* @property {Number} userType - 用户类型
* @property {Number} startDate - 有效期开始时间
* @property {Number} endDate - 有效期结束时间
* @property {Object} weekDays - 循环周期
* @property {Number} remoteEnable - 是否支持远程开锁0-未知1-2-
* @property {Number} faceAuthentication - 是否实名认证0-未知1-2-
* @property {Number} lastFaceValidateTime - 最后一次人脸验证时间
* @property {Number} nextFaceValidateTime - 下次人脸验证时间
* @property {Number} keyRight - 是否授权管理员钥匙: 0-未知1-2-
* @property {Number} keyStatus - 钥匙状态
* @property {Object} bluetooth - 蓝牙
* @property {Number} sendDate - 发送时间
* @property {Number} isLockOwner - 是否是锁主
* @property {Object} lockFeature - 锁特征
* @property {Object} lockSetting - 锁设置
* @property {Number} lockUserNo - 用户编号
* @property {Number} senderUserId - 发送者用户ID
* @property {Number} isOnlyManageSelf - 如果是授权管理员此字段区分是否仅管理自己发的钥匙
* @property {Number} restoreCount - 重置次数
* @property {String} model - 模式
*/
/**
* 锁蓝牙信息
* @typedef {Object} bluetooth
* @property {String} bluetoothDeviceId - 设备ID
* @property {String} bluetoothDeviceName - 设备名称
* @property {String} publicKey - 公钥
* @property {String} privateKey - 私钥
* @property {String} signKey - 签名密钥
* @property {String} passwordKey - 密码密钥
*/
/**
* 锁设置信息
* @typedef {Object} lockSetting
* @property {Number} appUnlockOnline - 开门是否需要联网
*/
/**
* 请求返回数据
* @typedef {Object} requestData
* @property {String} userNos - 设备ID
*/
// 命令ID
const cmdIds = {
// 获取公钥
getPublicKey: 0x3090,
// 获取私钥
getCommKey: 0x3091,
// 获取锁状态
getLockStatus: 0x3040,
// 新增用户
addUser: 0x3001,
// 开门
openDoor: 0x3005,
// 重置设备
resetDevice: 0x3004,
// 清理用户
2024-10-21 09:58:17 +08:00
cleanUser: 0x300c,
2024-10-12 14:35:58 +08:00
// 扩展命令
expandCmd: 0x3030
}
// 子命令ID
const subCmdIds = {
// 设置开锁密码
setLockPassword: 3,
// 重置开锁密码
resetLockPassword: 19
}
// 特性值回调
let characteristicValueCallback = null
// 完整数据
let completeArray
// 完整内容数据长度
let length
// 请求参数
let requestParams = null
export const useStarCloudStore = defineStore('starCloud', {
state() {
return {
// 环境
env: null,
// 客户端Id
clientId: null,
// 客户端密码
clientSecret: null,
// 星云是否登录
loginStarCloud: false,
// 星云用户信息
userInfo: null,
// 账户信息
accountInfo: null,
// 锁信息
lockInfo: null,
// 消息序号
messageCount: 1,
// 服务器时间
serverTimestamp: 0,
// 时间差
timeDifference: 0,
// 小程序环境
envVersion: ''
}
},
actions: {
// 初始化星云
initStarCloud(clientId, clientSecret, env = 'XHJ') {
const appInfo = uni.getAccountInfoSync()
this.envVersion = appInfo.miniProgram.envVersion
this.env = env
this.clientId = clientId
this.clientSecret = clientSecret
// 监听特性值变化
onBLECharacteristicValueChange(this.listenCharacteristicValue)
},
// 注册星云
async register() {
2024-10-21 09:58:17 +08:00
const { code, data, message } = await starCloudCreateUser({
2024-10-12 14:35:58 +08:00
clientId: this.clientId,
clientSecret: this.clientSecret
})
return new Result(code, data, message)
},
// 登录星云
async login(username, password) {
this.accountInfo = {
username,
password
}
const token = getStorage('starCloudToken')
if (token) {
this.userInfo = getStorage('starCloudUser')
this.loginStarCloud = true
// 获取服务器时间
2024-10-21 09:58:17 +08:00
this.getServerTimestamp().then(() => {})
2024-10-12 14:35:58 +08:00
return Result.Success
}
console.log('登录星云', username, password)
const {
code,
data: userInfo,
message
} = await getStarCloudToken({
2024-10-21 09:58:17 +08:00
username,
password,
2024-10-12 14:35:58 +08:00
clientId: this.clientId,
clientSecret: this.clientSecret
})
if (code === Result.Success.code) {
this.userInfo = userInfo
setStorage('starCloudToken', userInfo.access_token)
setStorage('starCloudUser', userInfo)
this.loginStarCloud = true
// 获取服务器时间
2024-10-21 09:58:17 +08:00
this.getServerTimestamp().then(() => {})
2024-10-12 14:35:58 +08:00
}
return new Result(code, {}, message)
},
// 选择锁
async selectLock(lockId) {
2024-10-21 09:58:17 +08:00
const { code, data, message } = await getLockDetail({
2024-10-12 14:35:58 +08:00
lockId
})
if (code === Result.Success.code) {
const lockList = getStorage('lockList')
2024-10-21 09:58:17 +08:00
if (lockList) {
2024-10-12 14:35:58 +08:00
const index = lockList.findIndex(item => item.lockId === lockId)
if (index === -1) {
lockList.push(data)
} else {
lockList[index] = data
}
setStorage('lockList', lockList)
} else {
setStorage('lockList', [data])
}
this.lockInfo = data
} else {
const lockList = getStorage('lockList')
console.log('锁列表', lockList)
2024-10-21 09:58:17 +08:00
if (lockList) {
2024-10-12 14:35:58 +08:00
const index = lockList.findIndex(item => item.lockId === lockId)
if (index !== -1) {
this.lockInfo = lockList[index]
return new Result(Result.Success.code, this.lockInfo)
}
}
}
return new Result(code, data, message)
},
// 清理用户
async cleanLockUser(disconnect = false) {
// 确认设备连接正常
const searchResult = await searchAndConnectDevice(this.lockInfo.bluetooth.bluetoothDeviceName)
if (searchResult.code !== Result.Success.code) {
return searchResult
}
this.updateLockInfo(searchResult.data)
// 获取并处理锁信息
2024-10-21 09:58:17 +08:00
let { uid: authUid, keyId, token, bluetooth } = this.lockInfo
2024-10-12 14:35:58 +08:00
let { uid } = this.userInfo
authUid = authUid.toString()
uid = uid.toString()
keyId = keyId.toString()
const name = bluetooth.bluetoothDeviceName
// 获取用户列表
2024-10-21 09:58:17 +08:00
const { code: requestCode, data: requestData } = await getUserNoListRequest({
2024-10-12 14:35:58 +08:00
lockId: this.lockInfo.lockId
})
console.log('获取用户列表请求结果', requestCode, requestData)
if (requestCode !== 0) return Result.Fail
const userNoList = requestData.userNos
// 组装发送数据
const length = 2 + 40 + 20 + 40 + 20 + 2 + userNoList.length + 4 + 1 + 16
const headArray = this.createPackageHeader(3, length)
const contentArray = new Uint8Array(length)
contentArray[0] = cmdIds.cleanUser / 256
contentArray[1] = cmdIds.cleanUser % 256
for (let i = 0; i < name.length; i++) {
contentArray[i + 2] = name.charCodeAt(i)
}
for (let i = 0; i < authUid.length; i++) {
contentArray[i + 42] = authUid.charCodeAt(i)
}
for (let i = 0; i < keyId.length; i++) {
contentArray[i + 62] = keyId.charCodeAt(i)
}
for (let i = 0; i < uid.length; i++) {
contentArray[i + 102] = uid.charCodeAt(i)
}
contentArray[122] = userNoList.length / 256
contentArray[123] = userNoList.length % 256
for (let i = 0; i < userNoList.length; i++) {
contentArray[i + 124] = userNoList[i]
}
contentArray.set(token || new Uint8Array([0, 0, 0, 0]), 124 + userNoList.length)
contentArray[128 + userNoList.length] = 16
2024-10-21 09:58:17 +08:00
const md5Array = md5Encrypt(
authUid + keyId,
token || new Uint8Array([0, 0, 0, 0]),
bluetooth.publicKey
)
2024-10-12 14:35:58 +08:00
contentArray.set(md5Array, 129 + userNoList.length)
const cebArray = sm4.encrypt(contentArray, bluetooth.privateKey, {
mode: 'ecb',
output: 'array'
})
const packageArray = createPackageEnd(headArray, cebArray)
2024-10-21 09:58:17 +08:00
const writeResult = await writeBLECharacteristicValue(
this.lockInfo.deviceId,
this.lockInfo.serviceId,
this.lockInfo.writeCharacteristicId,
packageArray
)
2024-10-12 14:35:58 +08:00
if (writeResult.code !== Result.Success.code) {
return writeResult
}
return this.getWriteResult(this.cleanLockUser, disconnect)
},
// 开门
2024-10-21 09:58:17 +08:00
// eslint-disable-next-line default-param-last
2024-10-12 14:35:58 +08:00
async openDoor(type = 'open', disconnect) {
// 确认设备连接正常
const searchResult = await searchAndConnectDevice(this.lockInfo.bluetooth.bluetoothDeviceName)
if (searchResult.code !== Result.Success.code) {
return searchResult
}
this.updateLockInfo(searchResult.data)
// 检查是否已添加为用户
const checkResult = await this.checkLockUser()
if (checkResult.code !== Result.Success.code) {
return checkResult
}
// 是否需要联网
let onlineToken = ''
if (this.lockInfo.lockSetting.appUnlockOnline) {
const result = await this.getNetToken()
if (result.code === Result.Success.code) {
onlineToken = result.data.token
} else {
return result
}
}
// 开门方式
let openMode
if (type === 'close') {
openMode = this.lockInfo.lockSetting.appUnlockOnline ? 33 : 32
} else {
openMode = this.lockInfo.lockSetting.appUnlockOnline ? 1 : 0
}
const name = this.lockInfo.bluetooth.bluetoothDeviceName
const uid = this.userInfo.uid.toString()
2024-10-21 09:58:17 +08:00
const openTime = Math.ceil(new Date().getTime() / 1000) + this.timeDifference
2024-10-12 14:35:58 +08:00
const length = 2 + 40 + 20 + 1 + 4 + 4 + 1 + 16 + 16
const headArray = this.createPackageHeader(3, length)
const contentArray = new Uint8Array(length)
contentArray[0] = cmdIds.openDoor / 256
contentArray[1] = cmdIds.openDoor % 256
for (let i = 0; i < name.length; i++) {
contentArray[i + 2] = name.charCodeAt(i)
}
for (let i = 0; i < uid.length; i++) {
contentArray[i + 42] = uid.charCodeAt(i)
}
contentArray[62] = openMode
contentArray.set(timestampToArray(openTime), 63)
console.log('开门时token', this.lockInfo.token)
contentArray.set(this.lockInfo.token || timestampToArray(openTime), 67)
contentArray[71] = 16
2024-10-21 09:58:17 +08:00
const md5Array = md5Encrypt(
name + uid,
this.lockInfo.token || timestampToArray(openTime),
this.lockInfo.bluetooth.signKey
)
2024-10-12 14:35:58 +08:00
contentArray.set(md5Array, 72)
for (let i = 0; i < onlineToken.length; i++) {
contentArray[i + 88] = onlineToken.charCodeAt(i)
}
const cebArray = sm4.encrypt(contentArray, this.lockInfo.bluetooth.privateKey, {
mode: 'ecb',
output: 'array'
})
const packageArray = createPackageEnd(headArray, cebArray)
2024-10-21 09:58:17 +08:00
const writeResult = await writeBLECharacteristicValue(
this.lockInfo.deviceId,
this.lockInfo.serviceId,
this.lockInfo.writeCharacteristicId,
packageArray
)
2024-10-12 14:35:58 +08:00
if (writeResult.code !== Result.Success.code) {
return writeResult
}
return this.getWriteResult(this.openDoor, disconnect)
},
// 获取离线密码
async getOfflinePassword(password) {
return await getOfflinePassword({
...password,
lockId: this.lockInfo.lockId
})
},
// 自定义密码
async customPassword(password, disconnect) {
// 确认设备连接正常
const searchResult = await searchAndConnectDevice(this.lockInfo.bluetooth.bluetoothDeviceName)
if (searchResult.code !== Result.Success.code) {
return searchResult
}
this.updateLockInfo(searchResult.data)
// 检查是否已添加为用户
const checkResult = await this.checkLockUser()
if (checkResult.code !== Result.Success.code) {
return checkResult
}
requestParams = password
let { pwdNo, operate, keyboardPwd, startDate, endDate, pwdRight } = password
const uid = this.userInfo.uid.toString()
const keyId = this.lockInfo.keyId.toString()
const isAdmin = pwdRight
2024-10-21 09:58:17 +08:00
const userCountLimit = 0xffff
2024-10-12 14:35:58 +08:00
startDate = Math.floor(startDate / 1000)
endDate = Math.floor(endDate / 1000)
keyboardPwd = keyboardPwd.toString()
2024-10-21 09:58:17 +08:00
if (!pwdNo) {
2024-10-12 14:35:58 +08:00
pwdNo = 0
}
const length = 2 + 1 + 1 + 40 + 20 + 2 + 1 + 1 + 20 + 2 + 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.setLockPassword
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] = pwdNo / 256
contentArray[65] = pwdNo % 256
contentArray[66] = operate
contentArray[67] = isAdmin
for (let i = 0; i < keyboardPwd.length; i++) {
contentArray[i + 68] = keyboardPwd.charCodeAt(i)
}
contentArray[88] = userCountLimit / 256
contentArray[89] = userCountLimit % 256
contentArray.set(this.lockInfo.token || new Uint8Array([0, 0, 0, 0]), 90)
contentArray.set(timestampToArray(startDate), 94)
contentArray.set(timestampToArray(endDate), 98)
contentArray[102] = 16
2024-10-21 09:58:17 +08:00
const md5Array = md5Encrypt(
keyId + uid,
this.lockInfo.token || new Uint8Array([0, 0, 0, 0]),
this.lockInfo.bluetooth.signKey
)
2024-10-12 14:35:58 +08:00
contentArray.set(md5Array, 103)
const cebArray = sm4.encrypt(contentArray, this.lockInfo.bluetooth.privateKey, {
mode: 'ecb',
output: 'array'
})
const packageArray = createPackageEnd(headArray, cebArray)
2024-10-21 09:58:17 +08:00
const writeResult = await writeBLECharacteristicValue(
this.lockInfo.deviceId,
this.lockInfo.serviceId,
this.lockInfo.writeCharacteristicId,
packageArray
)
2024-10-12 14:35:58 +08:00
if (writeResult.code !== Result.Success.code) {
return writeResult
}
return this.getWriteResult(this.customPassword, disconnect, password)
},
// 获取联网token
async getNetToken() {
2024-10-21 09:58:17 +08:00
const { code, data, message } = await getLockNetTokenRequest({
2024-10-12 14:35:58 +08:00
lockId: this.lockInfo.lockId
})
return new Result(code, data, message)
},
// 获取服务器时间
async getServerTimestamp() {
2024-10-21 09:58:17 +08:00
const { code, data, message } = await getServerDatetime({})
2024-10-12 14:35:58 +08:00
if (code === Result.Success.code) {
this.serverTimestamp = Math.ceil(data.date / 1000)
2024-10-21 09:58:17 +08:00
this.timeDifference = Math.ceil((data.date - new Date().getTime()) / 1000)
2024-10-12 14:35:58 +08:00
}
return new Result(code, data, message)
},
// 添加用户
async addLockUser(data, disconnect = false) {
// 确认设备连接正常
const searchResult = await searchAndConnectDevice(this.lockInfo.bluetooth.bluetoothDeviceName)
if (searchResult.code !== Result.Success.code) {
return searchResult
}
this.updateLockInfo(searchResult.data)
const {
name,
authUid,
uid,
keyId,
openMode,
keyType,
startDate,
expireDate,
useCountLimit,
isRound,
weekRound,
startHour,
startMin,
endHour,
endMin,
role,
password
} = data
2024-10-21 09:58:17 +08:00
const length =
2 + 40 + 20 + 40 + 20 + 1 + 1 + 4 + 4 + 2 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 20 + 4 + 1 + 16
2024-10-12 14:35:58 +08:00
const headArray = this.createPackageHeader(3, length)
const contentArray = new Uint8Array(length)
contentArray[0] = cmdIds.addUser / 256
contentArray[1] = cmdIds.addUser % 256
for (let i = 0; i < name.length; i++) {
contentArray[i + 2] = name.charCodeAt(i)
}
for (let i = 0; i < authUid.length; i++) {
contentArray[i + 42] = authUid.charCodeAt(i)
}
for (let i = 0; i < keyId.length; i++) {
contentArray[i + 62] = keyId.charCodeAt(i)
}
for (let i = 0; i < uid.length; i++) {
contentArray[i + 102] = uid.charCodeAt(i)
}
contentArray[122] = openMode
contentArray[123] = keyType
contentArray.set(timestampToArray(startDate), 124)
contentArray.set(timestampToArray(expireDate), 128)
contentArray[132] = useCountLimit / 256
contentArray[133] = useCountLimit % 256
contentArray[134] = isRound
contentArray[135] = weekRound
contentArray[136] = startHour
contentArray[137] = startMin
contentArray[138] = endHour
contentArray[139] = endMin
contentArray[140] = role
for (let i = 0; i < password.length; i++) {
contentArray[i + 141] = password.charCodeAt(i)
}
contentArray.set(this.lockInfo.token || timestampToArray(startDate), 161)
contentArray[165] = 16
2024-10-21 09:58:17 +08:00
const md5Array = md5Encrypt(
authUid + keyId,
this.lockInfo.token || timestampToArray(startDate),
this.lockInfo.bluetooth.publicKey
)
2024-10-12 14:35:58 +08:00
contentArray.set(md5Array, 166)
const cebArray = sm4.encrypt(contentArray, this.lockInfo.bluetooth.privateKey, {
mode: 'ecb',
output: 'array'
})
const packageArray = createPackageEnd(headArray, cebArray)
2024-10-21 09:58:17 +08:00
const writeResult = await writeBLECharacteristicValue(
this.lockInfo.deviceId,
this.lockInfo.serviceId,
this.lockInfo.writeCharacteristicId,
packageArray
)
2024-10-12 14:35:58 +08:00
if (writeResult.code !== Result.Success.code) {
return writeResult
}
return this.getWriteResult(this.addLockUser, disconnect, data)
},
// 获取写入结果
2024-10-21 09:58:17 +08:00
// eslint-disable-next-line default-param-last
2024-10-12 14:35:58 +08:00
getWriteResult(request, disconnect = false, params) {
return new Promise(resolve => {
const getWriteResultTimer = setTimeout(() => {
resolve(Result.Fail)
}, 20000)
2024-10-21 09:58:17 +08:00
characteristicValueCallback = async data => {
2024-10-12 14:35:58 +08:00
// code 6 token过期,重新获取
if (data.code === Result.NotTokenLock.code) {
resolve(await request(params))
} else if (data.code === Result.NotRegisteredLock.code) {
const checkResult = await this.checkLockUser(true)
if (checkResult.code === Result.Success.code) {
resolve(await request(params))
} else {
clearTimeout(getWriteResultTimer)
resolve(checkResult)
}
} else {
clearTimeout(getWriteResultTimer)
2024-10-21 09:58:17 +08:00
if (disconnect) {
2024-10-12 14:35:58 +08:00
await this.disconnectDevice()
}
console.log('写入结果', data, request, params)
resolve(data)
}
}
})
},
// 检查是否已添加为用户
async checkLockUser(forceAdd = false) {
if (this.lockInfo.lockUserNo === 0 || forceAdd) {
2024-10-21 09:58:17 +08:00
const timestamp = Math.floor(new Date().getTime() / 1000)
const password = (Math.floor(Math.random() * 900000) + 100000).toString()
2024-10-12 14:35:58 +08:00
console.log('用户未添加,开始添加用户')
const addUserParams = {
name: this.lockInfo.bluetooth.bluetoothDeviceName,
keyId: this.lockInfo.keyId.toString(),
authUid: this.lockInfo.uid.toString(),
uid: this.userInfo.uid.toString(),
openMode: 1,
keyType: 0,
2024-10-21 09:58:17 +08:00
startDate:
this.lockInfo.startDate === 0 ? timestamp : Math.floor(this.lockInfo.startDate / 1000),
expireDate:
this.lockInfo.endDate === 0 ? 0xffffffff : Math.floor(this.lockInfo.endDate / 1000),
2024-10-12 14:35:58 +08:00
useCountLimit: this.lockInfo.keyType === 3 ? 1 : 0xffff,
isRound: this.lockInfo.keyType === 4 ? 1 : 0,
2024-10-21 09:58:17 +08:00
weekRound:
this.lockInfo.keyType === 4 ? convertWeekdaysToNumber(this.lockInfo.weekDays) : 0,
startHour: this.lockInfo.keyType === 4 ? new Date(this.lockInfo.startDate).getHours() : 0,
startMin:
this.lockInfo.keyType === 4 ? new Date(this.lockInfo.startDate).getMinutes() : 0,
endHour: this.lockInfo.keyType === 4 ? new Date(this.lockInfo.endDate).getHours() : 0,
endMin: this.lockInfo.keyType === 4 ? new Date(this.lockInfo.endDate).getMinutes() : 0,
2024-10-12 14:35:58 +08:00
role: 0,
password
}
const addUserResult = await this.addLockUser(addUserParams)
console.log('添加用户蓝牙结果', addUserResult)
if (addUserResult.code === Result.Success.code) {
2024-10-21 09:58:17 +08:00
const { code } = await updateLockUserNoRequest({
2024-10-12 14:35:58 +08:00
keyId: this.lockInfo.keyId,
lockUserNo: this.lockInfo.lockUserNo
})
console.log('添加用户请求结果', code)
return Result.Success
2024-10-21 09:58:17 +08:00
}
if (addUserResult.code === Result.NotMoreKeyLock.code) {
2024-10-12 14:35:58 +08:00
console.log('用户达上限,开始清理用户')
2024-10-21 09:58:17 +08:00
const { code: cleanCode } = await this.cleanLockUser()
2024-10-12 14:35:58 +08:00
console.log('清理用户蓝牙结果', cleanCode)
if (cleanCode === Result.Success.code) {
return await this.checkLockUser()
}
return Result.Fail
}
2024-10-21 09:58:17 +08:00
if (addUserResult.code === Result.ReadyHasKeyLock.code) {
return Result.Success
}
return Result.Fail
2024-10-12 14:35:58 +08:00
}
2024-10-21 09:58:17 +08:00
return Result.Success
2024-10-12 14:35:58 +08:00
},
// 更新锁信息
updateLockInfo(lockInfo) {
this.lockInfo = {
...this.lockInfo,
...lockInfo
}
},
// 特征值变化回调
listenCharacteristicValue(res) {
if (res.deviceId === this.lockInfo.deviceId) {
let binaryData = new Uint8Array(res.value)
2024-10-21 09:58:17 +08:00
if (
binaryData[0] === 0xef &&
binaryData[1] === 0x01 &&
binaryData[2] === 0xee &&
binaryData[3] === 0x02
) {
2024-10-12 14:35:58 +08:00
length = binaryData[8] * 256 + binaryData[9]
if (length + 14 > binaryData.length) {
completeArray = binaryData
} else {
this.parsingCharacteristicValue(binaryData).then(() => {})
}
2024-10-21 09:58:17 +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) {
this.parsingCharacteristicValue(completeArray).then(() => {})
completeArray = null
2024-10-12 14:35:58 +08:00
}
}
}
},
// 解析特征值
2024-10-21 09:58:17 +08:00
async parsingCharacteristicValue(binaryData) {
2024-10-12 14:35:58 +08:00
// 0x20 明文 0x22 SM4事先约定密钥 0x23 SM4设备指定密钥
if (binaryData[7] === 0x20) {
if (binaryData[12] * 256 + binaryData[13] === cmdIds.getPublicKey) {
if (binaryData[14] === Result.Success.code) {
this.updateLockInfo({
bluetooth: {
...this.lockInfo.bluetooth,
publicKey: [...binaryData.slice(15, 31)]
}
})
}
characteristicValueCallback(new Result(binaryData[14]))
}
} else if (binaryData[7] === 0x22) {
// 截取入参
const cebBinaryData = binaryData.slice(12, binaryData.length - 2)
// 解密
const key = new Uint8Array(16)
for (let i = 0; i < this.lockInfo.bluetooth.bluetoothDeviceName.length; i++) {
key[i] = this.lockInfo.bluetooth.bluetoothDeviceName.charCodeAt(i)
}
const decrypted = sm4.decrypt(cebBinaryData, key, {
mode: 'ecb',
output: 'array'
})
console.log('ecb解密后的数据', decrypted)
if (decrypted[0] * 256 + decrypted[1] === cmdIds.getCommKey) {
if (decrypted[2] === Result.Success.code) {
this.updateLockInfo({
bluetooth: {
...this.lockInfo.bluetooth,
privateKey: decrypted.slice(3, 19),
signKey: decrypted.slice(19, 35),
pwdTimestamp: arrayToTimestamp(decrypted.slice(35, 39)) * 1000
}
})
console.log('privateKey', Array.from(this.lockInfo.bluetooth.privateKey))
console.log('signKey', Array.from(this.lockInfo.signKey))
}
characteristicValueCallback(new Result(decrypted[2]))
}
} else {
const cebBinaryData = binaryData.slice(12, binaryData.length - 2)
const decrypted = sm4.decrypt(cebBinaryData, this.lockInfo.bluetooth.privateKey, {
mode: 'ecb',
output: 'array'
})
console.log('ecb解密后的数据', decrypted)
const cmdId = decrypted[0] * 256 + decrypted[1]
switch (cmdId) {
case cmdIds.getLockStatus:
if (decrypted[2] === Result.Success.code) {
const lockConfig = {
vendor: uint8ArrayToString(decrypted.slice(3, 23)),
product: decrypted[23],
model: uint8ArrayToString(decrypted.slice(24, 44)),
fwVersion: uint8ArrayToString(decrypted.slice(44, 64)),
hwVersion: uint8ArrayToString(decrypted.slice(64, 84)),
serialNum0: uint8ArrayToString(decrypted.slice(84, 100)),
serialNum1: uint8ArrayToString(decrypted.slice(100, 116)),
btDeviceName: uint8ArrayToString(decrypted.slice(116, 132)),
electricQuantity: decrypted[132],
electricQuantityStandby: decrypted[133],
restoreCount: decrypted[134] * 256 + decrypted[135],
restoreDate: arrayToTimestamp(decrypted.slice(136, 140)),
icPartNo: uint8ArrayToString(decrypted.slice(140, 150)),
indate: arrayToTimestamp(decrypted.slice(150, 154)),
mac: uint8ArrayToString(decrypted.slice(154, 174)),
2024-10-21 09:58:17 +08:00
timezoneOffset: new Date().getTimezoneOffset() * 60
2024-10-12 14:35:58 +08:00
}
this.updateLockInfo({
2024-10-21 09:58:17 +08:00
featureValue: uint8ArrayToString(decrypted.slice(175, 175 + decrypted[174])),
featureSettingValue: 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]])
),
2024-10-12 14:35:58 +08:00
lockConfig
})
console.log('获取锁状态成功', this.lockInfo.lockConfig)
}
characteristicValueCallback(new Result(decrypted[2]))
break
case cmdIds.addUser:
this.updateLockInfo({
token: decrypted.slice(42, 46)
})
if (decrypted[46] === Result.Success.code) {
this.updateLockInfo({
lockUserNo: decrypted[47] * 256 + decrypted[48]
})
}
console.log('添加用户结果', decrypted[46], this.lockInfo.token)
characteristicValueCallback(new Result(decrypted[46]))
break
case cmdIds.expandCmd:
const subCmdId = decrypted[3]
switch (subCmdId) {
case subCmdIds.resetLockPassword:
this.updateLockInfo({
token: decrypted.slice(5, 9)
})
characteristicValueCallback(new Result(decrypted[4]))
break
case subCmdIds.setLockPassword:
this.updateLockInfo({
token: decrypted.slice(5, 9)
})
if (decrypted[2] === Result.Success.code) {
2024-10-21 09:58:17 +08:00
if (decrypted[11] === Result.Success.code) {
2024-10-12 14:35:58 +08:00
const pwdNo = decrypted[9] * 256 + decrypted[10]
if (requestParams.operate === 0) {
const addResult = await addCustomPassword({
...requestParams,
pwdUserNo: pwdNo,
lockId: this.lockInfo.lockId
})
if (addResult.code === Result.Success.code) {
2024-10-21 09:58:17 +08:00
characteristicValueCallback(
new Result(addResult.code, {
pwdNo,
keyboardPwdId: addResult.data.keyboardPwdId,
keyboardPwd: addResult.data.keyboardPwd
})
)
2024-10-12 14:35:58 +08:00
} else {
2024-10-21 09:58:17 +08:00
characteristicValueCallback(
new Result(addResult.code, addResult.data, addResult.message)
)
2024-10-12 14:35:58 +08:00
}
} else if (requestParams.operate === 1) {
const updateResult = await updatePassword({
...requestParams,
keyboardPwdId: this.lockInfo.keyboardPwdId
})
if (updateResult.code === Result.Success.code) {
characteristicValueCallback(new Result(updateResult.code))
} else {
2024-10-21 09:58:17 +08:00
characteristicValueCallback(
new Result(updateResult.code, updateResult.data, updateResult.message)
)
2024-10-12 14:35:58 +08:00
}
}
} else {
characteristicValueCallback(new Result(decrypted[11]))
}
} else {
characteristicValueCallback(new Result(decrypted[2]))
}
break
2024-10-21 09:58:17 +08:00
default:
break
2024-10-12 14:35:58 +08:00
}
break
case cmdIds.openDoor:
this.updateLockInfo({
token: decrypted.slice(2, 6)
})
console.log('开门', decrypted[6], this.lockInfo.token)
characteristicValueCallback(new Result(decrypted[6]))
break
default:
this.updateLockInfo({
token: decrypted.slice(2, 6)
})
console.log('默认结果', decrypted[6], this.lockInfo.token)
characteristicValueCallback(new Result(decrypted[6]))
break
}
}
},
// 获取配置
getConfig() {
let config = configs[this.env]
return {
...config,
version,
buildNumber
}
},
/*
* 生成包头
* encryptionType 加密类型 0明文1AES1282SM4事先约定密钥3SM4设备指定密钥
* originalLength 原始数据长度
* */
createPackageHeader(encryptionType, originalLength) {
// 头部数据
let headArray = new Uint8Array(12)
// 固定包头
2024-10-21 09:58:17 +08:00
headArray[0] = 0xef
2024-10-12 14:35:58 +08:00
headArray[1] = 0x01
2024-10-21 09:58:17 +08:00
headArray[2] = 0xee
2024-10-12 14:35:58 +08:00
headArray[3] = 0x02
// 包类型 发送
headArray[4] = 0x01
// 包序号
headArray[5] = this.messageCount / 256
headArray[6] = this.messageCount % 256
this.messageCount++
// 包标识
if (encryptionType === 0) {
headArray[7] = 0x20
} else if (encryptionType === 2) {
headArray[7] = 0x22
} else {
headArray[7] = 0x23
}
// 数据长度
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
},
// 断开与设备的连接
async disconnectDevice() {
return await closeBLEConnection(this.lockInfo.deviceId)
2024-10-21 09:58:17 +08:00
}
2024-10-12 14:35:58 +08:00
}
})