import { sm4 } from 'sm-crypto' import { cmdIds, Result } from '../constant' import { searchAndConnectDevice, writeBLECharacteristicValue } from '../uni/basic' import { createPackageEnd, md5Encrypt, timestampToArray } from '../format' import { getLockDetailRequest, getLockSettingDataRequest } from '../api' import { getStorage, setStorage } from '../export' import log from '../log' /** * 选择锁 * @param params * @param {Number} [params.uid] 用户ID * @param {Number} params.lockId 锁ID * @returns {Promise} */ export async function selectLock(params) { const { lockId } = params const result = await this.login(params.uid) if (result.code !== Result.Success.code) { return result } const { code, data, message } = await getLockDetailRequest({ lockId }) if (code === Result.Success.code) { this.lockInfo = data let lockList = getStorage('starLockList') if (!lockList) { lockList = {} } if (lockList[this.accountInfo.uid]) { const index = lockList[this.accountInfo.uid].findIndex(item => item.lockId === lockId) if (index === -1) { lockList[this.accountInfo.uid].push(this.lockInfo) } else { this.lockInfo.token = lockList[this.accountInfo.uid][index].token lockList[this.accountInfo.uid][index] = this.lockInfo } setStorage('starLockList', lockList) } else { lockList[this.accountInfo.uid] = [this.lockInfo] setStorage('starLockList', lockList) } } else if (code === Result.Fail.code) { const lockList = getStorage('starLockList') if (lockList[this.accountInfo.uid]) { const index = lockList[this.accountInfo.uid].findIndex(item => item.lockId === lockId) if (index !== -1) { this.lockInfo = lockList[this.accountInfo.uid][index] return new Result(Result.Success.code, this.lockInfo) } } } return new Result(code, data, message) } /** * 开门 * @param params * @param {Number} [params.uid] 用户ID * @param {String} params.type 开门方式 close: 关门 open: 开门 * @param {Boolean} [params.disconnect] 操作后是否断开连接,默认断开 * @returns {Promise} */ export async function openDoor(params) { const { type } = params log.info({ ...new Result( Result.Success.code, { lockName: this.lockInfo.bluetooth.bluetoothDeviceName, lockId: this.lockInfo.lockId, uid: params.uid, time: new Date().getTime() }, `开始开门` ), name: 'openDoor' }) // 设置执行账号 const result = await this.login(params.uid) if (result.code !== Result.Success.code) { return result } log.info({ ...new Result( result.code, { lockName: this.lockInfo.bluetooth.bluetoothDeviceName, lockId: this.lockInfo.lockId, uid: this.accountInfo.uid, time: new Date().getTime() }, `登录星云账号: ${result.message}` ), name: 'openDoor' }) // 确认设备连接正常 if (!params.connected) { const searchResult = await searchAndConnectDevice(this.lockInfo.bluetooth.bluetoothDeviceName) log.info({ ...new Result( searchResult.code, { lockName: this.lockInfo.bluetooth.bluetoothDeviceName, lockId: this.lockInfo.lockId, uid: this.accountInfo.uid, time: new Date().getTime() }, `连接设备: ${searchResult.message}` ), name: 'openDoor' }) 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 } log.info({ ...new Result( checkResult.code, { lockName: this.lockInfo.bluetooth.bluetoothDeviceName, lockId: this.lockInfo.lockId, uid: this.accountInfo.uid, time: new Date().getTime() }, `确认是否为锁用户: ${checkResult.message}` ), name: 'openDoor' }) // 是否需要联网 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 } } log.info({ ...new Result( checkResult.code, { lockName: this.lockInfo.bluetooth.bluetoothDeviceName, lockId: this.lockInfo.lockId, uid: this.accountInfo.uid, time: new Date().getTime() }, `判断是否需要联网token: ${this.lockInfo.lockSetting.appUnlockOnline}` ), name: 'openDoor' }) // 开门方式 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.accountInfo.uid.toString() const openTime = Math.ceil(new Date().getTime() / 1000) + this.timeDifference 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 const md5Array = md5Encrypt( name + uid, this.lockInfo.token || timestampToArray(openTime), this.lockInfo.bluetooth.signKey ) 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) log.info({ ...new Result( Result.Success.code, { lockName: this.lockInfo.bluetooth.bluetoothDeviceName, lockId: this.lockInfo.lockId, uid: this.accountInfo.uid, time: new Date().getTime() }, `开始写入` ), name: 'openDoor' }) const writeResult = await writeBLECharacteristicValue( this.lockInfo.deviceId, this.lockInfo.serviceId, this.lockInfo.writeCharacteristicId, packageArray ) if (writeResult.code !== Result.Success.code) { return writeResult } log.info({ ...new Result( writeResult.code, { lockName: this.lockInfo.bluetooth.bluetoothDeviceName, lockId: this.lockInfo.lockId, uid: this.accountInfo.uid, time: new Date().getTime() }, `写入完成:${writeResult.message}` ), name: 'openDoor' }) return this.getWriteResult(this.openDoor, params) } /** * 删除锁 * @param params * @param {Number} [params.uid] 用户ID */ export async function deleteLock(params) { // 设置执行账号 const result = await this.login(params.uid) if (result.code !== Result.Success.code) { return result } // 确认设备连接正常 if (!params.connected) { 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 } const { token, bluetooth: { publicKey, privateKey } } = this.lockInfo const authUid = this.lockInfo.uid.toString() const name = this.lockInfo.bluetooth.bluetoothDeviceName const length = 2 + 40 + 20 + 4 + 1 + 16 const headArray = this.createPackageHeader(3, length) const contentArray = new Uint8Array(length) contentArray[0] = cmdIds.resetDevice / 256 contentArray[1] = cmdIds.resetDevice % 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) } contentArray.set(token || new Uint8Array([0, 0, 0, 0]), 62) contentArray[66] = 16 const md5Array = md5Encrypt(name, token || new Uint8Array([0, 0, 0, 0]), publicKey) contentArray.set(md5Array, 67) const cebArray = sm4.encrypt(contentArray, privateKey, { mode: 'ecb', output: 'array' }) const packageArray = createPackageEnd(headArray, cebArray) const writeResult = await writeBLECharacteristicValue( this.lockInfo.deviceId, this.lockInfo.serviceId, this.lockInfo.writeCharacteristicId, packageArray ) if (writeResult.code !== Result.Success.code) { return writeResult } return this.getWriteResult(this.deleteLock, params) } /** * 获取锁支持项 * @param params * @param {Number} [params.uid] 用户ID * @param {Number} params.lockId 锁 Id * @returns {Promise} */ export async function getLockSupportFeatures(params) { const { lockId } = params // 设置执行账号 const result = await this.login(params.uid) if (result.code !== Result.Success.code) { return result } const { code, data, message } = await getLockSettingDataRequest({ lockId }) if (code === Result.Success.code) { return new Result(code, { ...data.lockFeature }, message) } return new Result(code, data, message) }