From f0693a54847212d32089a000fa59ce5071af7414 Mon Sep 17 00:00:00 2001 From: Dominic Griesel Date: Wed, 8 May 2024 09:27:15 +0200 Subject: [PATCH] fix: convert LR beam TX power, documentation for beam frames --- docs/api/config-manager.md | 4 -- docs/api/controller.md | 2 +- docs/api/node.md | 10 +-- docs/api/zniffer.md | 64 ++++++++++++++++++- .../serial/src/message/ZnifferMessages.ts | 20 ------ packages/zwave-js/src/Zniffer.ts | 1 + packages/zwave-js/src/lib/zniffer/MPDU.ts | 35 ++++++++-- 7 files changed, 93 insertions(+), 43 deletions(-) diff --git a/docs/api/config-manager.md b/docs/api/config-manager.md index 41526d6b0f97..ad7007674d23 100644 --- a/docs/api/config-manager.md +++ b/docs/api/config-manager.md @@ -413,8 +413,6 @@ interface GenericDeviceClass { readonly key: number; readonly label: string; readonly requiresSecurity?: boolean; - readonly supportedCCs: readonly CommandClasses[]; - readonly controlledCCs: readonly CommandClasses[]; readonly maySupportBasicCC: boolean; readonly specific: ReadonlyMap; } @@ -428,8 +426,6 @@ interface SpecificDeviceClass { readonly label: string; readonly zwavePlusDeviceType?: string; readonly requiresSecurity?: boolean; - readonly supportedCCs: readonly CommandClasses[]; - readonly controlledCCs: readonly CommandClasses[]; readonly maySupportBasicCC: boolean; } ``` diff --git a/docs/api/controller.md b/docs/api/controller.md index 07a0002f142a..f73fff26338c 100644 --- a/docs/api/controller.md +++ b/docs/api/controller.md @@ -374,7 +374,7 @@ interface LifelineRoutes { ```ts interface RouteStatistics { /** The protocol and used data rate for this route */ - protocolDataRate: ProtocolDataRate; + protocolDataRate?: ProtocolDataRate; /** Which nodes are repeaters for this route */ repeaters: number[]; diff --git a/docs/api/node.md b/docs/api/node.md index 04b8837e41e0..3f7f2763670f 100644 --- a/docs/api/node.md +++ b/docs/api/node.md @@ -884,8 +884,6 @@ interface DeviceClass { readonly basic: BasicDeviceClass; readonly generic: GenericDeviceClass; readonly specific: SpecificDeviceClass; - readonly mandatorySupportedCCs: readonly CommandClasses[]; - readonly mandatoryControlledCCs: readonly CommandClasses[]; } ``` @@ -905,8 +903,6 @@ interface GenericDeviceClass { readonly key: number; readonly label: string; readonly requiresSecurity?: boolean; - readonly supportedCCs: readonly CommandClasses[]; - readonly controlledCCs: readonly CommandClasses[]; readonly maySupportBasicCC: boolean; readonly specific: ReadonlyMap; } @@ -920,8 +916,6 @@ interface SpecificDeviceClass { readonly label: string; readonly zwavePlusDeviceType?: string; readonly requiresSecurity?: boolean; - readonly supportedCCs: readonly CommandClasses[]; - readonly controlledCCs: readonly CommandClasses[]; readonly maySupportBasicCC: boolean; } ``` @@ -946,7 +940,7 @@ If the `Z-Wave+` Command Class is supported, this returns the `Z-Wave+` node typ ```ts enum ZWavePlusNodeType { - Node = 0, + Node = 0, // ZWave+ Node IPGateway = 2, } ``` @@ -1559,7 +1553,7 @@ interface NodeStatistics { ```ts interface RouteStatistics { /** The protocol and used data rate for this route */ - protocolDataRate: ProtocolDataRate; + protocolDataRate?: ProtocolDataRate; /** Which nodes are repeaters for this route */ repeaters: number[]; diff --git a/docs/api/zniffer.md b/docs/api/zniffer.md index 0b6d9292b776..5aaf29c17820 100644 --- a/docs/api/zniffer.md +++ b/docs/api/zniffer.md @@ -153,15 +153,18 @@ type CorruptedFrame = { }; ``` -A valid frame can either be a Z-Wave frame or a Z-Wave Long Range frame... +A valid frame can either be a Z-Wave frame or a Z-Wave Long Range frame, either normal or beaming... ```ts -type Frame = ZWaveFrame | LongRangeFrame; +type Frame = + | ZWaveFrame + | LongRangeFrame + | BeamFrame; ``` -...both of which have several subtypes: +...all of which have several subtypes: @@ -302,6 +305,57 @@ type LongRangeFrame = ); ``` + + +```ts +type BeamFrame = + // Common fields for all Beam frames + & { + channel: number; + } + // Different types of beam frames: + & ( + | { + // Z-Wave Classic + protocol: Protocols.ZWave; + type: ZWaveFrameType.BeamStart; + + protocolDataRate: ZnifferProtocolDataRate; + rssiRaw: number; + rssi?: RSSI; + region: ZnifferRegion; + + homeIdHash?: number; + destinationNodeId: number; + } + | { + // Z-Wave Long Range + protocol: Protocols.ZWaveLongRange; + type: LongRangeFrameType.BeamStart; + + protocolDataRate: ZnifferProtocolDataRate; + rssiRaw: number; + rssi?: RSSI; + region: ZnifferRegion; + + txPower: number; + homeIdHash: number; + destinationNodeId: number; + } + // The Zniffer sends the same command for the beam ending for both + // Z-Wave Classic and Long Range. To make testing the frame type more + // consistent with the other frames, two different values are used + | { + protocol: Protocols.ZWave; + type: ZWaveFrameType.BeamStop; + } + | { + protocol: Protocols.ZWaveLongRange; + type: LongRangeFrameType.BeamStop; + } + ); +``` + ## Type definitions @@ -323,6 +377,8 @@ enum ZWaveFrameType { ExplorerNormal, ExplorerSearchResult, ExplorerInclusionRequest, + BeamStart, + BeamStop, } ``` @@ -332,6 +388,8 @@ enum ZWaveFrameType { enum LongRangeFrameType { Singlecast, Ack, + BeamStart, + BeamStop, } ``` diff --git a/packages/serial/src/message/ZnifferMessages.ts b/packages/serial/src/message/ZnifferMessages.ts index 337820abb006..7a5f90fd0a12 100644 --- a/packages/serial/src/message/ZnifferMessages.ts +++ b/packages/serial/src/message/ZnifferMessages.ts @@ -76,9 +76,6 @@ export class ZnifferMessage { // The ZnifferParser takes care of segmenting frames, so here we // only cut off the type byte from the payload this.payload = payload.subarray(1); - // // TODO: Having the header etc. be part of the payload is a bit awkward - // const length = payload[9]; - // this.payload = payload.subarray(1, 10 + length); } else { throw new ZWaveError( `Invalid Zniffer message type ${this.type as any}`, @@ -166,23 +163,6 @@ export class ZnifferMessage { const ret = new Constructor(options); return ret; } - - // /** Generates a representation of this Message for the log */ - // public toLogEntry(): MessageOrCCLogEntry { - // const tags = [ - // this.type === MessageType.Request ? "REQ" : "RES", - // FunctionType[this.functionType], - // ]; - // const nodeId = this.getNodeId(); - // if (nodeId) tags.unshift(getNodeTag(nodeId)); - - // return { - // tags, - // message: this.payload.length > 0 - // ? { payload: `0x${this.payload.toString("hex")}` } - // : undefined, - // }; - // } } function computeChecksumXOR(buffer: Buffer): number { diff --git a/packages/zwave-js/src/Zniffer.ts b/packages/zwave-js/src/Zniffer.ts index 0eb461a3b1be..695814358364 100644 --- a/packages/zwave-js/src/Zniffer.ts +++ b/packages/zwave-js/src/Zniffer.ts @@ -1,5 +1,6 @@ export type { MPDU } from "./lib/zniffer/MPDU"; export type { + BeamFrame, CorruptedFrame, Frame, LongRangeFrame, diff --git a/packages/zwave-js/src/lib/zniffer/MPDU.ts b/packages/zwave-js/src/lib/zniffer/MPDU.ts index 945d04803161..283e965d183f 100644 --- a/packages/zwave-js/src/lib/zniffer/MPDU.ts +++ b/packages/zwave-js/src/lib/zniffer/MPDU.ts @@ -51,6 +51,27 @@ function getChannelConfiguration(region: ZnifferRegion): "1/2" | "3" | "4" { } } +function longRangeBeamPowerToDBm(power: number): number { + return [ + -6, + -2, + 2, + 6, + 10, + 13, + 16, + 19, + 21, + 23, + 25, + 26, + 27, + 28, + 29, + 30, + ][power]; +} + function formatNodeId(nodeId: number): string { return padStart(nodeId.toString(), 3, "0"); } @@ -858,7 +879,8 @@ export class LongRangeBeamStart { } } - this.txPower = data[1] >>> 4; + const txPower = data[1] >>> 4; + this.txPower = longRangeBeamPowerToDBm(txPower); this.destinationNodeId = data.readUint16BE(1) & 0x0fff; this.homeIdHash = data[3]; } @@ -878,8 +900,7 @@ export class LongRangeBeamStart { "protocol/data rate": znifferProtocolDataRateToString( this.frameInfo.protocolDataRate, ), - // FIXME: convert to dBm - "TX power": `${this.txPower}`, + "TX power": `${this.txPower} dBm`, RSSI: this.frameInfo.rssi != undefined ? rssiToString(this.frameInfo.rssi) : this.frameInfo.rssiRaw.toString(), @@ -1067,8 +1088,6 @@ export type BeamFrame = // Common fields for all Beam frames & { channel: number; - // Although it is being parsed, Stop frames contain no - // valid data for everything but the channel no. } // Different types of beam frames: & ( @@ -1086,6 +1105,7 @@ export type BeamFrame = destinationNodeId: number; } | { + // Z-Wave Long Range protocol: Protocols.ZWaveLongRange; type: LongRangeFrameType.BeamStart; @@ -1098,8 +1118,9 @@ export type BeamFrame = homeIdHash: number; destinationNodeId: number; } - // Currently, these two are identical, but we distinguish them - // to make the Frame type more consistent + // The Zniffer sends the same command for the beam ending for both + // Z-Wave Classic and Long Range. To make testing the frame type more + // consistent with the other frames, two different values are used | { protocol: Protocols.ZWave; type: ZWaveFrameType.BeamStop;