435 lines
13 KiB
JavaScript

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