SEC_Warehouse/utils/ble/parsers/commonParser.js

158 lines
4.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {bytesToHex, bytesToMac} from '../utils/hex'
import {joinLowHigh, readUint16LE, toUint8Array} from '../utils/bytes'
import {DEVICE_PROFILE} from '../protocols/profiles'
/**
* 解析 UUID_STATE 的状态字节,转为有符号 8bit。
*/
export function parseStateCode(payload) {
const bytes = toUint8Array(payload)
if (!bytes.length) {
return null
}
return bytes[0] > 127 ? bytes[0] - 256 : bytes[0]
}
/**
* ED713 MSG 解析。
* 文档布局MAC(6) + bindStatus(1) + 其它(3) + productId_H(1) + productId_L(1)
* + baseBoard(1) + coreBoard(1) + 其它(2) + deviceType(1)
* + wifiStatus(1) + cellularStatus(1) + 其它(1)
*/
function parseEd713DeviceInfo(bytes) {
if (!bytes.length) {
return {
raw: bytes, mac: '', bindStatus: null, productId: null,
deviceType: null, wifiStatus: null, cellularStatus: null
}
}
return {
raw: bytes,
mac: bytesToMac(bytes.slice(0, 6)),
bindStatus: bytes.length > 6 ? bytes[6] : null,
productId: bytes.length > 11 ? joinLowHigh(bytes[11], bytes[10]) : null,
baseBoardVersion: bytes.length > 12 ? bytes[12] : null,
coreBoardVersion: bytes.length > 13 ? bytes[13] : null,
deviceType: bytes.length > 16 ? bytes[16] : null,
wifiStatus: bytes.length > 17 ? bytes[17] : null,
cellularStatus: bytes.length > 18 ? bytes[18] : null
}
}
/**
* ED719 MSG 解析。
* 实际偏移与 ED713 一致(文档省略了 bindStatus/productId 但底板数据布局相同):
* MAC(6) + bindStatus(1) + 其它(3) + productId_H(1) + productId_L(1)
* + baseBoard(1) + coreBoard(1) + 其它(2) + deviceType(1)
* + wifiStatus(1) + cellularStatus(1) + 其它(1)
*/
function parseEd719DeviceInfo(bytes) {
return parseEd713DeviceInfo(bytes)
}
/**
* 解析 UUID_MSG 设备信息(按 profile 区分 ED713/ED719
*/
export function parseDeviceInfo(payload, profileId = DEVICE_PROFILE.UNKNOWN) {
const bytes = toUint8Array(payload)
if (!bytes.length) {
return {
raw: bytes, mac: '', bindStatus: null, productId: null,
deviceType: null, wifiStatus: null, cellularStatus: null
}
}
if (profileId === DEVICE_PROFILE.ED713) return parseEd713DeviceInfo(bytes)
if (profileId === DEVICE_PROFILE.ED719) return parseEd719DeviceInfo(bytes)
// UNKNOWN按 ED713 布局兼容
return parseEd713DeviceInfo(bytes)
}
/**
* ED713 雷达数据解析。
* 协议帧长度不足时返回 valid:false交由上层决定是否忽略。
*/
export function parseEd713Radar(payload) {
const bytes = toUint8Array(payload)
if (bytes.length < 60) {
return {
type: 'ED713',
valid: false,
reason: 'LENGTH_LT_60',
raw: bytes
}
}
return {
type: 'ED713',
valid: true,
raw: bytes,
peopleCount: bytes[24],
peopleLocalDecimeter: bytes[25],
peopleState: bytes[26],
heartRate: bytes[28],
respRate: bytes[29],
activityState: bytes[30],
moveIndex: bytes[35],
waveNum: bytes[37],
respWave: Array.from(bytes.slice(38, 58)),
narrowFlag: bytes[59]
}
}
/**
* ED719 雷达数据解析。
* 按文档结构体定义:
* header[4] + event(1) + people(1) + num(1) + nodata(1)
* + height(2) + mode(1) + beeper(1) + left(2) + right(2) + front(2) + back(2)
* + sensitive(1) + nodata1(1) + stateDelay(2) = 24 bytes
* shield_num 在 offset 24屏蔽区在 offset 25
* 屏蔽区之后wallOption + peopleHaveSwitch + peopleActivitySwitch
*/
export function parseEd719Radar(payload) {
const bytes = toUint8Array(payload)
if (bytes.length < 24) {
return {
type: 'ED719',
valid: false,
reason: 'LENGTH_LT_24',
raw: bytes
}
}
const shieldNum = bytes[24] || 0
const shieldStart = 25
const shieldBlockLength = Math.min(Math.max(shieldNum, 0), 4) * 9
const wallOffset = shieldStart + shieldBlockLength
return {
type: 'ED719',
valid: true,
raw: bytes,
eventState: bytes[4],
peopleState: bytes[5],
peopleNum: bytes[6],
installHeight: readUint16LE(bytes, 8),
installMode: bytes[10],
beeperOn: bytes[11],
leftDist: readUint16LE(bytes, 12),
rightDist: readUint16LE(bytes, 14),
frontDist: readUint16LE(bytes, 16),
backDist: readUint16LE(bytes, 18),
sensitive: bytes[20],
stateDelay: readUint16LE(bytes, 22),
shieldNum,
shieldZoneRaw: Array.from(bytes.slice(shieldStart, shieldStart + shieldBlockLength)),
wallOption: bytes[wallOffset] ?? null,
peopleHaveSwitch: bytes[wallOffset + 1] ?? null,
peopleActivitySwitch: bytes[wallOffset + 2] ?? null
}
}