Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow filtering Zniffer frames when saving als ZLF #7279

Merged
merged 2 commits into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions docs/api/zniffer.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,20 @@ Captured frames can also be returned as a `Buffer` in the `.zlf` format using th
await zniffer.getCaptureAsZLFBuffer();
```

When saving the capture to a file or buffer, an optional predicate function can be passed to filter frames first, for example:

```ts
await zniffer.saveCaptureToFile("/path/to/file.zlf", (frame) => {
// Limit frames to a specific home ID
return "homeId" in f.parsedFrame && f.parsedFrame.homeId === 0xdeadbeef;
});
await zniffer.getCaptureAsZLFBuffer((frame) => {
// Only include ZWLR frames
return "protocol" in f.parsedFrame
&& f.parsedFrame.protocol === Protocols.ZWaveLongRange;
});
```

## Frequency selection

The configured frequency of the Zniffer has to match the frequency of the Z-Wave network it is capturing. Zniffers based on 700/800 series firmware support frequencies that match the `ZnifferRegion` enum:
Expand Down
36 changes: 30 additions & 6 deletions packages/zwave-js/src/lib/zniffer/Zniffer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -871,21 +871,45 @@ supported frequencies: ${
this._capturedFrames = [];
}

/** Get the captured frames in the official Zniffer application format. */
public getCaptureAsZLFBuffer(): Buffer {
/**
* Get the captured frames in the official Zniffer application format.
* @param frameFilter Optional predicate function to filter the frames included in the capture
*/
public getCaptureAsZLFBuffer(
frameFilter?: (frame: CapturedFrame) => boolean,
): Buffer {
// Mimics the current Zniffer software, without using features like sessions and comments
const header = Buffer.alloc(2048, 0);
header[0] = 0x68; // zniffer version
header.writeUInt16BE(0x2312, 0x07fe); // checksum
let filteredFrames = this._capturedFrames;
if (frameFilter) {
filteredFrames = filteredFrames.filter((f) =>
// Always include Zniffer-protocol frames
f.parsedFrame == undefined
// Apply the filter to all other frames
|| frameFilter({
frameData: f.frameData,
parsedFrame: f.parsedFrame,
timestamp: f.timestamp,
})
);
}
return Buffer.concat([
header,
...this._capturedFrames.map(captureToZLFEntry),
...filteredFrames.map(captureToZLFEntry),
]);
}

/** Saves the captured frames in a `.zlf` file that can be read by the official Zniffer application. */
public async saveCaptureToFile(filePath: string): Promise<void> {
await fs.writeFile(filePath, this.getCaptureAsZLFBuffer());
/**
* Saves the captured frames in a `.zlf` file that can be read by the official Zniffer application.
* @param frameFilter Optional predicate function to filter the frames included in the capture
*/
public async saveCaptureToFile(
filePath: string,
frameFilter?: (frame: CapturedFrame) => boolean,
): Promise<void> {
await fs.writeFile(filePath, this.getCaptureAsZLFBuffer(frameFilter));
}

/**
Expand Down
Loading