import {bytesToHex, bytesToMac} from '../utils/hex' import {joinLowHigh, readUint16LE, toUint8Array} from '../utils/bytes' /** * 解析 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] } /** * 解析 UUID_MSG 设备信息(ED713/ED719 通用字段优先)。 */ export function parseDeviceInfo(payload) { const bytes = toUint8Array(payload) if (!bytes.length) { return { raw: bytes, mac: '', bindStatus: null, productId: null, deviceType: null, wifiStatus: null, cellularStatus: null } } const macBytes = bytes.slice(0, 6) const bindStatus = bytes.length > 6 ? bytes[6] : null const productId = bytes.length > 10 ? joinLowHigh(bytes[10], bytes[9]) : null const deviceType = bytes.length > 14 ? bytes[14] : null const wifiStatus = bytes.length > 15 ? bytes[15] : null const cellularStatus = bytes.length > 16 ? bytes[16] : null return { raw: bytes, mac: bytesToMac(macBytes), bindStatus, productId, deviceType, wifiStatus, cellularStatus, baseBoardVersion: bytes.length > 11 ? bytes[11] : null, coreBoardVersion: bytes.length > 12 ? bytes[12] : null } } /** * 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 雷达数据解析。 * 屏蔽区数量由 shieldNum 控制,每块固定 9 字节。 */ 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[27] || 0 const shieldStart = 28 const shieldBlockLength = Math.min(Math.max(shieldNum, 0), 4) * 9 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[shieldStart + shieldBlockLength] ?? null } }