160 lines
3.8 KiB
JavaScript
160 lines
3.8 KiB
JavaScript
/**
|
||
* HBY102J 晶全应用层协议:下行 FA … FF,上行 FB/FC … FF。
|
||
* 与 HBY100-J 使用同一颗蓝牙模组 / 同一套 GATT(AE30 + AE03 写 + AE02 通知),
|
||
* 见 `api/100J/HBY100-J.js` 中 SERVICE_UUID / WRITE / NOTIFY;仅帧语义与 100J 不同。
|
||
*/
|
||
|
||
export const HBY102J_SERVICE = '0000AE30-0000-1000-8000-00805F9B34FB'
|
||
export const HBY102J_WRITE = '0000AE03-0000-1000-8000-00805F9B34FB'
|
||
export const HBY102J_NOTIFY = '0000AE02-0000-1000-8000-00805F9B34FB'
|
||
|
||
function buildFaFrame(func, dataBytes = []) {
|
||
return [0xfa, func & 0xff, ...dataBytes.map((b) => b & 0xff), 0xff]
|
||
}
|
||
|
||
const BYTE_TO_RADAR = {
|
||
0: 'status_off',
|
||
1: 'status_2M',
|
||
2: 'status_4M',
|
||
3: 'status_7M',
|
||
4: 'status_10M'
|
||
}
|
||
|
||
const BYTE_TO_LED = {
|
||
0: 'led_off',
|
||
1: 'led_flash',
|
||
2: 'led_low_flash',
|
||
3: 'led_steady',
|
||
4: 'led_alarm'
|
||
}
|
||
|
||
const RADAR_KEY_TO_BYTE = {
|
||
status_off: 0,
|
||
status_2M: 1,
|
||
status_4M: 2,
|
||
status_7M: 3,
|
||
status_10M: 4,
|
||
status_on: 1
|
||
}
|
||
|
||
const LED_KEY_TO_BYTE = {
|
||
led_off: 0,
|
||
led_flash: 1,
|
||
led_low_flash: 2,
|
||
led_steady: 3,
|
||
led_alarm: 4
|
||
}
|
||
|
||
export function encodeChannelSet(channelDecimal1to80) {
|
||
const ch = Math.max(1, Math.min(80, Number(channelDecimal1to80) || 1))
|
||
return buildFaFrame(0x21, [ch])
|
||
}
|
||
|
||
export function encodeOnline(on) {
|
||
return buildFaFrame(0x22, [on ? 1 : 0])
|
||
}
|
||
|
||
export function encodeRadarFromUiKey(sta_RadarType) {
|
||
const b = RADAR_KEY_TO_BYTE[sta_RadarType] !== undefined ? RADAR_KEY_TO_BYTE[sta_RadarType] : 0
|
||
return buildFaFrame(0x23, [b])
|
||
}
|
||
|
||
export function encodeWarningLightFromLedKey(ledKey) {
|
||
const m = LED_KEY_TO_BYTE[ledKey] !== undefined ? LED_KEY_TO_BYTE[ledKey] : 0
|
||
return buildFaFrame(0x24, [m])
|
||
}
|
||
|
||
export function encodeQueryOnlineCount() {
|
||
return buildFaFrame(0x25, [0])
|
||
}
|
||
|
||
export function encodeQueryPower() {
|
||
return buildFaFrame(0x26, [])
|
||
}
|
||
|
||
function formatMacFromBytes(u8, start, len) {
|
||
const hex = []
|
||
for (let i = 0; i < len; i++) {
|
||
hex.push(u8[start + i].toString(16).padStart(2, '0'))
|
||
}
|
||
return hex.join(':').toUpperCase()
|
||
}
|
||
|
||
/**
|
||
* 解析设备上行一帧(Notify),输出与 HBY102 页 formData 对齐的字段
|
||
*/
|
||
export function parseHby102jUplink(u8) {
|
||
const out = {}
|
||
if (!u8 || u8.length < 3) return out
|
||
|
||
const h = u8[0]
|
||
const func = u8[1]
|
||
const tail = u8[u8.length - 1]
|
||
|
||
if (tail !== 0xff && u8.length >= 4) {
|
||
// 非标准结尾时仍尽量解析
|
||
}
|
||
|
||
if (h === 0xfc && u8.length >= 8 && u8[7] === 0xff) {
|
||
out.sta_address = formatMacFromBytes(u8, 1, 6)
|
||
return out
|
||
}
|
||
|
||
if (h !== 0xfb) return out
|
||
|
||
switch (func) {
|
||
case 0x21:
|
||
if (u8.length >= 4) {
|
||
out.sta_Channel = u8[2]
|
||
}
|
||
break
|
||
case 0x22:
|
||
out.sta_Online = u8[2] === 1 ? 'E49_on' : 'E49_off'
|
||
break
|
||
case 0x23:
|
||
out.sta_RadarType = BYTE_TO_RADAR[u8[2]] !== undefined ? BYTE_TO_RADAR[u8[2]] : 'status_off'
|
||
break
|
||
case 0x24:
|
||
out.sta_LedType = BYTE_TO_LED[u8[2]] !== undefined ? BYTE_TO_LED[u8[2]] : 'led_off'
|
||
break
|
||
case 0x25:
|
||
if (u8.length >= 4) {
|
||
out.sta_onlineQuantity = u8[2]
|
||
}
|
||
break
|
||
case 0x26:
|
||
if (u8.length >= 5) {
|
||
out.sta_PowerPercent = u8[2]
|
||
out.sta_charge = u8[3]
|
||
}
|
||
break
|
||
case 0x27:
|
||
if (u8.length >= 9) {
|
||
out.sta_PowerPercent = u8[2]
|
||
out.sta_charge = u8[3]
|
||
out.sta_Channel = u8[4]
|
||
out.sta_LedType = BYTE_TO_LED[u8[5]] !== undefined ? BYTE_TO_LED[u8[5]] : 'led_off'
|
||
out.sta_RadarType = BYTE_TO_RADAR[u8[6]] !== undefined ? BYTE_TO_RADAR[u8[6]] : 'status_off'
|
||
out.sta_Online = u8[7] === 1 ? 'E49_on' : 'E49_off'
|
||
}
|
||
break
|
||
case 0x28:
|
||
if (u8.length >= 10) {
|
||
const peerMac = formatMacFromBytes(u8, 2, 6)
|
||
const ev = u8[8]
|
||
if (ev === 0x01) {
|
||
out.sta_sosadd = peerMac
|
||
out.sta_Intrusion = 1
|
||
} else if (ev === 0x02) {
|
||
out.sta_sosadd_off = peerMac
|
||
} else if (ev === 0x03) {
|
||
out.sta_tomac = peerMac
|
||
}
|
||
}
|
||
break
|
||
default:
|
||
break
|
||
}
|
||
return out
|
||
}
|