commit cbf8505bae1e80cf2d9c92148f1ddbf8419f1197 Author: 范鹏 Date: Sat Oct 12 14:35:58 2024 +0800 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..485dee6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea diff --git a/README.md b/README.md new file mode 100644 index 0000000..e2ef19a --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +## 星云SDK + +### 1. 安装 + +### 2. 需安装的npm包 +`npm install buffer crc js-md5 pinia sm-crypto` diff --git a/api.js b/api.js new file mode 100644 index 0000000..d3a7b6b --- /dev/null +++ b/api.js @@ -0,0 +1,91 @@ +import request from '@/starCloud/request' + +// 创建账号 +export function starCloudCreateUser(data) { + return request({ + url: '/createUser', + method: 'POST', + data + }) +} + +// 获取访问令牌 +export function getStarCloudToken(data) { + return request({ + url: '/oauth2/token', + method: 'POST', + data + }) +} + +// 更新锁用户 +export function updateLockUserNoRequest(data) { + return request({ + url: '/v1/key/updateLockUserNo', + method: 'POST', + data + }) +} + +// 获取所有锁用户 +export function getUserNoListRequest(data) { + return request({ + url: '/v1/key/getUserNoList', + method: 'POST', + data + }) +} + +// 获取手机联网token +export function getLockNetTokenRequest(data) { + return request({ + url: '/v1/lock/getLockNetToken', + method: 'POST', + data + }) +} + +// 获取服务器时间 +export function getServerDatetime(data) { + return request({ + url: '/v1/lock/queryDate', + method: 'POST', + data + }) +} + +// 获取锁详情 +export function getLockDetail(data) { + return request({ + url: '/v1/lock/detail', + method: 'POST', + data + }) +} + +// 获取离线密码 +export function getOfflinePassword(data) { + return request({ + url: '/v1/keyboardPwd/get', + method: 'POST', + data + }) +} + +// 添加自定义密码 +export function addCustomPassword(data) { + return request({ + url: '/v1/keyboardPwd/add', + method: 'POST', + data + }) +} + +// 更新密码 +export function updatePassword(data) { + return request({ + url: '/v1/keyboardPwd/update', + method: 'POST', + data + }) +} diff --git a/basic.js b/basic.js new file mode 100644 index 0000000..6a0032f --- /dev/null +++ b/basic.js @@ -0,0 +1,442 @@ +export class Result { + static codes = { + Success: 0, + Fail: -1, + + NotAvailableBluetooth: -20, + NotAvailableBluetoothPermission: -21, + NotAvailableWeChatNearbyDevicesPermission: -22, + NotAvailableWeChatLocationPermission: -23, + NotAvailableWeChatNearbyDevicesEmpty: -24, + DeviceHasBeenReset: -30, + + NotRegisteredLock: 4, + NotTokenLock: 6, + NotMoreKeyLock: 12, + ReadyHasKeyLock: 15, + } + + static resultsMap = new Map([ + [Result.codes.Success, { message: '成功', data: {} }], + [Result.codes.Fail, { message: '失败', data: {} }], + + [Result.codes.NotAvailableBluetooth, { message: '蓝牙未开启', data: {} }], + [Result.codes.NotAvailableBluetoothPermission, { message: '小程序蓝牙权限被禁用', data: {} }], + [Result.codes.NotAvailableWeChatNearbyDevicesPermission, { message: '微信附近的设备权限被禁用', data: {} }], + [Result.codes.NotAvailableWeChatLocationPermission, { message: '微信定位权限被禁用', data: {} }], + [Result.codes.NotAvailableWeChatNearbyDevicesEmpty, { message: '微信附近的设备权限无法使用', data: {} }], + [Result.codes.DeviceHasBeenReset, { message: '设备已被重置', data: {} }], + + [Result.codes.NotRegisteredLock, { message: '用户在锁端未注册', data: {} }], + [Result.codes.NotTokenLock, { message: '用户在锁端token失效', data: {} }], + [Result.codes.NotMoreKeyLock, { message: '锁端钥匙数量已达上限', data: {} }], + [Result.codes.ReadyHasKeyLock, { message: '用户已是锁端用户', data: {} }], + ]) + + constructor(code, data, message) { + const result = Result.resultsMap.get(code) + if (result) { + this.code = code + this.message = message || result.message + this.data = data || result.data + } else { + this.code = code + this.message = message || '' + this.data = data || {} + } + } + + // 成功 + static get Success() { + return new Result(Result.codes.Success) + } + + // 失败(默认错误) + static get Fail() { + return new Result(Result.codes.Fail) + } + + // 蓝牙未开启 + static get NotAvailableBluetooth() { + return new Result(Result.codes.NotAvailableBluetooth) + } + + // 小程序蓝牙权限被禁用 + static get NotAvailableBluetoothPermission() { + return new Result(Result.codes.NotAvailableBluetoothPermission) + } + + // 微信附近的设备权限被禁用 + static get NotAvailableWeChatNearbyDevicesPermission() { + return new Result(Result.codes.NotAvailableWeChatNearbyDevicesPermission) + } + + // 微信定位权限被禁用 + static get NotAvailableWeChatLocationPermission() { + return new Result(Result.codes.NotAvailableWeChatLocationPermission) + } + + // 微信附近的设备权限无法使用(针对小米空白通行证,鸿蒙系统隐私中的定位服务) + static get NotAvailableWeChatNearbyDevicesEmpty() { + return new Result(Result.codes.NotAvailableWeChatNearbyDevicesEmpty) + } + + // 设备已被重置 + static get DeviceHasBeenReset() { + return new Result(Result.codes.DeviceHasBeenReset) + } + + // 用户在锁端未注册 + static get NotRegisteredLock() { + return new Result(Result.codes.NotRegisteredLock) + } + + // 用户在锁端token失效 + static get NotTokenLock() { + return new Result(Result.codes.NotTokenLock) + } + + // 锁端钥匙数量已达上限 + static get NotMoreKeyLock() { + return new Result(Result.codes.NotMoreKeyLock) + } + + // 锁端钥匙数量已达上限 + static get ReadyHasKeyLock() { + return new Result(Result.codes.ReadyHasKeyLock) + } +} + + +/** + * @typedef {Object} err + * @property {number} errno - 错误代码 + * @property {number} errCode - 错误代码 + * @property {String} errMsg - 错误信息 + */ + +// 查找设备并连接 +export function searchAndConnectDevice(name) { + // 循环查找设备 + let timer + // 超时计时器 + let timeoutTimer + + return new Promise(async (resolve) => { + const result = await startBluetoothDevicesDiscovery() + if(result.code === Result.Success.code) { + let searchFlag = false + timeoutTimer = setTimeout(async () => { + await stopBluetoothDevicesDiscovery() + clearInterval(timer) + if (!searchFlag) { + resolve(Result.NotAvailableWeChatNearbyDevicesEmpty) + } else { + resolve(Result.Fail) + } + }, 10500) + timer = setInterval(async () => { + const queryResult = await getBluetoothDevices() + if(queryResult.code === Result.Success.code) { + const deviceList = queryResult.data + if (searchFlag === false && deviceList.length > 0) { + searchFlag = true + } + for (let i = 0; i < deviceList.length; i++) { + if (deviceList[i]?.name === name) { + const uuid = deviceList[i]?.advertisServiceUUIDs[0] + if(uuid && uuid.slice(2, 8) === '758824') { + await stopBluetoothDevicesDiscovery() + clearTimeout(timeoutTimer) + clearInterval(timer) + if(uuid.slice(30, 32) === '00') { + resolve(Result.DeviceHasBeenReset) + } else if (uuid.slice(30, 32) === '01') { + const connectResult = await createBLEConnection(deviceList[i].deviceId) + resolve(connectResult) + } else { + resolve(Result.Fail) + } + break + } + } + } + } else { + resolve(queryResult) + } + }, 1000) + } else { + resolve(result) + } + }) +} + +// 蓝牙操作报错处理 +async function handleError (err, event) { + if (err.errCode === 10000) { + const result = await openBluetoothAdapter() + if (result.code === Result.Success.code) { + return await event() + } else { + return result + } + } else if (err.errCode === 10001) { + return Result.NotAvailableBluetooth + } else if (err.errno === 3) { + return Result.NotAvailableWeChatNearbyDevicesPermission + } else if (err.errno === 103) { + return Result.NotAvailableBluetoothPermission + } else if (err.errno === 1509008) { + return Result.NotAvailableWeChatLocationPermission + } else if (err.errMsg === 'openBluetoothAdapter:fail already opened') { + return Result.Success + } else { + return Result.Fail + } +} + +// 初始化蓝牙模块 +function openBluetoothAdapter() { + return new Promise((resolve) => { + uni.openBluetoothAdapter({ + success() { + resolve(Result.Success) + }, + async fail (err) { + resolve(await handleError(err)) + } + }) + }) +} + +// 关闭蓝牙模块 +function closeBluetoothAdapter() { + return new Promise((resolve) => { + uni.closeBluetoothAdapter({ + success() { + resolve(Result.Success) + }, + async fail (err) { + resolve(await handleError(err)) + } + }) + }) +} + +// 移除蓝牙适配器的全部监听 +function offBluetoothAdapterStateChange() { + uni.offBluetoothAdapterStateChange() +} + +// 监听蓝牙特征值改变 +export function onBLECharacteristicValueChange(callback) { + uni.onBLECharacteristicValueChange((res) => { + callback(res) + }) +} + +// 开始搜索附近的蓝牙设备 +function startBluetoothDevicesDiscovery() { + return new Promise((resolve) => { + uni.startBluetoothDevicesDiscovery({ + success() { + resolve(Result.Success) + }, + async fail (err) { + resolve(await handleError(err, startBluetoothDevicesDiscovery)) + } + }) + }) +} + +// 获取所有已发现的蓝牙设备 +function getBluetoothDevices() { + return new Promise((resolve) => { + uni.getBluetoothDevices({ + success(res) { + resolve(new Result(Result.Success.code, res.devices)) + }, + async fail () { + resolve(await handleError(err, getBluetoothDevices)) + } + }) + }) +} + +// 停止搜索附近的蓝牙设备 +function stopBluetoothDevicesDiscovery() { + return new Promise((resolve) => { + uni.stopBluetoothDevicesDiscovery({ + success() { + resolve(Result.Success) + }, + async fail () { + resolve(await handleError(err)) + } + }) + }) +} + +// 连接低功耗蓝牙设备 +function createBLEConnection(deviceId, reconnectNumber = 0) { + return new Promise((resolve) => { + uni.createBLEConnection({ + deviceId, + timeout: 10000, + async success () { + const res = await getBLEDeviceServicesAndCharacteristics(deviceId) + await notifyBLECharacteristicValueChange(deviceId, res.data.serviceId, res.data.notifyCharacteristicId) + resolve(res) + }, + async fail (err) { + if (err.errno === 1509007) { + const res = await getBLEDeviceServicesAndCharacteristics(deviceId) + await notifyBLECharacteristicValueChange(deviceId, res.data.serviceId, res.data.notifyCharacteristicId) + resolve(res) + } else if (err.errno === 1509001 && reconnectNumber < 1) { + resolve(Result.Fail) + } else if (reconnectNumber < 1) { + resolve(await createBLEConnection(deviceId, reconnectNumber + 1)) + } else { + resolve(Result.Fail) + } + } + }) + }) +} + +// 获取服务及对应特征值 +async function getBLEDeviceServicesAndCharacteristics (deviceId) { + const { code, data } = await getBLEDeviceServices(deviceId) + if (code === Result.Success.code) { + const { serviceId } = data + const { + code, + data: { notifyCharacteristicId, writeCharacteristicId } + } = await getBLEDeviceCharacteristics(deviceId, serviceId) + if (code === Result.Success.code) { + return new Result(Result.Success.code, { deviceId, serviceId, notifyCharacteristicId, writeCharacteristicId }) + } else { + return Result.Fail + } + } else { + return Result.Fail + } +} + +// 获取设备的服务 +function getBLEDeviceServices(deviceId) { + return new Promise((resolve) => { + uni.getBLEDeviceServices({ + deviceId, + success(res) { + let serviceId + for(let i = 0; i < res.services.length; i++) { + if(res.services[i].uuid.indexOf('FFF0') !== -1) { + serviceId = res.services[i].uuid + } + } + if(!serviceId) { + resolve(Result.Fail) + return + } + resolve(new Result(Result.Success.code, { serviceId })) + }, + fail() { + resolve(Result.Fail) + } + }) + }) +} + +// 获取服务的特征值 +function getBLEDeviceCharacteristics(deviceId, serviceId) { + return new Promise((resolve) => { + uni.getBLEDeviceCharacteristics({ + deviceId, + serviceId, + success(res) { + let notifyCharacteristicId + let writeCharacteristicId + for(let i = 0; i < res.characteristics.length; i++) { + const characteristic = res.characteristics[i] + if(characteristic.properties.notify) { + notifyCharacteristicId = characteristic.uuid + } + if(characteristic.properties.write) { + writeCharacteristicId = characteristic.uuid + } + } + if(notifyCharacteristicId && writeCharacteristicId) { + resolve(new Result(Result.Success.code, { notifyCharacteristicId, writeCharacteristicId })) + } else { + resolve(Result.Fail) + } + }, + fail() { + resolve(Result.Fail) + } + }) + }) +} + +// 订阅特征值 +function notifyBLECharacteristicValueChange(deviceId, serviceId, characteristicId) { + return new Promise((resolve) => { + uni.notifyBLECharacteristicValueChange({ + deviceId, + serviceId, + characteristicId, + state: true, + success() { + resolve(Result.Success) + }, + fail() { + resolve(Result.Fail) + } + }) + }) +} + +// 断开与低功耗蓝牙设备的连接 +export function closeBLEConnection(deviceId) { + return new Promise((resolve) => { + uni.closeBLEConnection({ + deviceId, + success() { + console.log('断开连接成功') + resolve(Result.Success) + }, + fail() { + console.log('断开连接失败') + resolve(Result.Fail) + } + }) + }) +} + +// 写入特征值 +export function writeBLECharacteristicValue(deviceId, serviceId, characteristicId, binaryData) { + return new Promise((resolve) => { + const count = Math.ceil(binaryData.length / 20) + let successCount = 0 + for(let i = 0; i < count; i++) { + const writeData = binaryData.slice(i * 20, i === (count - 1) ? binaryData.length : (i + 1) * 20) + uni.writeBLECharacteristicValue({ + deviceId, + serviceId, + characteristicId, + value: writeData.buffer, + success() { + successCount++ + if(successCount === count) { + resolve(Result.Success) + } + }, + fail() { + resolve(Result.Fail) + } + }) + } + }) +} diff --git a/env.js b/env.js new file mode 100644 index 0000000..47435d6 --- /dev/null +++ b/env.js @@ -0,0 +1,24 @@ +// 版本号 +export const version = '1.0.0' +// 构建号 +export const buildNumber = 1 + +// 环境配置 +export const configs = { + DEV: { + name: 'DEV', + baseUrl: 'https://dev.cloud.star-lock.cn/sdk' + }, + PRE: { + name: 'PRE', + baseUrl: 'https://pre.cloud.star-lock.cn' + }, + XHJ: { + name: 'XHJ', + baseUrl: 'https://cloud.star-lock.cn' + }, + SKY: { + name: 'SKY', + baseUrl: 'https://cloud.star-lock.cn' + } +} diff --git a/format.js b/format.js new file mode 100644 index 0000000..3bd8313 --- /dev/null +++ b/format.js @@ -0,0 +1,83 @@ +import { + md5 +} from 'js-md5' +import crc from 'crc' + +// 周数组转换 +export function convertWeekdaysToNumber(weekDay) { + let weekStr = '00000000' + + for (const day of weekDay) { + const index = day % 7 // 将周日的索引转换为0 + weekStr = weekStr.substring(0, index) + '1' + weekStr.substring(index + 1) + } + + // 倒序 weekStr + weekStr = weekStr.split('') + .reverse() + .join('') + + return parseInt(weekStr, 2) +} + +// 时间戳转二进制 +export function timestampToArray(timestamp) { + const array = new Uint8Array(4) + array[0] = (timestamp & 0xff000000) >> 24 + array[1] = (timestamp & 0xff0000) >> 16 + array[2] = (timestamp & 0xff00) >> 8 + array[3] = (timestamp & 0xff) + return array +} + +// md5加密 +export function md5Encrypt(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) + } + + md5Array.set(token, text.length) + md5Array.set(key, text.length + 4) + + const md5Text = md5(md5Array) + return new Uint8Array(md5Text.match(/.{1,2}/g) + .map(byte => parseInt(byte, 16))) +} + +// 生成包尾 头部数据+内容数据 +export function createPackageEnd(headArray, contentArray) { + // 拼接头部和内容 + let mergerArray = new Uint8Array(headArray.length + contentArray.length) + mergerArray.set(headArray) + 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 +} + +// 二进制转时间戳 +export function arrayToTimestamp(array) { + const timestamp = (array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3] + return timestamp >>> 0 +} + +// 二进制转字符串 +export function uint8ArrayToString(uint8Array) { + let str = '' + for (let i = 0; i < uint8Array.length; i++) { + if (uint8Array[i] !== 0) { + str += String.fromCharCode(uint8Array[i]) + } + } + return str +} diff --git a/request.js b/request.js new file mode 100644 index 0000000..3f436de --- /dev/null +++ b/request.js @@ -0,0 +1,104 @@ +import { getStorage, removeStorage } from '@/starCloud/storage' +import { useStarCloudStore } from '@/starCloud/starCloud' +import { Result } from '@/starCloud/basic' + +/* +* config +* baseUrl: 请求域名 +* url: 请求路径 +* method: 请求方法 +* header: 请求头 +* token: 请求token +* data: 请求参数 +* */ + +const request = (config) => { + const starCloud = useStarCloudStore() + let timer + return new Promise(async (resolve) => { + const baseConfig = starCloud.getConfig() + + const token = config?.token ? config.token : getStorage('starCloudToken') + // 请求地址 + const URL = config.baseUrl ? config.baseUrl + config.url : baseConfig.baseUrl + config.url + + // 默认请求头 + const headerDefault = { + version: baseConfig.version + '+' + baseConfig.buildNumber + } + const header = { + ...headerDefault, + ...config.header + } + const method = config.method || 'POST' + const data = { + ...config.data, + accessToken: token, + clientId: starCloud.clientId + } + const timestamp = new Date().getTime() + + // 超时处理 + timer = setTimeout(() => { + resolve(new Result(Result.Fail.code, {},'网络访问失败,请检查网络是否正常')) + }, 3200) + + uni.request({ + url: URL, + method, + header, + data, + timeout: 3000, + async success (res) { + const { statusCode, data } = res + if (timer) { + clearTimeout(timer) + } + if (statusCode === 200) { + const code = data.errcode + const message = data.errmsg + if (code === 10003) { + removeStorage('starCloudToken') + removeStorage('starCloudUser') + const { code } = await starCloud.login( + starCloud.accountInfo.username, + starCloud.accountInfo.password + ) + if(code === Result.Success.code) { + resolve(await request(config)) + } + } else { + resolve({ + code, + data: data.data, + message + }) + } + } else { + resolve(new Result(Result.Fail.code, {},'网络访问失败,请检查网络是否正常')) + } + }, + async fail (res) { + console.log('网络访问失败', res) + if (timer) { + clearTimeout(timer) + } + resolve(new Result(Result.Fail.code, {},'网络访问失败,请检查网络是否正常')) + }, + async complete (res) { + console.log(URL.substring(baseConfig.baseUrl.length + 1), { + env: baseConfig.name, + url: URL.substring(baseConfig.baseUrl.length + 1), + req: config?.data || {}, + code: res?.data?.errcode, + res: res?.data?.data, + token: header?.authorization || '', + message: res?.data?.errmsg, + duration: new Date().getTime() - timestamp + }) + } + }) + }) +} + +export default request diff --git a/starCloud.js b/starCloud.js new file mode 100644 index 0000000..2257827 --- /dev/null +++ b/starCloud.js @@ -0,0 +1,1013 @@ +import { defineStore } from 'pinia' +import { buildNumber, configs, version } from '@/starCloud/env' +import { + addCustomPassword, + getLockDetail, + getLockNetTokenRequest, + getOfflinePassword, + getServerDatetime, + getStarCloudToken, + getUserNoListRequest, + starCloudCreateUser, + updateLockUserNoRequest, updatePassword +} 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' +import { sm4 } from 'sm-crypto' + +/** + * 锁信息 + * @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, + // 清理用户 + cleanUser: 0x300C, + // 扩展命令 + 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() { + const { + code, + data, + message + } = await starCloudCreateUser({ + clientId: this.clientId, + clientSecret: this.clientSecret + }) + return new Result(code, data, message) + }, + // 登录星云 + async login(username, password) { + this.accountInfo = { + username, + password + } + setStorage('starCloudUser', {"username":"vridg_Hgn3uuO1Sh36Hc2oI","access_token":"Bh7fBK8gIIsHPmZJG6Jpr4ka0tNHbAVJ3i43v69a","uid":650,"refresh_token":"TguBYKgPu9T0b5V96opXzk0gGaj3hMTpHANVsc1y","scope":"user,key,room","token_type":"Bearer","expires_in":7349225}) + setStorage('starCloudToken', 'Bh7fBK8gIIsHPmZJG6Jpr4ka0tNHbAVJ3i43v69a') + + 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: username, + password: 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) + }, + // 选择锁 + async selectLock(lockId) { + const { + code, + data, + message + } = await getLockDetail({ + lockId + }) + if (code === Result.Success.code) { + const lockList = getStorage('lockList') + if(lockList) { + 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) + if(lockList) { + 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) + + // 获取并处理锁信息 + let { + uid: authUid, + keyId, + token, + bluetooth + } = this.lockInfo + let { uid } = this.userInfo + authUid = authUid.toString() + uid = uid.toString() + keyId = keyId.toString() + const name = bluetooth.bluetoothDeviceName + + // 获取用户列表 + const { + code: requestCode, + data: requestData + } = await getUserNoListRequest({ + 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 + + const md5Array = md5Encrypt(authUid + keyId, token || new Uint8Array([0, 0, 0, 0]), bluetooth.publicKey) + + contentArray.set(md5Array, 129 + userNoList.length) + + const cebArray = sm4.encrypt(contentArray, 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.cleanLockUser, disconnect) + }, + // 开门 + 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() + 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, 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 + 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) + }, + + + + // 获取联网token + async getNetToken() { + const { + code, + data, + message + } = await getLockNetTokenRequest({ + lockId: this.lockInfo.lockId + }) + return new Result(code, data, message) + }, + // 获取服务器时间 + async getServerTimestamp() { + const { + code, + data, + message + } = await getServerDatetime({}) + if (code === Result.Success.code) { + this.serverTimestamp = Math.ceil(data.date / 1000) + this.timeDifference = Math.ceil((data.date - new Date() + .getTime()) / 1000) + } + 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 + + 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) + 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 + + const md5Array = md5Encrypt(authUid + keyId, this.lockInfo.token || timestampToArray(startDate), + this.lockInfo.bluetooth.publicKey) + + contentArray.set(md5Array, 166) + + 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.addLockUser, disconnect, data) + }, + // 获取写入结果 + getWriteResult(request, disconnect = false, params) { + return new Promise(resolve => { + const getWriteResultTimer = setTimeout(() => { + resolve(Result.Fail) + }, 20000) + characteristicValueCallback = async (data) => { + // 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) + if(disconnect) { + await this.disconnectDevice() + } + console.log('写入结果', data, request, params) + resolve(data) + } + } + }) + }, + // 检查是否已添加为用户 + async checkLockUser(forceAdd = false) { + if (this.lockInfo.lockUserNo === 0 || forceAdd) { + const timestamp = Math.floor(new Date() + .getTime() / 1000) + const password = (Math.floor(Math.random() * 900000) + 100000) + .toString() + 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, + startDate: this.lockInfo.startDate === 0 ? timestamp : Math.floor(this.lockInfo.startDate / + 1000), + expireDate: this.lockInfo.endDate === 0 ? 0xffffffff : Math.floor(this.lockInfo.endDate / + 1000), + useCountLimit: this.lockInfo.keyType === 3 ? 1 : 0xffff, + isRound: this.lockInfo.keyType === 4 ? 1 : 0, + 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, + role: 0, + password + } + const addUserResult = await this.addLockUser(addUserParams) + console.log('添加用户蓝牙结果', addUserResult) + if (addUserResult.code === Result.Success.code) { + const { + code + } = await updateLockUserNoRequest({ + keyId: this.lockInfo.keyId, + lockUserNo: this.lockInfo.lockUserNo + }) + console.log('添加用户请求结果', code) + return Result.Success + } else if (addUserResult.code === Result.NotMoreKeyLock.code) { + console.log('用户达上限,开始清理用户') + const { + code: cleanCode + } = await this.cleanLockUser() + console.log('清理用户蓝牙结果', cleanCode) + if (cleanCode === Result.Success.code) { + return await this.checkLockUser() + } else { + return Result.Fail + } + } else if (addUserResult.code === Result.ReadyHasKeyLock.code) { + return Result.Success + } else { + return Result.Fail + } + } else { + return Result.Success + } + }, + // 更新锁信息 + updateLockInfo(lockInfo) { + this.lockInfo = { + ...this.lockInfo, + ...lockInfo + } + }, + // 特征值变化回调 + listenCharacteristicValue(res) { + if (res.deviceId === this.lockInfo.deviceId) { + let binaryData = new Uint8Array(res.value) + if (binaryData[0] === 0xEF && binaryData[1] === 0x01 && binaryData[2] === 0xEE && binaryData[3] === + 0x02) { + length = binaryData[8] * 256 + binaryData[9] + if (length + 14 > binaryData.length) { + completeArray = binaryData + } else { + this.parsingCharacteristicValue(binaryData).then(() => {}) + } + } 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 + } + } + } + } + }, + // 解析特征值 + async parsingCharacteristicValue (binaryData) { + // 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)), + timezoneOffset: new Date() + .getTimezoneOffset() * 60 + } + this.updateLockInfo({ + 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]])), + 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) { + if(decrypted[11] === Result.Success.code) { + 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) { + characteristicValueCallback(new Result(addResult.code, { + pwdNo: pwdNo, + keyboardPwdId: addResult.data.keyboardPwdId, + keyboardPwd: addResult.data.keyboardPwd + })) + } else { + characteristicValueCallback(new Result(addResult.code, addResult.data, addResult.message)) + } + } 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 { + characteristicValueCallback(new Result(updateResult.code, updateResult.data, updateResult.message)) + } + } + } else { + characteristicValueCallback(new Result(decrypted[11])) + } + } else { + characteristicValueCallback(new Result(decrypted[2])) + } + break + } + 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:明文,1:AES128,2:SM4(事先约定密钥),3:SM4(设备指定密钥) + * originalLength 原始数据长度 + * */ + createPackageHeader(encryptionType, originalLength) { + // 头部数据 + let headArray = new Uint8Array(12) + + // 固定包头 + headArray[0] = 0xEF + headArray[1] = 0x01 + headArray[2] = 0xEE + 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) + }, + } +}) diff --git a/storage.js b/storage.js new file mode 100644 index 0000000..b6a8fe9 --- /dev/null +++ b/storage.js @@ -0,0 +1,18 @@ +import { useStarCloudStore } from '@/starCloud/starCloud' + +export function setStorage(key, value) { + return uni.setStorageSync(getPrefix() + key, value) +} + +export function getStorage(key) { + return uni.getStorageSync(getPrefix() + key) +} + +export function removeStorage(key) { + return uni.removeStorageSync(getPrefix() + key) +} + +function getPrefix() { + const starCloud = useStarCloudStore() + return `${ starCloud.envVersion }:` +}