From 9bc62bc6fbb520fa46fd434315ef00c7429e2bca Mon Sep 17 00:00:00 2001 From: liyi Date: Thu, 10 Apr 2025 15:01:55 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E5=A2=9E=E5=8A=A0=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=8A=9F=E8=83=BD=E9=A1=B9=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=EF=BC=88=E5=B8=A6=E5=8F=82=E6=95=B0=EF=BC=89=E3=80=81=E8=AF=BB?= =?UTF-8?q?=E5=8F=96=E6=94=AF=E6=8C=81=E5=8A=9F=E8=83=BD=E9=A1=B9=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E3=80=81=E8=BF=9C=E7=A8=8B=E5=BC=80=E9=94=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api.js | 40 +++ common.js | 143 ++++++++- constant.js | 20 ++ star-cloud/generalExtend.js | 240 ++++++++++++--- star-cloud/lock.js | 576 +++++++++++++++++++----------------- star-cloud/password.js | 474 +++++++++++++++-------------- uni/index.js | 94 +++--- 7 files changed, 1020 insertions(+), 567 deletions(-) diff --git a/api.js b/api.js index c0dc4f3..60dd44b 100644 --- a/api.js +++ b/api.js @@ -738,4 +738,44 @@ export function getRemoteListRequest(data) { method: 'POST', data }) +} + +/** + * 远程开锁 + * @param data.lockId 锁id + * @returns {Promise} + */ +export function remoteUnLockRequest(data) { + return request({ + url: '/v1/gateway/unlock', + method: 'POST', + data + }) +} + + +/** + * 获取锁设置 + * @param data.lockId 锁id + * @returns {Promise} + */ +export function getLockSettingRequest(data) { + return request({ + url: '/v1/lockSetting/getLockSetting', + method: 'POST', + data + }) +} + +/** + * 更新锁设置 + * @param data.lockId 锁id + * @returns {Promise} + */ +export function updateLockSettingRequest(data) { + return request({ + url: '/v1/lockSetting/updateLockSetting', + method: 'POST', + data + }) } \ No newline at end of file diff --git a/common.js b/common.js index fd3fc14..39b8817 100644 --- a/common.js +++ b/common.js @@ -9,7 +9,7 @@ import { uint8ArrayToString } from './format' import {configs} from './env' -import {cmdIds, Result, subCmdIds} from './constant' +import {cmdIds, Result, subCmdIds, supportFunctionsFeatureBit} from './constant' import { closeBLEConnection, searchAndConnectDevice, @@ -34,7 +34,7 @@ import { updateElectricQuantityRequest, updateFaceRequest, updateFingerprintRequest, - updateIcCardRequest, + updateIcCardRequest, updateLockSettingRequest, updateLockUserNoRequest, updatePalmVeinRequest, updatePasswordRequest, updateRemoteRequest, uploadRecordRequest @@ -788,7 +788,6 @@ export async function parsingCharacteristicValue(binaryData) { const cmdId = decrypted[0] * 256 + decrypted[1] - switch (cmdId) { case cmdIds.getLockStatus: if (decrypted[2] === Result.Success.code) { @@ -992,6 +991,8 @@ export async function parsingCharacteristicValue(binaryData) { this.characteristicValueCallback(new Result(decrypted[2])) break; } + } else { + this.characteristicValueCallback(new Result(decrypted[2])) } break; case subCmdIds.registerCardConfirm: @@ -1018,6 +1019,8 @@ export async function parsingCharacteristicValue(binaryData) { await this.disconnectDevice() break; } + } else { + this.characteristicValueCallback(new Result(decrypted[2])) } break; case subCmdIds.registerFingerprint: @@ -1063,6 +1066,8 @@ export async function parsingCharacteristicValue(binaryData) { this.characteristicValueCallback(new Result(decrypted[2])) break; } + } else { + this.characteristicValueCallback(new Result(decrypted[2])) } break; case subCmdIds.registerFingerprintProcess: @@ -1092,6 +1097,8 @@ export async function parsingCharacteristicValue(binaryData) { // 断开蓝牙连接 await this.disconnectDevice() } + } else { + this.characteristicValueCallback(new Result(decrypted[2])) } break; case subCmdIds.registerFace: @@ -1135,6 +1142,8 @@ export async function parsingCharacteristicValue(binaryData) { this.characteristicValueCallback(new Result(decrypted[2])) break; } + } else { + this.characteristicValueCallback(new Result(decrypted[2])) } break; case subCmdIds.registerFaceProcess: @@ -1161,6 +1170,8 @@ export async function parsingCharacteristicValue(binaryData) { emitRegisterFaceConfirmEvent(addResult) // 断开蓝牙连接 await this.disconnectDevice() + } else { + this.characteristicValueCallback(new Result(decrypted[2])) } break; case subCmdIds.registerPalmVein: @@ -1202,6 +1213,8 @@ export async function parsingCharacteristicValue(binaryData) { this.characteristicValueCallback(new Result(decrypted[2])) break; } + } else { + this.characteristicValueCallback(new Result(decrypted[2])) } break; case subCmdIds.registerPalmVeinConfirm: @@ -1228,6 +1241,8 @@ export async function parsingCharacteristicValue(binaryData) { await this.disconnectDevice() break; } + } else { + this.characteristicValueCallback(new Result(decrypted[2])) } break; case subCmdIds.registerRemote: @@ -1267,6 +1282,8 @@ export async function parsingCharacteristicValue(binaryData) { this.characteristicValueCallback(new Result(decrypted[2])) break; } + } else { + this.characteristicValueCallback(new Result(decrypted[2])) } break; case subCmdIds.registerRemoteConfirm: @@ -1293,8 +1310,67 @@ export async function parsingCharacteristicValue(binaryData) { await this.disconnectDevice() break; } + } else { + this.characteristicValueCallback(new Result(decrypted[2])) } break; + case subCmdIds.supportFunctionsWithParams: + // 收到锁版回复判断操作类型进行对应api操作 + if (decrypted[2] === Result.Success.code) { + const {data, featureEnable} = this.requestParams + console.log('this.requestParams', this.requestParams) + let updateResult = new Result(); + switch (this.requestParams.featureBit) { + case supportFunctionsFeatureBit.passageMode: + updateResult = await updateLockSettingRequest({ + lockId: this.lockInfo.lockId, + passageMode: data.passageMode, + passageModeConfig: [ + { + startTime: data.startTime, + endTime: data.endTime, + isAllDay: data.isAllDay, + weekDays: data.weekDay, + autoUnlock: data.autoUnlock, + } + ], + }) + break; + case supportFunctionsFeatureBit.automaticLocking: + updateResult = await updateLockSettingRequest({ + lockId: this.lockInfo.lockId, + autoLock: data > 0 ? 1 : 0, + autoLockSecond: data, + }) + break; + case supportFunctionsFeatureBit.antiPrySwitch: + updateResult = await updateLockSettingRequest({ + lockId: this.lockInfo.lockId, + antiPrySwitch: featureEnable + }) + break; + case supportFunctionsFeatureBit.lockSound: + updateResult = await updateLockSettingRequest({ + lockId: this.lockInfo.lockId, + lockSound: data > 0 ? 1 : 0, + lockSoundVolume: data, + }) + break; + default: + this.characteristicValueCallback(new Result(decrypted[2])) + break; + } + this.characteristicValueCallback(new Result(updateResult.code)) + } else { + this.characteristicValueCallback(new Result(decrypted[2])) + } + break; + case subCmdIds.supportFunctions: + this.updateLockInfo({ + token: decrypted.slice(5, 9) + }) + this.characteristicValueCallback(new Result(decrypted[2])) + break; default: break } @@ -1419,6 +1495,7 @@ export async function disconnectDevice() { return await closeBLEConnection(this.lockInfo.deviceId) } + /** * 用于判断时间戳是否是秒级别的,如果是的话则补充到毫秒级别 * @param timestamp 时间戳 @@ -1428,4 +1505,64 @@ export async function disconnectDevice() { export function _convertToMilliseconds(timestamp) { if (!timestamp) return timestamp; return timestamp.toString().length === 10 ? timestamp * 1000 : timestamp; +} + +/** + * 检查并返回具体哪个参数为空 + * @param {Object} params - 参数对象 + * @param {Array} requiredFields - 必填字段列表 + * @returns {string | null} - 如果有字段为空,则返回错误消息;否则返回null + */ +export function checkRequiredFields(params, requiredFields) { + for (let field of requiredFields) { + if (params[field] === undefined || params[field] === null) { + return `${field} 不能为空`; + } + } + return null; +} + +/** + * 辅助函数:将分钟时间转换为两个字节的数组 + * @param minutes + * @returns {(number|number)[]} + */ +export function convertTimeToBytes(minutes) { + return [ + Math.floor(minutes / 256), // 高字节 + minutes % 256 // 低字节 + ]; +} + +/** + * 二进制字符串转换为十进制数字数组 + * 例如 '0111110' 会被转换为 [1, 2, 3, 4, 5](表示周一到周五) + * @param weekdayBit + * @returns {*[]} + */ +export function convertWeekdayBitToArray(weekdayBit) { + const weekdays = []; + const bits = weekdayBit.split(''); + bits.forEach((bit, index) => { + if (bit === '1') { + weekdays.push(index); + } + }); + return weekdays; +} + +/** + * 十进制数字数组转为二进制字符串 + * 例如 将 [1,2,3,4,5] 转换回 '0111110' + * @param weekdays + * @returns {string} + */ +export function convertWeekdayArrayToBit(weekdays) { + const bits = new Array(7).fill('0'); + weekdays.forEach(day => { + if (day >= 0 && day < 7) { + bits[day] = '1'; + } + }); + return bits.join(''); } \ No newline at end of file diff --git a/constant.js b/constant.js index 4081898..689448b 100644 --- a/constant.js +++ b/constant.js @@ -1,4 +1,6 @@ // 命令ID +import {updateAutomaticLocking, updateSupportFunctionsWithParams} from "./star-cloud/generalExtend.js"; + export const cmdIds = { // 获取公钥 getPublicKey: 0x3090, @@ -62,6 +64,24 @@ export const subCmdIds = { registerPalmVeinConfirm: 43, // 注册掌纹取消 registerPalmVeinCancel: 44, + // 设置支持功能(带参数) + supportFunctionsWithParams: 72, + // 设置支持功能 + supportFunctions: 70, +} + +// 支持项对于功能位 +export const supportFunctionsFeatureBit = { + // 自动闭锁 + automaticLocking: 29, + // 支持防撬开关配置(启用/禁用) + antiPrySwitch: 30, + // 支持重置键配置(启用/禁用) + resetSwitch: 30, + // 支持语音提示管理(音量大小/禁用) + lockSound: 33, + // 常开模式 + passageMode: 50 } // 回调事件key昵称 diff --git a/star-cloud/generalExtend.js b/star-cloud/generalExtend.js index 539354b..c1de6ea 100644 --- a/star-cloud/generalExtend.js +++ b/star-cloud/generalExtend.js @@ -1,5 +1,5 @@ import {searchAndConnectDevice, writeBLECharacteristicValue} from "../uni/basic.js"; -import {cmdIds, Result, subCmdIds} from '../constant' +import {cmdIds, Result, subCmdIds, supportFunctionsFeatureBit} from '../constant' import {convertWeekdaysToNumber, createPackageEnd, md5Encrypt, parseTimeToList, timestampToArray} from "../format.js"; import {sm4} from "sm-crypto"; import { @@ -11,26 +11,11 @@ import { clearAllIcCard, deleteIcCardRequest, getFaceListRequest, getFingerprintListRequest, - getIcCardListRequest, getPalmVeinListRequest, getRemoteListRequest, + getIcCardListRequest, getLockSettingRequest, getPalmVeinListRequest, getRemoteListRequest, updateIcCardRequest } from "../api.js"; -import {_convertToMilliseconds} from "../common.js"; - -/** - * 检查并返回具体哪个参数为空 - * @param {Object} params - 参数对象 - * @param {Array} requiredFields - 必填字段列表 - * @returns {string | null} - 如果有字段为空,则返回错误消息;否则返回null - */ -function _checkRequiredFields(params, requiredFields) { - for (let field of requiredFields) { - if (params[field] === undefined || params[field] === null) { - return `${field} 不能为空`; - } - } - return null; -} +import {_convertToMilliseconds, checkRequiredFields, convertTimeToBytes, convertWeekdayArrayToBit} from "../common.js"; /** @@ -45,7 +30,7 @@ function _checkRequiredFields(params, requiredFields) { * @param {number} params.isAdmin - 是否管理员,整型,1 表示是,0 表示否 * @param {number} params.isForce - 是否胁迫,整型,1 表示是,0 表示否 * @param {number} params.isRound - 是否循环,整型,1 表示是,0 表示否 - * @param {array} params.weekDays - 循环周期,数组,Bit0 -- 6 置位分别代表周日 -- 周六,例如:循环星期一、星期二、星期四,对应为:[1,2,4] + * @param {array} params.weekDay - 循环周期,数组,Bit0 -- 6 置位分别代表周日 -- 周六,例如:循环星期一、星期二、星期四,对应为:[1,2,4] * @param {number} params.startDate - 生效日期,时间戳,永久则填0 * @param {number} params.endDate - 失效日期,时间戳,永久则填0 * @param {string} params.startTime - 生效时间,字符串,例如:'00:00' @@ -81,7 +66,7 @@ function _checkRequiredFields(params, requiredFields) { export async function registerExtendedProducts(params) { const cardRequiredFields = ['type', 'keyId', 'uid', 'userCountLimit', 'operate', 'isAdmin', 'isForce', 'isRound', 'startDate', 'endDate']; - const missingField = _checkRequiredFields(params, cardRequiredFields); + const missingField = checkRequiredFields(params, cardRequiredFields); if (missingField) { return new Result(Result.NotMoreData, null, `参数信息不完整: ${missingField}`); } @@ -91,7 +76,7 @@ export async function registerExtendedProducts(params) { // 注册卡片时的参数校验 if (params.operate === 0) { const cardRequiredFields = ['cardName', 'cardType', 'cardNumber']; - const missingField = _checkRequiredFields(params, cardRequiredFields); + const missingField = checkRequiredFields(params, cardRequiredFields); if (missingField) { return new Result(Result.NotMoreData, null, `卡片信息不完整: ${missingField}`); } @@ -114,7 +99,7 @@ export async function registerExtendedProducts(params) { if (params.operate === 2) { cardRequiredFields.push('cardNumber') } - const missingField = _checkRequiredFields(params, cardRequiredFields); + const missingField = checkRequiredFields(params, cardRequiredFields); if (missingField) { return new Result(Result.NotMoreData, null, `卡片信息不完整: ${missingField}`); } @@ -125,7 +110,7 @@ export async function registerExtendedProducts(params) { if (params.type === 'fingerprint') { if (params.operate === 0) { const cardRequiredFields = ['fingerprintName', 'fingerprintNumber', 'fingerprintType']; - const missingField = _checkRequiredFields(params, cardRequiredFields); + const missingField = checkRequiredFields(params, cardRequiredFields); if (missingField) { return new Result(Result.NotMoreData, null, `指纹信息不完整: ${missingField}`); } @@ -149,7 +134,7 @@ export async function registerExtendedProducts(params) { cardRequiredFields.push('deleteType') cardRequiredFields.push('fingerprintNumber') } - const missingField = _checkRequiredFields(params, cardRequiredFields); + const missingField = checkRequiredFields(params, cardRequiredFields); if (missingField) { return new Result(Result.NotMoreData, null, `指纹信息不完整: ${missingField}`); } @@ -160,7 +145,7 @@ export async function registerExtendedProducts(params) { if (params.type === 'face') { if (params.operate === 0) { const cardRequiredFields = ['faceName', 'faceNumber', 'faceType']; - const missingField = _checkRequiredFields(params, cardRequiredFields); + const missingField = checkRequiredFields(params, cardRequiredFields); if (missingField) { return new Result(Result.NotMoreData, null, `人脸信息不完整: ${missingField}`); } @@ -183,7 +168,7 @@ export async function registerExtendedProducts(params) { if (params.operate === 2) { cardRequiredFields.push('faceNumber') } - const missingField = _checkRequiredFields(params, cardRequiredFields); + const missingField = checkRequiredFields(params, cardRequiredFields); if (missingField) { return new Result(Result.NotMoreData, null, `人脸信息不完整: ${missingField}`); } @@ -194,7 +179,7 @@ export async function registerExtendedProducts(params) { if (params.type === 'palmVein') { if (params.operate === 0) { const cardRequiredFields = ['palmVeinName', 'palmVeinNumber', 'palmVeinType']; - const missingField = _checkRequiredFields(params, cardRequiredFields); + const missingField = checkRequiredFields(params, cardRequiredFields); if (missingField) { return new Result(Result.NotMoreData, null, `掌静脉信息不完整: ${missingField}`); } @@ -217,7 +202,7 @@ export async function registerExtendedProducts(params) { if (params.operate === 2) { cardRequiredFields.push('palmVeinNumber') } - const missingField = _checkRequiredFields(params, cardRequiredFields); + const missingField = checkRequiredFields(params, cardRequiredFields); if (missingField) { return new Result(Result.NotMoreData, null, `掌静脉信息不完整: ${missingField}`); } @@ -228,7 +213,7 @@ export async function registerExtendedProducts(params) { if (params.type === 'remote') { if (params.operate === 0) { const cardRequiredFields = ['remoteName', 'remoteNumber', 'remoteType']; - const missingField = _checkRequiredFields(params, cardRequiredFields); + const missingField = checkRequiredFields(params, cardRequiredFields); if (missingField) { return new Result(Result.NotMoreData, null, `遥控信息不完整: ${missingField}`); } @@ -251,7 +236,7 @@ export async function registerExtendedProducts(params) { if (params.operate === 2) { cardRequiredFields.push('remoteNumber') } - const missingField = _checkRequiredFields(params, cardRequiredFields); + const missingField = checkRequiredFields(params, cardRequiredFields); if (missingField) { return new Result(Result.NotMoreData, null, `遥控信息不完整: ${missingField}`); } @@ -263,8 +248,6 @@ export async function registerExtendedProducts(params) { // 操作后不断开蓝牙 params.disconnect = false; - console.log('params', params) - let { type, keyId, @@ -274,7 +257,7 @@ export async function registerExtendedProducts(params) { userCountLimit, isForce, isRound, - weekDays, + weekDay, startDate, endDate, startTime, @@ -381,7 +364,7 @@ export async function registerExtendedProducts(params) { contentArray.set(this.lockInfo.token || new Uint8Array([0, 0, 0, 0]), 71) contentArray[75] = isRound - contentArray[76] = convertWeekdaysToNumber(weekDays) + contentArray[76] = convertWeekdaysToNumber(weekDay) contentArray.set(timestampToArray(startDate), 77) contentArray.set(timestampToArray(endDate), 81) @@ -511,6 +494,195 @@ export async function registerExtendedProductsCancel(params) { packageArray) } + +/** + * 更新支持功能项设置(带参数) + * + * @param {Object} params - 所需参数 + * @param {Object} params.accountInfo - 用户信息 + * @param {Number} params.featureBit - 支持功能对应的位 + * @param {boolean} params.withParams - 是否携带参数 + * @param {Object} params.data - 是否携带参数 + * @param {Number} params.featureEnable - 不携带参数时的开关:1-开,0-关 + */ +export async function updateSupportFunctionsWithParams(params) { + // 需要校验的参数 + const baseRequiredFields = [ + 'accountInfo', + 'featureBit', + 'withParams', + ]; + + // 定义功能位对应的必填字段映射 + const featureBitFields = { + [supportFunctionsFeatureBit.passageMode]: [ + 'passageMode', + 'startTime', + 'endTime', + 'isAllDay', + 'weekDay', + 'autoUnlock' + ] + }; + + // 根据operate值动态添加必填字段 + let cardRequiredFields = [...baseRequiredFields]; + if (params && params.withParams && params.withParams === true) { + cardRequiredFields.push('data'); + // 如果存在对应的功能位字段配置,则添加相应字段 + if (featureBitFields[params.featureBit]) { + const dataFields = featureBitFields[params.featureBit]; + for (const field of dataFields) { + if (params.data === undefined || params.data[field] === undefined) { + return new Result(Result.NotMoreData, null, `data参数信息不完整: ${field}`); + } + } + } + } else if (params && params.withParams && params.withParams === false) { + cardRequiredFields.push('featureEnable'); + } + + const missingField = checkRequiredFields(params, cardRequiredFields); + if (missingField) { + return new Result(Result.NotMoreData, null, `参数信息不完整: ${missingField}`); + } + + // 深拷贝一份参数赋值 + this.requestParams = JSON.parse(JSON.stringify(params)) + + // 转换参数 + if (params && params.withParams && params.withParams === true && params.data) { + try { + switch (params.featureBit) { + case supportFunctionsFeatureBit.passageMode: + const {passageMode, startTime, endTime, isAllDay, weekDay, autoUnlock} = params.data + const startTimeBytes = convertTimeToBytes(startTime); + const endTimeBytes = convertTimeToBytes(endTime); + const weekDayBit = parseInt(String(convertWeekdayArrayToBit(weekDay)), 2); + params.data = [ + passageMode, + ...startTimeBytes, + ...endTimeBytes, + isAllDay, + weekDayBit, + autoUnlock + ] + break; + default: + params.data = [params.data] + break; + } + console.log('转换后的参数:', params.data) + } catch (e) { + return new Result(Result.NotMoreData, null, `参数转换时异常,请检查参数格式: ${e}`); + } + } + + + // 设置执行账号 + 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 + } + + let {featureBit, data, withParams, featureEnable} = params + + const uid = this.accountInfo.uid.toString() + const keyId = this.lockInfo.keyId.toString() + + // 确保data是数组形式 + let dataArray = Array.isArray(data) ? data : [data] + + let length = 2 + 1 + 1 + 40 + 20 + 4 + 1 + 16 + + if (withParams) { + length += 2 + dataArray.length + } else { + length += 2 + } + + const headArray = this.createPackageHeader(3, length) + const contentArray = new Uint8Array(length) + + contentArray[0] = cmdIds.expandCmd / 256 + contentArray[1] = cmdIds.expandCmd % 256 + + contentArray[2] = withParams ? subCmdIds.supportFunctionsWithParams : subCmdIds.supportFunctions + + 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] = featureBit + + if (withParams) { + contentArray[65] = dataArray.length + contentArray.set(new Uint8Array(dataArray), 66) + } else { + contentArray[65] = featureEnable + } + + contentArray.set( + this.lockInfo.token || new Uint8Array([0, 0, 0, 0]), + withParams ? 66 + dataArray.length : 66 + ) + + contentArray[withParams ? 70 + dataArray.length : 70] = 16 + + const md5Array = md5Encrypt( + keyId + uid, + this.lockInfo.token || new Uint8Array([0, 0, 0, 0]), + this.lockInfo.bluetooth.signKey + ) + + contentArray.set(md5Array, withParams ? 71 + dataArray.length : 71) + console.log('加密前:', Array.from(contentArray)) + + const cebArray = sm4.encrypt(contentArray, this.lockInfo.bluetooth.privateKey, { + mode: 'ecb', + output: 'array' + }) + + const packageArray = createPackageEnd(headArray, cebArray) + + await writeBLECharacteristicValue(this.lockInfo.deviceId, + this.lockInfo.serviceId, + this.lockInfo.writeCharacteristicId, + packageArray) + + return this.getWriteResult(this.updateSupportFunctionsWithParams, params) +} + +/** + * 读取支持功能项设置 + * @param params + * @param {Number} params.lockId 锁id (必填) + * @returns {Promise} + */ +export async function readSupportFunctionsSetting(params){ + return await getLockSettingRequest(params) +} + /** * 获取Ic卡列表 * @param params.lockId 锁id (必填) diff --git a/star-cloud/lock.js b/star-cloud/lock.js index 60389e3..454e351 100644 --- a/star-cloud/lock.js +++ b/star-cloud/lock.js @@ -1,9 +1,9 @@ -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 {sm4} from 'sm-crypto' +import {cmdIds, Result} from '../constant' +import {searchAndConnectDevice, writeBLECharacteristicValue} from '../uni/basic' +import {createPackageEnd, md5Encrypt, timestampToArray} from '../format' +import {getLockDetailRequest, getLockSettingDataRequest, remoteUnLockRequest} from '../api' +import {getStorage, setStorage} from '../export' import log from '../log' /** @@ -14,45 +14,45 @@ import log from '../log' * @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 {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 = {} + 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) + } + } } - 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) + return new Result(code, data, message) } /** @@ -64,204 +64,204 @@ export async function selectLock(params) { * @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) + const {type} = params 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' + ...new Result( + Result.Success.code, + { + lockName: this.lockInfo.bluetooth.bluetoothDeviceName, + lockId: this.lockInfo.lockId, + uid: params.uid, + time: new Date().getTime() + }, + `开始开门` + ), + name: 'openDoor' }) - if (searchResult.code !== Result.Success.code) { - return searchResult + + // 设置执行账号 + const result = await this.login(params.uid) + if (result.code !== Result.Success.code) { + return result } - this.updateLockInfo(searchResult.data) - } - // 检查是否已添加为用户 - const checkResult = await this.checkLockUser() - if (checkResult.code !== Result.Success.code) { - return checkResult - } + 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' + }) - 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' - }) + // 确认设备连接正常 + 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) + } - // 是否需要联网 - let onlineToken = '' - if (this.lockInfo.lockSetting.appUnlockOnline) { - const result = await this.getNetToken() - if (result.code === Result.Success.code) { - onlineToken = result.data.token + // 检查是否已添加为用户 + 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 { - return result + openMode = this.lockInfo.lockSetting.appUnlockOnline ? 1 : 0 } - } - 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' - }) + const name = this.lockInfo.bluetooth.bluetoothDeviceName + const uid = this.accountInfo.uid.toString() + const openTime = Math.ceil(new Date().getTime() / 1000) + this.timeDifference - // 开门方式 - let openMode - if (type === 'close') { - openMode = this.lockInfo.lockSetting.appUnlockOnline ? 33 : 32 - } else { - openMode = this.lockInfo.lockSetting.appUnlockOnline ? 1 : 0 - } + const length = 2 + 40 + 20 + 1 + 4 + 4 + 1 + 16 + 16 + const headArray = this.createPackageHeader(3, length) - const name = this.lockInfo.bluetooth.bluetoothDeviceName - const uid = this.accountInfo.uid.toString() - const openTime = Math.ceil(new Date().getTime() / 1000) + this.timeDifference + const contentArray = new Uint8Array(length) + contentArray[0] = cmdIds.openDoor / 256 + contentArray[1] = cmdIds.openDoor % 256 - const length = 2 + 40 + 20 + 1 + 4 + 4 + 1 + 16 + 16 - const headArray = this.createPackageHeader(3, length) + for (let i = 0; i < name.length; i++) { + contentArray[i + 2] = name.charCodeAt(i) + } - const contentArray = new Uint8Array(length) - contentArray[0] = cmdIds.openDoor / 256 - contentArray[1] = cmdIds.openDoor % 256 + for (let i = 0; i < uid.length; i++) { + contentArray[i + 42] = uid.charCodeAt(i) + } - for (let i = 0; i < name.length; i++) { - contentArray[i + 2] = name.charCodeAt(i) - } + contentArray[62] = openMode - for (let i = 0; i < uid.length; i++) { - contentArray[i + 42] = uid.charCodeAt(i) - } + contentArray.set(timestampToArray(openTime), 63) - contentArray[62] = openMode + console.log('开门时token', this.lockInfo.token) - contentArray.set(timestampToArray(openTime), 63) + contentArray.set(this.lockInfo.token || timestampToArray(openTime), 67) - console.log('开门时token', this.lockInfo.token) + contentArray[71] = 16 - contentArray.set(this.lockInfo.token || timestampToArray(openTime), 67) + const md5Array = md5Encrypt( + name + uid, + this.lockInfo.token || timestampToArray(openTime), + this.lockInfo.bluetooth.signKey + ) - contentArray[71] = 16 + contentArray.set(md5Array, 72) - const md5Array = md5Encrypt( - name + uid, - this.lockInfo.token || timestampToArray(openTime), - this.lockInfo.bluetooth.signKey - ) + for (let i = 0; i < onlineToken.length; i++) { + contentArray[i + 88] = onlineToken.charCodeAt(i) + } - contentArray.set(md5Array, 72) + const cebArray = sm4.encrypt(contentArray, this.lockInfo.bluetooth.privateKey, { + mode: 'ecb', + output: 'array' + }) - for (let i = 0; i < onlineToken.length; i++) { - contentArray[i + 88] = onlineToken.charCodeAt(i) - } + const packageArray = createPackageEnd(headArray, cebArray) - const cebArray = sm4.encrypt(contentArray, this.lockInfo.bluetooth.privateKey, { - mode: 'ecb', - output: 'array' - }) + 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 packageArray = createPackageEnd(headArray, cebArray) + const writeResult = await writeBLECharacteristicValue( + this.lockInfo.deviceId, + this.lockInfo.serviceId, + this.lockInfo.writeCharacteristicId, + packageArray + ) - 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' - }) + if (writeResult.code !== Result.Success.code) { + return writeResult + } - const writeResult = await writeBLECharacteristicValue( - this.lockInfo.deviceId, - this.lockInfo.serviceId, - this.lockInfo.writeCharacteristicId, - packageArray - ) + 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' + }) - 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) + return this.getWriteResult(this.openDoor, params) } /** @@ -270,73 +270,73 @@ export async function openDoor(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 + // 设置执行账号 + 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) } - this.updateLockInfo(searchResult.data) - } - // 检查是否已添加为用户 - const checkResult = await this.checkLockUser() - if (checkResult.code !== Result.Success.code) { - return checkResult - } + // 检查是否已添加为用户 + const checkResult = await this.checkLockUser() + if (checkResult.code !== Result.Success.code) { + return checkResult + } - const { - token, - bluetooth: { publicKey, privateKey } - } = this.lockInfo + const { + token, + bluetooth: {publicKey, privateKey} + } = this.lockInfo - const authUid = this.lockInfo.uid.toString() - const name = this.lockInfo.bluetooth.bluetoothDeviceName + 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) + 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 + 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 < 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 + 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 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 cebArray = sm4.encrypt(contentArray, privateKey, { + mode: 'ecb', + output: 'array' + }) - const packageArray = createPackageEnd(headArray, cebArray) + const packageArray = createPackageEnd(headArray, cebArray) - const writeResult = await writeBLECharacteristicValue( - this.lockInfo.deviceId, - this.lockInfo.serviceId, - this.lockInfo.writeCharacteristicId, - packageArray - ) + const writeResult = await writeBLECharacteristicValue( + this.lockInfo.deviceId, + this.lockInfo.serviceId, + this.lockInfo.writeCharacteristicId, + packageArray + ) - if (writeResult.code !== Result.Success.code) { - return writeResult - } + if (writeResult.code !== Result.Success.code) { + return writeResult + } - return this.getWriteResult(this.deleteLock, params) + return this.getWriteResult(this.deleteLock, params) } /** @@ -347,19 +347,37 @@ export async function deleteLock(params) { * @returns {Promise} */ export async function getLockSupportFeatures(params) { - const { lockId } = params + const {lockId} = params - // 设置执行账号 - const result = await this.login(params.uid) - if (result.code !== Result.Success.code) { - return result - } + // 设置执行账号 + 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) + 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) +} + +/** + * 远程开锁 + * @param params + * @param {Number} params.lockId 锁 Id + * @returns {Promise} + */ +export async function remoteUnLock(params) { + // 设置执行账号 + const result = await this.login(params.uid) + if (result.code !== Result.Success.code) { + return result + } + + return await remoteUnLockRequest({ + lockId: params.lockId, + }) } diff --git a/star-cloud/password.js b/star-cloud/password.js index 6f349b2..1650c21 100644 --- a/star-cloud/password.js +++ b/star-cloud/password.js @@ -1,10 +1,12 @@ -import { sm4 } from 'sm-crypto' -import { cmdIds, Result, subCmdIds } from '../constant' -import { searchAndConnectDevice, writeBLECharacteristicValue } from '../uni/basic' -import { createPackageEnd, md5Encrypt, timestampToArray } from '../format' -import { checkPasswordRequest, getOfflinePasswordRequest } from '../api' +import {sm4} from 'sm-crypto' +import {cmdIds, Result, subCmdIds} from '../constant' +import {searchAndConnectDevice, writeBLECharacteristicValue} from '../uni/basic' +import {createPackageEnd, md5Encrypt, timestampToArray} from '../format' +import {checkPasswordRequest, getOfflinePasswordRequest} from '../api' import {getConfig} from "../common.js"; import StarCloud from "../star-cloud.js"; +import {checkRequiredFields} from "../common.js"; + /** * 离线密码 @@ -43,13 +45,13 @@ import StarCloud from "../star-cloud.js"; * @returns {Promise} */ export async function getOfflinePassword(params) { - const { password } = params - // 设置执行账号 - const result = await this.login(params.uid) - if (result.code !== Result.Success.code) { - return result - } - return await getOfflinePasswordRequest(password) + const {password} = params + // 设置执行账号 + const result = await this.login(params.uid) + if (result.code !== Result.Success.code) { + return result + } + return await getOfflinePasswordRequest(password) } /** @@ -61,130 +63,155 @@ export async function getOfflinePassword(params) { * @returns {Promise} */ export async function customPassword(params) { - const { password } = params - // 设置执行账号 - const result = await this.login(params.uid) - if (result.code !== Result.Success.code) { - return result - } - - this.requestParams = password - let { pwdNo, operate, keyboardPwd, startDate, endDate, pwdRight } = password - - if (operate === 0 || operate === 1) { - const checkPasswordParams = { - lockId: this.lockInfo.lockId, - keyboardPwd + const baseRequiredFields = [ + 'keyboardPwdName', + 'keyboardPwdType', + 'keyboardPwd', + 'addType', + 'isCoerced', + 'startDate', + 'endDate', + 'operate', + 'pwdRight', + 'lockId' + ]; + + // 根据operate值动态添加必填字段 + let cardRequiredFields = [...baseRequiredFields]; + if (params.password && (params.password.operate === 1 || params.password.operate === 2)) { + cardRequiredFields.push('pwdNo', 'keyboardPwdId'); } - if (password.keyboardPwdId) { - checkPasswordParams.keyboardPwdId = password.keyboardPwdId + + const missingField = checkRequiredFields(params.password, cardRequiredFields); + if (missingField) { + return new Result(Result.NotMoreData, null, `参数信息不完整: ${missingField}`); } - const checkPasswordResult = await this.checkPassword({ - uid:params.uid, - info:checkPasswordParams + + + const {password} = params + // 设置执行账号 + const result = await this.login(params.uid) + if (result.code !== Result.Success.code) { + return result + } + + this.requestParams = password + let {pwdNo, operate, keyboardPwd, startDate, endDate, pwdRight} = password + + if (operate === 0 || operate === 1) { + const checkPasswordParams = { + lockId: this.lockInfo.lockId, + keyboardPwd + } + if (password.keyboardPwdId) { + checkPasswordParams.keyboardPwdId = password.keyboardPwdId + } + const checkPasswordResult = await this.checkPassword({ + uid: params.uid, + info: checkPasswordParams + }) + if (checkPasswordResult.code === -3) { + return Result.ReadyHasPassword + } + if (checkPasswordResult.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 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' }) - if (checkPasswordResult.code === -3) { - return Result.ReadyHasPassword + + 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 } - if (checkPasswordResult.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 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) + return this.getWriteResult(this.customPassword, params) } /** @@ -196,119 +223,132 @@ export async function customPassword(params) { * @returns {Promise} */ export async function updateAdminPassword(params) { - const { adminPwd } = params + // 需要校验的参数 + const baseRequiredFields = [ + 'adminPwd', + ]; - // 设置执行账号 - const result = await this.login(params.uid) - if (result.code !== Result.Success.code) { - return result - } + // 根据operate值动态添加必填字段 + let cardRequiredFields = [...baseRequiredFields]; - // 确认设备连接正常 - if (!params.connected) { - const searchResult = await searchAndConnectDevice(this.lockInfo.bluetooth.bluetoothDeviceName) - if (searchResult.code !== Result.Success.code) { - return searchResult + const missingField = checkRequiredFields(params, cardRequiredFields); + if (missingField) { + return new Result(Result.NotMoreData, null, `参数信息不完整: ${missingField}`); } - this.updateLockInfo(searchResult.data) - } - // 检查是否已添加为用户 - const checkResult = await this.checkLockUser() - if (checkResult.code !== Result.Success.code) { - return checkResult - } + const {adminPwd} = params - this.requestParams = params + // 设置执行账号 + const result = await this.login(params.uid) + if (result.code !== Result.Success.code) { + return result + } - const uid = this.lockInfo.uid.toString() - const keyId = this.lockInfo.keyId.toString() - const pwdNo = 1 - const userCountLimit = 0xff - const startDate = Math.floor(this.lockInfo.startDate / 1000) - const endDate = Math.floor(this.lockInfo.endDate / 1000) + // 确认设备连接正常 + if (!params.connected) { + const searchResult = await searchAndConnectDevice(this.lockInfo.bluetooth.bluetoothDeviceName) + if (searchResult.code !== Result.Success.code) { + return searchResult + } + this.updateLockInfo(searchResult.data) + } - const length = 2 + 1 + 1 + 40 + 20 + 2 + 20 + 2 + 4 + 4 + 4 + 1 + 16 - const headArray = this.createPackageHeader(3, length) + // 检查是否已添加为用户 + const checkResult = await this.checkLockUser() + if (checkResult.code !== Result.Success.code) { + return checkResult + } - const contentArray = new Uint8Array(length) - contentArray[0] = cmdIds.expandCmd / 256 - contentArray[1] = cmdIds.expandCmd % 256 + this.requestParams = params - // 子命令 - contentArray[2] = subCmdIds.updateAdminPassword + const uid = this.lockInfo.uid.toString() + const keyId = this.lockInfo.keyId.toString() + const pwdNo = 1 + const userCountLimit = 0xff + const startDate = Math.floor(this.lockInfo.startDate / 1000) + const endDate = Math.floor(this.lockInfo.endDate / 1000) - contentArray[3] = length - 3 + const length = 2 + 1 + 1 + 40 + 20 + 2 + 20 + 2 + 4 + 4 + 4 + 1 + 16 + const headArray = this.createPackageHeader(3, length) - for (let i = 0; i < keyId.length; i++) { - contentArray[i + 4] = keyId.charCodeAt(i) - } + const contentArray = new Uint8Array(length) + contentArray[0] = cmdIds.expandCmd / 256 + contentArray[1] = cmdIds.expandCmd % 256 - for (let i = 0; i < uid.length; i++) { - contentArray[i + 44] = uid.charCodeAt(i) - } + // 子命令 + contentArray[2] = subCmdIds.updateAdminPassword - if( StarCloud.env !== null && - StarCloud.env !== undefined&& - StarCloud.env !=='' && - StarCloud.env === 'SKY'){ - contentArray[64] = Math.floor(pwdNo / 256) & 0xFF // 确保高字节为 0x00 - contentArray[65] = pwdNo & 0xFF - }else{ - contentArray[64] = pwdNo / 256 - contentArray[65] = pwdNo % 256 - } + contentArray[3] = length - 3 - for (let i = 0; i < adminPwd.length; i++) { - contentArray[i + 66] = adminPwd.charCodeAt(i) - } + for (let i = 0; i < keyId.length; i++) { + contentArray[i + 4] = keyId.charCodeAt(i) + } - contentArray[86] = userCountLimit / 256 - contentArray[87] = userCountLimit % 256 + for (let i = 0; i < uid.length; i++) { + contentArray[i + 44] = uid.charCodeAt(i) + } - contentArray.set(this.lockInfo.token || new Uint8Array([0, 0, 0, 0]), 88) + if (StarCloud.env !== null && + StarCloud.env !== undefined && + StarCloud.env !== '' && + StarCloud.env === 'SKY') { + contentArray[64] = Math.floor(pwdNo / 256) & 0xFF // 确保高字节为 0x00 + contentArray[65] = pwdNo & 0xFF + } else { + contentArray[64] = pwdNo / 256 + contentArray[65] = pwdNo % 256 + } - contentArray.set(timestampToArray(startDate), 92) - contentArray.set(timestampToArray(endDate), 96) + for (let i = 0; i < adminPwd.length; i++) { + contentArray[i + 66] = adminPwd.charCodeAt(i) + } - contentArray[100] = 16 + contentArray[86] = userCountLimit / 256 + contentArray[87] = userCountLimit % 256 - const md5Array = md5Encrypt( - keyId + uid, - this.lockInfo.token || new Uint8Array([0, 0, 0, 0]), - this.lockInfo.bluetooth.signKey - ) + contentArray.set(this.lockInfo.token || new Uint8Array([0, 0, 0, 0]), 88) - contentArray.set(md5Array, 101) + contentArray.set(timestampToArray(startDate), 92) + contentArray.set(timestampToArray(endDate), 96) - const cebArray = sm4.encrypt(contentArray, this.lockInfo.bluetooth.privateKey, { - mode: 'ecb', - output: 'array' - }) + contentArray[100] = 16 - const packageArray = createPackageEnd(headArray, cebArray) + const md5Array = md5Encrypt( + keyId + uid, + this.lockInfo.token || new Uint8Array([0, 0, 0, 0]), + this.lockInfo.bluetooth.signKey + ) - const writeResult = await writeBLECharacteristicValue( - this.lockInfo.deviceId, - this.lockInfo.serviceId, - this.lockInfo.writeCharacteristicId, - packageArray - ) + contentArray.set(md5Array, 101) - if (writeResult.code !== Result.Success.code) { - return writeResult - } + const cebArray = sm4.encrypt(contentArray, this.lockInfo.bluetooth.privateKey, { + mode: 'ecb', + output: 'array' + }) - return this.getWriteResult(this.updateAdminPassword, params) + 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.updateAdminPassword, params) } // 检查密码名称与密码是否已存在 export async function checkPassword(params) { - const { info } = params - // 设置执行账号 - const result = await this.login(params.uid) - if (result.code !== Result.Success.code) { - return result - } - return await checkPasswordRequest(info) + const {info} = params + // 设置执行账号 + const result = await this.login(params.uid) + if (result.code !== Result.Success.code) { + return result + } + return await checkPasswordRequest(info) } diff --git a/uni/index.js b/uni/index.js index 651e61a..de6966d 100644 --- a/uni/index.js +++ b/uni/index.js @@ -1,8 +1,6 @@ import starCloudInstance from '../star-cloud' -import { Result } from '../constant' -import {getPalmVeinListRequest, getRemoteListRequest} from "../api.js"; - -export { Result } +import {Result, supportFunctionsFeatureBit} from '../constant' +export {Result} /** * 账户信息 @@ -22,10 +20,10 @@ export { Result } * @param {Boolean} params.isReportLog 是否上报日志 */ export const init = params => { - starCloudInstance.init({ - ...params, - platform: 1 - }) + starCloudInstance.init({ + ...params, + platform: 1 + }) } /** @@ -33,7 +31,7 @@ export const init = params => { * @returns Result */ export const register = async () => { - return await starCloudInstance.register() + return await starCloudInstance.register() } /** @@ -42,7 +40,7 @@ export const register = async () => { * @param {Number} params.uid 用户ID */ export const logout = params => { - starCloudInstance.logout(params) + starCloudInstance.logout(params) } /** @@ -53,7 +51,7 @@ export const logout = params => { * @returns Result */ export const selectLock = async params => { - return await starCloudInstance.selectLock(params) + return await starCloudInstance.selectLock(params) } /** @@ -65,7 +63,7 @@ export const selectLock = async params => { * @returns Result */ export const openDoor = async params => { - return await starCloudInstance.openDoor(params) + return await starCloudInstance.openDoor(params) } /** @@ -89,7 +87,7 @@ export const openDoor = async params => { * @returns Result */ export const getOfflinePassword = async params => { - return await starCloudInstance.getOfflinePassword(params) + return await starCloudInstance.getOfflinePassword(params) } /** @@ -109,7 +107,7 @@ export const getOfflinePassword = async params => { * @returns Result */ export const checkPassword = async params => { - return await starCloudInstance.checkPassword(params) + return await starCloudInstance.checkPassword(params) } /** @@ -137,7 +135,7 @@ export const checkPassword = async params => { * @returns Result */ export const customPassword = async params => { - return await starCloudInstance.customPassword(params) + return await starCloudInstance.customPassword(params) } /** @@ -146,7 +144,7 @@ export const customPassword = async params => { * @returns Result */ export const searchDevice = async callback => { - return await starCloudInstance.searchDevice(callback) + return await starCloudInstance.searchDevice(callback) } /** @@ -154,7 +152,7 @@ export const searchDevice = async callback => { * @returns Result */ export const stopSearchDevice = async () => { - return await starCloudInstance.stopSearchDevice() + return await starCloudInstance.stopSearchDevice() } /** @@ -165,7 +163,7 @@ export const stopSearchDevice = async () => { * @returns Result */ export const bindDevice = async params => { - return await starCloudInstance.bindDevice(params) + return await starCloudInstance.bindDevice(params) } /** @@ -176,7 +174,7 @@ export const bindDevice = async params => { * @returns Result */ export const removeBadLock = async params => { - return await starCloudInstance.removeBadLock(params) + return await starCloudInstance.removeBadLock(params) } /** @@ -185,7 +183,7 @@ export const removeBadLock = async params => { * @param {Number} [params.uid] 用户ID */ export const deleteLock = async params => { - return await starCloudInstance.deleteLock(params) + return await starCloudInstance.deleteLock(params) } /** @@ -197,7 +195,7 @@ export const deleteLock = async params => { * @returns Result */ export const updateAdminPassword = async params => { - return await starCloudInstance.updateAdminPassword(params) + return await starCloudInstance.updateAdminPassword(params) } /** @@ -208,7 +206,7 @@ export const updateAdminPassword = async params => { * @returns Result */ export const syncOpenDoorRecord = async params => { - return await starCloudInstance.syncAllOpenRecord(params) + return await starCloudInstance.syncAllOpenRecord(params) } /** @@ -216,7 +214,7 @@ export const syncOpenDoorRecord = async params => { * @returns Result */ export const getServerTime = async () => { - return await starCloudInstance.getServerTimestamp() + return await starCloudInstance.getServerTimestamp() } /** @@ -227,7 +225,7 @@ export const getServerTime = async () => { * @returns Result */ export const getLockSupportFeatures = async params => { - return await starCloudInstance.getLockSupportFeatures(params) + return await starCloudInstance.getLockSupportFeatures(params) } /** @@ -238,7 +236,7 @@ export const getLockSupportFeatures = async params => { * @returns Result */ export const refreshElecInfo = async params => { - return await starCloudInstance.refreshElecInfo(params) + return await starCloudInstance.refreshElecInfo(params) } /** @@ -249,7 +247,7 @@ export const refreshElecInfo = async params => { * @returns Result */ export const refreshColdWaterInfo = async params => { - return await starCloudInstance.refreshColdWaterInfo(params) + return await starCloudInstance.refreshColdWaterInfo(params) } @@ -261,11 +259,10 @@ export const refreshColdWaterInfo = async params => { * @returns Result */ export const refreshHotWaterInfo = async params => { - return await starCloudInstance.refreshHotWaterInfo(params) + return await starCloudInstance.refreshHotWaterInfo(params) } - /** * 注册扩展产品(卡片、指纹、人脸、遥控、掌静脉等) * @@ -325,9 +322,29 @@ export const registerExtendedProducts = async params => { * @param {string} params.uid - 用户 ID */ export const registerExtendedProductsCancel = async params => { - return await starCloudInstance.registerExtendedProductsCancel(params) + return await starCloudInstance.registerExtendedProductsCancel(params) } +/** + * 更新支持功能项设置(带参数) + * @param params + * @returns {Promise<*>} + */ +export const updateSupportFunctionsWithParams = async params => { + return await starCloudInstance.updateSupportFunctionsWithParams(params) +} + + +/** + * 读取支持功能项设置 + * @param params + * @returns {Promise<*>} + */ +export const readSupportFunctionsSetting = async params => { + return await starCloudInstance.readSupportFunctionsSetting(params) +} + + /** * 获取Ic卡列表 @@ -336,7 +353,7 @@ export const registerExtendedProductsCancel = async params => { * @param params.pageSize 每页显示数(选填) */ export const getIcCardList = async params => { - return await starCloudInstance.getIcCardList(params) + return await starCloudInstance.getIcCardList(params) } @@ -347,7 +364,7 @@ export const getIcCardList = async params => { * @param params.pageSize 每页显示数(选填) */ export const getFingerprintList = async params => { - return await starCloudInstance.getFingerprintList(params) + return await starCloudInstance.getFingerprintList(params) } /** @@ -357,7 +374,7 @@ export const getFingerprintList = async params => { * @param params.pageSize 每页显示数(选填) */ export const getFaceList = async params => { - return await starCloudInstance.getFaceList(params) + return await starCloudInstance.getFaceList(params) } /** @@ -367,7 +384,7 @@ export const getFaceList = async params => { * @param params.pageSize 每页显示数(选填) */ export const getPalmVeinList = async params => { - return await starCloudInstance.getPalmVeinList(params) + return await starCloudInstance.getPalmVeinList(params) } /** @@ -377,5 +394,14 @@ export const getPalmVeinList = async params => { * @param params.pageSize 每页显示数(选填) */ export const getRemoteList = async params => { - return await starCloudInstance.getRemoteList(params) + return await starCloudInstance.getRemoteList(params) +} + +/** + * 远程开锁 + * @param params + * @returns {Promise<*>} + */ +export const remoteUnLock = async params => { + return await starCloudInstance.remoteUnLock(params) } \ No newline at end of file