From 806ec1b7779de0de38b632a646cacbd91fdfc984 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8C=83=E9=B9=8F?= Date: Mon, 18 Nov 2024 14:45:33 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=98=9F=E4=BA=91SDK=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=A4=9A=E8=B4=A6=E5=8F=B7=E5=90=8C=E6=97=B6=E4=BD=BF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 105 ++---- request.js | 9 +- starCloud.js | 967 +++++++++++++++++++++++++++++---------------------- 3 files changed, 595 insertions(+), 486 deletions(-) diff --git a/README.md b/README.md index 031f750..cb5075f 100644 --- a/README.md +++ b/README.md @@ -30,12 +30,13 @@ import { useStarCloudStore } from '@/starCloud/starCloud' const $starCloud = useStarCloudStore() /** - * 初始化SDK - * @property {String} clientId - 客户端Id - * @property {String} clientSecret - 客户端密码 - * @property {String} env - 环境('DEV', 'PRE', 'XHJ', 'SKY) + * 初始化星云 + * @param params + * @param {String} params.clientId 客户端Id + * @param {String} params.clientSecret 客户端密码 + * @param {String} params.env 环境 */ -$starCloud.initStarCloud(clientId, clientSecret, env) +$starCloud.initStarCloud(params) // 注册,后续所有方法调用返回值均为code, data, message // code对应报错码有三部分组合构成,锁端报错码+星云服务端报错码+自定义报错码 @@ -48,83 +49,48 @@ if (code === Result.Success.code) { } /** - * 登录 - * @property {String} username - 用户名 - * @property {String} password - 密码 + * 退出登录 + * @param params + * @param {Number} params.uid 用户ID */ -const { code, data, message } = await $starCloud.login(username, password) - -/** - * 退出登录(未做请求,实际上不会失败) - */ -const { code, data, message } = await $starCloud.logout() +const { code, data, message } = await $starCloud.logout(params) /** * 选择锁 - * @property {Number} lockId - 锁Id + * @param params + * @param {AccountInfo} params.accountInfo 账号信息 + * @param {Number} params.lockId 锁ID + * @returns {Promise} */ -// 所需信息data中会返回,如data中没有可通过$starCloud.lockInfo获取 -const { code, data, message } = await $starCloud.selectLock(lockId) +const { code, data, message } = await $starCloud.selectLock(params) /** * 开门 - * @property {String} type - 开门或关门类型('open', 'close') - * @property {Boolean} disconnect - 操作完成后是否断开连接 + * @param params + * @param {AccountInfo} params.accountInfo 账号信息 + * @param {String} params.type 开门方式 close: 关门 open: 开门 + * @param {Boolean} params.disconnect 操作后是否断开连接 + * @returns {Promise} */ -const { code, data, message } = await $starCloud.openDoor(type, disconnect) - -/** - * 清理用户 - * @property {Boolean} disconnect - 操作完成后是否断开连接 - */ -const { code, data, message } = await $starCloud.cleanLockUser(disconnect) +const { code, data, message } = await $starCloud.openDoor(params) /** * 获取离线密码 - * 该功能无需蓝牙交互直接请求服务端,详细参数说明请看星云接口文档 - * @typedef {Object} password - * @property {String} keyboardPwdName - 密码名称 - * @property {Number} keyboardPwdType - 密码类型 - * @property {Number} isCoerced - 胁迫 1:胁迫 2:非胁迫 - * @property {Number} startDate - 开始时间 - * @property {Number} endDate - 结束时间 - * @property {Number} hoursStart - 开始小时 - * @property {Number} hoursEnd - 结束小时 + * @param {AccountInfo} accountInfo 账号信息 + * @param {OfflinePassword} password 密码信息 + * @returns {Promise} */ -const data = await $starCloud.getOfflinePassword({ - keyboardPwdName: `租客端单次密码${new Date().getTime()}`, - keyboardPwdType: 1, - isCoerced: 2, - startDate: 0, - endDate: 0, - hoursStart: 0, - hoursEnd: 0 -}) +const data = await $starCloud.getOfflinePassword(accountInfo, password) /** * 自定义密码 - * @typedef {Object} password - * @property {String} keyboardPwdName - 密码名称 - * @property {Number} keyboardPwdType - 密码类型 - * @property {Number} isCoerced - 胁迫 1:胁迫 2:非胁迫 - * @property {Number} startDate - 开始时间 - * @property {Number} endDate - 结束时间 - * @property {Number} keyboardPwd - 密码 - * @property {Number} addType - 添加方式,当前仅支持1 1:蓝牙 2:网关 - * @property {Number} operate - 操作类型,0:注册 1:修改 - * @property {Number} pwdRight - 是否是管理员密码,0:否 1:是 + * @param params + * @param {AccountInfo} params.accountInfo 账号信息 + * @param {CustomPassword} params.password 密码信息 + * @param {Boolean} params.disconnect 操作后是否断开连接 + * @returns {Promise} */ -const data = await $starCloud.customPassword({ - keyboardPwdName: `租客端自定义密码`, - keyboardPwdType: 3, - keyboardPwd: 111111, - addType: 1, - isCoerced: 2, - startDate: 1728698137000, - endDate: 1735574400000, - operate: 0, - pwdRight: 0 -}, true) +const data = await $starCloud.customPassword(params) /** * 搜索蓝牙设备 @@ -139,8 +105,11 @@ const searchDevice = async result => { await $starCloud.stopSearchDevice() /** - * 连接蓝牙设备 - * @property {String} name - 设备名称 + * 绑定设备 + * @param params + * @param {AccountInfo} params.accountInfo 账号信息 + * @param {String} params.name 设备名称 + * @returns {Promise} */ -const data = await $starCloud.bindDevice(name) +const data = await $starCloud.bindDevice(params) ``` diff --git a/request.js b/request.js index f596ac0..58b2073 100644 --- a/request.js +++ b/request.js @@ -60,10 +60,11 @@ const request = config => { if (code === 10003) { removeStorage('starCloudToken') removeStorage('starCloudUser') - const { code } = await starCloud.login( - starCloud.accountInfo.username, - starCloud.accountInfo.password - ) + const { code } = await starCloud.login({ + username: starCloud.starCloudAccountInfo.username, + password: starCloud.starCloudAccountInfo.password, + uid: starCloud.starCloudAccountInfo.uid + }) if (code === Result.Success.code) { resolve(await request(config)) } diff --git a/starCloud.js b/starCloud.js index fbfd96b..8eba676 100644 --- a/starCloud.js +++ b/starCloud.js @@ -38,6 +38,42 @@ import { uint8ArrayToString } from '@/starCloud/format' +/** + * 离线密码 + * 该功能无需蓝牙交互直接请求服务端,详细参数说明请看星云接口文档 + * @typedef {Object} OfflinePassword + * @property {String} keyboardPwdName - 密码名称 + * @property {Number} keyboardPwdType - 密码类型 + * @property {Number} isCoerced - 胁迫 1:胁迫 2:非胁迫 + * @property {Number} startDate - 开始时间 + * @property {Number} endDate - 结束时间 + * @property {Number} hoursStart - 开始小时 + * @property {Number} hoursEnd - 结束小时 + */ + +/** + * 自定义密码 + * @typedef {Object} CustomPassword + * @property {String} keyboardPwdName - 密码名称 + * @property {Number} keyboardPwdType - 密码类型 + * @property {Number} isCoerced - 胁迫 1:胁迫 2:非胁迫 + * @property {Number} startDate - 开始时间 + * @property {Number} endDate - 结束时间 + * @property {Number} keyboardPwd - 密码 + * @property {Number} addType - 添加方式,当前仅支持1 1:蓝牙 2:网关 + * @property {Number} operate - 操作类型,0:注册 1:修改 + * @property {Number} pwdRight - 是否是管理员密码,0:否 1:是 + */ + +/** + * 账户信息信息 + * @typedef {Object} AccountInfo + * @property {Number} uid 用户ID + * @property {String} username 用户名 + * @property {String} password 密码 + * @property {String} token token 非必填 + */ + /** * 锁信息 * @typedef {Object} lockInfo @@ -145,39 +181,47 @@ export const useStarCloudStore = defineStore('starCloud', { clientId: null, // 客户端密码 clientSecret: null, - // 星云是否登录 - loginStarCloud: false, - // 星云用户信息 - userInfo: null, - // 账户信息 - accountInfo: null, + // 小程序环境 + envVersion: '', // 锁信息 lockInfo: null, - // 消息序号 - messageCount: 1, // 服务器时间 serverTimestamp: 0, // 时间差 timeDifference: 0, - // 小程序环境 - envVersion: '', // 搜索设备列表 - searchDeviceList: [] + searchDeviceList: [], + // 星云用户信息 + userInfo: null, + // 账户信息 + accountInfo: null, + // 消息序号 + messageCount: 1 } }, actions: { - // 初始化星云 - initStarCloud(clientId, clientSecret, env = 'XHJ') { + /** + * 初始化星云 + * @param params + * @param {String} params.clientId 客户端Id + * @param {String} params.clientSecret 客户端密码 + * @param {String} params.env 环境 + */ + initStarCloud(params) { + const { clientId, clientSecret, env } = params const appInfo = uni.getAccountInfoSync() this.envVersion = appInfo.miniProgram.envVersion - this.env = env + this.env = env || 'XHJ' this.clientId = clientId this.clientSecret = clientSecret // 监听特性值变化 onBLECharacteristicValueChange(this.listenCharacteristicValue) }, - // 注册星云 + /** + * 注册星云 + * @returns {Promise} + */ async register() { const { code, data, message } = await starCloudCreateUser({ clientId: this.clientId, @@ -185,87 +229,456 @@ export const useStarCloudStore = defineStore('starCloud', { }) return new Result(code, data, message) }, - // 登录星云 - async login(username, password) { - this.accountInfo = { - username, - password + /** + * 退出登录 + * @param params + * @param {Number} params.uid 用户ID + */ + logout(params) { + const { uid } = params + if (this.accountInfo.uid === uid) { + this.userInfo = null + this.accountInfo = null + this.lockInfo = null + removeStorage('starCloudToken') + } + }, + /** + * 选择锁 + * @param params + * @param {AccountInfo} params.accountInfo 账号信息 + * @param {Number} params.lockId 锁ID + * @returns {Promise} + */ + async selectLock(params) { + const { accountInfo, lockId } = params + const result = await this.login(accountInfo) + if (result.code !== Result.Success.code) { + return result } - const token = getStorage('starCloudToken') - if (token) { - this.userInfo = getStorage('starCloudUser') - this.loginStarCloud = true - // 获取服务器时间 - this.getServerTimestamp().then(() => {}) - return Result.Success - } - console.log('登录星云', username, password) - const { - code, - data: userInfo, - message - } = await getStarCloudToken({ - username, - password, - 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 - // 获取服务器时间 - this.getServerTimestamp().then(() => {}) - } - return new Result(code, {}, message) - }, - // 退出登录 - logout() { - this.loginStarCloud = false - this.userInfo = null - this.accountInfo = null - removeStorage('starCloudToken') - removeStorage('starCloudUser') - removeStorage('lockList') - - return Result.Success - }, - // 选择锁 - async selectLock(lockId) { const { code, data, message } = await getLockDetailRequest({ lockId }) if (code === Result.Success.code) { - const lockList = getStorage('lockList') - if (lockList) { - const index = lockList.findIndex(item => item.lockId === lockId) + let lockList = getStorage('lockList') + if (!lockList) { + lockList = {} + } + if (lockList[accountInfo.uid]) { + const index = lockList[accountInfo.uid].findIndex(item => item.lockId === lockId) if (index === -1) { - lockList.push(data) + lockList[accountInfo.uid].push(data) } else { - lockList[index] = data + lockList[accountInfo.uid][index] = data } setStorage('lockList', lockList) } else { - setStorage('lockList', [data]) + lockList[accountInfo.uid] = [data] + setStorage('lockList', lockList) } this.lockInfo = data } else { const lockList = getStorage('lockList') - console.log('锁列表', lockList) - if (lockList) { - const index = lockList.findIndex(item => item.lockId === lockId) + if (lockList[accountInfo.uid]) { + const index = lockList[accountInfo.uid].findIndex(item => item.lockId === lockId) if (index !== -1) { - this.lockInfo = lockList[index] + this.lockInfo = lockList[accountInfo.uid][index] return new Result(Result.Success.code, this.lockInfo) } } } return new Result(code, data, message) }, - // 清理用户 - async cleanLockUser(disconnect = false) { + /** + * 开门 + * @param params + * @param {AccountInfo} params.accountInfo 账号信息 + * @param {String} params.type 开门方式 close: 关门 open: 开门 + * @param {Boolean} params.disconnect 操作后是否断开连接 + * @returns {Promise} + */ + async openDoor(params) { + const { accountInfo, type } = params + // 设置执行账号 + const result = await this.login(accountInfo) + if (result.code !== Result.Success.code) { + return result + } + + // 确认设备连接正常 + 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.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) + + 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.openDoor, params) + }, + /** + * 获取离线密码 + * @param {AccountInfo} accountInfo 账号信息 + * @param {OfflinePassword} password 密码信息 + * @returns {Promise} + */ + async getOfflinePassword(accountInfo, password) { + // 设置执行账号 + const result = await this.login(accountInfo) + if (result.code !== Result.Success.code) { + return result + } + return await getOfflinePasswordRequest({ + ...password, + lockId: this.lockInfo.lockId + }) + }, + /** + * 自定义密码 + * @param params + * @param {AccountInfo} params.accountInfo 账号信息 + * @param {CustomPassword} params.password 密码信息 + * @param {Boolean} params.disconnect 操作后是否断开连接 + * @returns {Promise} + */ + async customPassword(params) { + const { accountInfo, password } = params + // 设置执行账号 + const result = await this.login(accountInfo) + if (result.code !== Result.Success.code) { + return result + } + // 确认设备连接正常 + 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.accountInfo.uid.toString() + const keyId = this.lockInfo.keyId.toString() + const isAdmin = pwdRight + const userCountLimit = 0xffff + startDate = Math.floor(startDate / 1000) + endDate = Math.floor(endDate / 1000) + keyboardPwd = keyboardPwd.toString() + + if (!pwdNo) { + 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 + + const md5Array = md5Encrypt( + keyId + uid, + this.lockInfo.token || new Uint8Array([0, 0, 0, 0]), + this.lockInfo.bluetooth.signKey + ) + + contentArray.set(md5Array, 103) + + const cebArray = sm4.encrypt(contentArray, this.lockInfo.bluetooth.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.customPassword, params) + }, + + // 搜索设备 + async searchDevice(callback) { + const result = await startBluetoothDevicesDiscovery() + if (result.code === Result.Success.code) { + const timestamp = new Date().getTime() + let queryFlag = false + timer = setInterval(async () => { + const queryResult = await getBluetoothDevices() + if (queryResult.code === Result.Success.code) { + const deviceList = queryResult.data + if (queryFlag === false && deviceList.length > 0) { + queryFlag = true + } + if (new Date().getTime() - timestamp > 10000 && !queryFlag) { + if (timer) { + clearInterval(timer) + } + callback(Result.NotAvailableWeChatNearbyDevicesEmpty) + } + + const list = [] + + for (let i = 0; i < deviceList.length; i++) { + if (deviceList[i]?.advertisServiceUUIDs) { + const uuid = deviceList[i]?.advertisServiceUUIDs[0] + if (uuid && uuid.slice(2, 8) === '758824' && uuid.slice(30, 32) === '00') { + list.push(deviceList[i]) + } + } + } + + this.searchDeviceList = list + callback( + new Result(Result.Success, { + list + }) + ) + } else { + callback(queryResult) + } + }, 1000) + } else { + callback(result) + } + }, + // 停止搜索 + async stopSearchDevice() { + console.log('停止搜索') + if (timer) { + clearInterval(timer) + } + + return await stopBluetoothDevicesDiscovery() + }, + /** + * 绑定设备 + * @param params + * @param {AccountInfo} params.accountInfo 账号信息 + * @param {String} params.name 设备名称 + * @returns {Promise} + */ + async bindDevice(params) { + const { accountInfo, name } = params + // 设置执行账号 + const result = await this.login(accountInfo) + if (result.code !== Result.Success.code) { + return result + } + const device = this.searchDeviceList.find(item => item.name === name) + const connectResult = await createBLEConnection(device.deviceId) + if (connectResult.code === Result.Success.code) { + this.updateLockInfo({ + ...connectResult.data, + bluetooth: { + bluetoothDeviceId: device.deviceId, + bluetoothDeviceName: device.name + } + }) + const publicKeyResult = await this.getPublicKey() + if (publicKeyResult.code !== Result.Success.code) { + return publicKeyResult + } + const commKeyResult = await this.getCommKey() + if (commKeyResult.code !== Result.Success.code) { + return commKeyResult + } + const lockStatusResult = await this.getLockStatus() + if (lockStatusResult.code !== Result.Success.code) { + return lockStatusResult + } + const timestamp = Math.ceil(new Date().getTime() / 1000) + const password = (Math.floor(Math.random() * 900000) + 100000).toString() + const addUserResult = await this.addLockUser({ + params: { + name: this.lockInfo.bluetooth.bluetoothDeviceName, + keyId: '0', + authUid: this.accountInfo.uid.toString(), + uid: this.accountInfo.uid.toString(), + openMode: 1, + keyType: 0, + startDate: timestamp, + expireDate: 0xffffffff, + useCountLimit: 0xffff, + isRound: 0, + weekRound: 0, + startHour: 0, + startMin: 0, + endHour: 0, + endMin: 0, + role: 0xff, + password + }, + disconnect: true + }) + if (addUserResult.code !== Result.Success.code) { + return addUserResult + } + + offBluetoothAdapterStateChange() + closeBluetoothAdapter() + + const params = { + lockAlias: this.lockInfo.bluetooth.bluetoothDeviceName, + lockInfo: { + ...this.lockInfo.lockConfig, + adminPwd: password + }, + bluetooth: this.lockInfo.bluetooth, + lockUserNo: this.lockInfo.lockUserNo, + pwdTimestamp: this.lockInfo.pwdTimestamp, + featureValue: this.lockInfo.featureValue, + featureSettingValue: this.lockInfo.featureSettingValue, + featureSettingParams: this.lockInfo.featureSettingParams + } + const bindLockResult = await bindLockRequest(params) + if (bindLockResult.code === Result.Success.code) { + this.updateLockInfo({ + lockId: bindLockResult.data.lockId, + keyId: bindLockResult.data.keyId + }) + } + return bindLockResult + } + return connectResult + }, + + /** + * 清理用户 + * @returns {Promise} + */ + async cleanLockUser() { // 确认设备连接正常 const searchResult = await searchAndConnectDevice(this.lockInfo.bluetooth.bluetoothDeviceName) if (searchResult.code !== Result.Success.code) { @@ -350,346 +763,69 @@ export const useStarCloudStore = defineStore('starCloud', { return writeResult } - return this.getWriteResult(this.cleanLockUser, disconnect) + return this.getWriteResult(this.cleanLockUser, { disconnect: false }) }, - // 开门 - // eslint-disable-next-line default-param-last - async openDoor(type = 'open', disconnect) { - // 确认设备连接正常 - const searchResult = await searchAndConnectDevice(this.lockInfo.bluetooth.bluetoothDeviceName) - if (searchResult.code !== Result.Success.code) { - return searchResult + /** + * 登录星云 + * @param {Object} accountInfo + * @returns {Promise} + */ + async login(accountInfo) { + let accounts = getStorage('starCloudAccount') + let userInfos = getStorage('starCloudUser') + if (!accounts) { + accounts = {} } - this.updateLockInfo(searchResult.data) - - // 检查是否已添加为用户 - const checkResult = await this.checkLockUser() - if (checkResult.code !== Result.Success.code) { - return checkResult + if (!userInfos) { + userInfos = {} } - // 是否需要联网 - 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 - } + this.accountInfo = accounts[accountInfo.uid] + if (this.accountInfo && this.accountInfo.token) { + this.userInfo = userInfos[accountInfo.uid] + + setStorage('starCloudToken', this.accountInfo.token) + + this.getServerTimestamp().then(() => {}) + return Result.Success } - // 开门方式 - 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() - 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 { + code, + data: userInfo, + message + } = await getStarCloudToken({ + username: accountInfo.username, + password: accountInfo.password, + clientId: this.clientId, + clientSecret: this.clientSecret }) - - 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.openDoor, disconnect) - }, - // 获取离线密码 - async getOfflinePassword(password) { - return await getOfflinePasswordRequest({ - ...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 - const userCountLimit = 0xffff - startDate = Math.floor(startDate / 1000) - endDate = Math.floor(endDate / 1000) - keyboardPwd = keyboardPwd.toString() - - if (!pwdNo) { - 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 - - const md5Array = md5Encrypt( - keyId + uid, - this.lockInfo.token || new Uint8Array([0, 0, 0, 0]), - this.lockInfo.bluetooth.signKey - ) - - contentArray.set(md5Array, 103) - - const cebArray = sm4.encrypt(contentArray, this.lockInfo.bluetooth.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.customPassword, disconnect, password) - }, - - // 搜索设备 - async searchDevice(callback) { - const result = await startBluetoothDevicesDiscovery() - if (result.code === Result.Success.code) { - const timestamp = new Date().getTime() - let queryFlag = false - timer = setInterval(async () => { - const queryResult = await getBluetoothDevices() - if (queryResult.code === Result.Success.code) { - const deviceList = queryResult.data - if (queryFlag === false && deviceList.length > 0) { - queryFlag = true - } - if (new Date().getTime() - timestamp > 10000 && !queryFlag) { - if (timer) { - clearInterval(timer) - } - callback(Result.NotAvailableWeChatNearbyDevicesEmpty) - } - - const list = [] - - for (let i = 0; i < deviceList.length; i++) { - if (deviceList[i]?.advertisServiceUUIDs) { - const uuid = deviceList[i]?.advertisServiceUUIDs[0] - if (uuid && uuid.slice(2, 8) === '758824' && uuid.slice(30, 32) === '00') { - list.push(deviceList[i]) - } - } - } - - this.searchDeviceList = list - callback( - new Result(Result.Success, { - list - }) - ) - } else { - callback(queryResult) - } - }, 1000) - } else { - callback(result) - } - }, - - // 停止搜索 - async stopSearchDevice() { - console.log('停止搜索') - if (timer) { - clearInterval(timer) - } - - return await stopBluetoothDevicesDiscovery() - }, - - // 绑定设备 - async bindDevice(name) { - const device = this.searchDeviceList.find(item => item.name === name) - const connectResult = await createBLEConnection(device.deviceId) - if (connectResult.code === Result.Success.code) { - this.updateLockInfo({ - ...connectResult.data, - bluetooth: { - bluetoothDeviceId: device.deviceId, - bluetoothDeviceName: device.name - } - }) - const publicKeyResult = await this.getPublicKey() - if (publicKeyResult.code !== Result.Success.code) { - return publicKeyResult - } - const commKeyResult = await this.getCommKey() - if (commKeyResult.code !== Result.Success.code) { - return commKeyResult - } - const lockStatusResult = await this.getLockStatus() - if (lockStatusResult.code !== Result.Success.code) { - return lockStatusResult - } - const timestamp = Math.ceil(new Date().getTime() / 1000) - const password = (Math.floor(Math.random() * 900000) + 100000).toString() - const addUserResult = await this.addLockUser( - { - name: this.lockInfo.bluetooth.bluetoothDeviceName, - keyId: '0', - authUid: this.userInfo.uid.toString(), - uid: this.userInfo.uid.toString(), - openMode: 1, - keyType: 0, - startDate: timestamp, - expireDate: 0xffffffff, - useCountLimit: 0xffff, - isRound: 0, - weekRound: 0, - startHour: 0, - startMin: 0, - endHour: 0, - endMin: 0, - role: 0xff, - password - }, - true - ) - if (addUserResult.code !== Result.Success.code) { - return addUserResult + if (code === Result.Success.code) { + this.userInfo = userInfo + this.accountInfo = { + username: accountInfo.username, + password: accountInfo.password, + token: userInfo.access_token, + uid: userInfo.cloudUid } + setStorage('starCloudToken', userInfo.access_token) - offBluetoothAdapterStateChange() - closeBluetoothAdapter() + accounts[userInfo.cloudUid] = { + uid: userInfo.cloudUid, + username: accountInfo.username, + password: accountInfo.password, + token: userInfo.access_token + } + setStorage('starCloudAccount', accounts) - const params = { - lockAlias: this.lockInfo.bluetooth.bluetoothDeviceName, - lockInfo: { - ...this.lockInfo.lockConfig, - adminPwd: password - }, - bluetooth: this.lockInfo.bluetooth, - lockUserNo: this.lockInfo.lockUserNo, - pwdTimestamp: this.lockInfo.pwdTimestamp, - featureValue: this.lockInfo.featureValue, - featureSettingValue: this.lockInfo.featureSettingValue, - featureSettingParams: this.lockInfo.featureSettingParams - } - const bindLockResult = await bindLockRequest(params) - if (bindLockResult.code === Result.Success.code) { - this.updateLockInfo({ - lockId: bindLockResult.data.lockId, - keyId: bindLockResult.data.keyId - }) - } - return bindLockResult + userInfos[userInfo.cloudUid] = userInfo + setStorage('starCloudUser', userInfo) + + // 获取服务器时间 + this.getServerTimestamp().then(() => {}) } - return connectResult + return new Result(code, {}, message) }, - // 获取公钥 async getPublicKey() { const headArray = this.createPackageHeader(0, 42) @@ -718,7 +854,7 @@ export const useStarCloudStore = defineStore('starCloud', { return writeResult } - return this.getWriteResult(this.getPublicKey, false) + return this.getWriteResult(this.getPublicKey, { disconnect: false }) }, // 获取私钥 async getCommKey() { @@ -731,7 +867,7 @@ export const useStarCloudStore = defineStore('starCloud', { const name = this.lockInfo.bluetooth.bluetoothDeviceName const keyId = '0' - const authUid = this.userInfo.uid.toString() + const authUid = this.accountInfo.uid.toString() await this.getServerTimestamp() const nowTime = this.serverTimestamp @@ -777,7 +913,7 @@ export const useStarCloudStore = defineStore('starCloud', { return writeResult } - return this.getWriteResult(this.getCommKey, false) + return this.getWriteResult(this.getCommKey, { disconnect: false }) }, // 获取锁状态 async getLockStatus() { @@ -789,7 +925,7 @@ export const useStarCloudStore = defineStore('starCloud', { contentArray[1] = cmdIds.getLockStatus % 256 const name = this.lockInfo.bluetooth.bluetoothDeviceName - const uid = this.userInfo.uid.toString() + const uid = this.accountInfo.uid.toString() await this.getServerTimestamp() const nowTime = this.serverTimestamp const date = new Date() @@ -822,7 +958,7 @@ export const useStarCloudStore = defineStore('starCloud', { return writeResult } - return this.getWriteResult(this.getLockStatus, false) + return this.getWriteResult(this.getLockStatus, { disconnect: false }) }, // 获取联网token async getNetToken() { @@ -841,7 +977,8 @@ export const useStarCloudStore = defineStore('starCloud', { return new Result(code, data, message) }, // 添加用户 - async addLockUser(data, disconnect = false) { + async addLockUser(params) { + const { params: data } = params // 确认设备连接正常 const searchResult = await searchAndConnectDevice( this.lockInfo.bluetooth.bluetoothDeviceName, @@ -945,11 +1082,10 @@ export const useStarCloudStore = defineStore('starCloud', { if (writeResult.code !== Result.Success.code) { return writeResult } - return this.getWriteResult(this.addLockUser, disconnect, data) + return this.getWriteResult(this.addLockUser, params) }, // 获取写入结果 - // eslint-disable-next-line default-param-last - getWriteResult(request, disconnect = false, params) { + getWriteResult(request, params) { return new Promise(resolve => { const getWriteResultTimer = setTimeout(() => { resolve(Result.Fail) @@ -968,7 +1104,7 @@ export const useStarCloudStore = defineStore('starCloud', { } } else { clearTimeout(getWriteResultTimer) - if (disconnect) { + if (params.disconnect) { await this.disconnectDevice() } console.log('写入结果', data, request, params) @@ -987,7 +1123,7 @@ export const useStarCloudStore = defineStore('starCloud', { name: this.lockInfo.bluetooth.bluetoothDeviceName, keyId: this.lockInfo.keyId.toString(), authUid: this.lockInfo.uid.toString(), - uid: this.userInfo.uid.toString(), + uid: this.accountInfo.uid.toString(), openMode: 1, keyType: 0, startDate: @@ -1006,7 +1142,10 @@ export const useStarCloudStore = defineStore('starCloud', { role: 0, password } - const addUserResult = await this.addLockUser(addUserParams) + const addUserResult = await this.addLockUser({ + params: addUserParams, + disconnect: false + }) console.log('添加用户蓝牙结果', addUserResult) if (addUserResult.code === Result.Success.code) { const { code } = await updateLockUserNoRequest({