From 547377ae0c1958e0b1276112e13a869f14758dad Mon Sep 17 00:00:00 2001
From: Daniel Lando
Date: Wed, 8 May 2024 11:28:04 +0200
Subject: [PATCH 001/120] feat: zniffer
---
api/app.ts | 38 ++++++++++
api/config/store.ts | 2 +
api/lib/SocketEvents.ts | 3 +
api/lib/ZnifferManager.ts | 147 ++++++++++++++++++++++++++++++++++++++
api/lib/ZwaveClient.ts | 53 +-------------
api/lib/utils.ts | 63 +++++++++++++++-
src/stores/base.js | 21 +++++-
7 files changed, 274 insertions(+), 53 deletions(-)
create mode 100644 api/lib/ZnifferManager.ts
diff --git a/api/app.ts b/api/app.ts
index 806d510a91..71e3f4c0bd 100644
--- a/api/app.ts
+++ b/api/app.ts
@@ -48,6 +48,7 @@ import * as utils from './lib/utils'
import backupManager from './lib/BackupManager'
import { readFile, realpath } from 'fs/promises'
import { generate } from 'selfsigned'
+import ZnifferManager from './lib/ZnifferManager'
const createCertificate = promisify(generate)
@@ -158,6 +159,7 @@ socketManager.authMiddleware = function (
}
let gw: Gateway // the gateway instance
+let zniffer: ZnifferManager // the zniffer instance
const plugins: CustomPlugin[] = []
let pluginsRouter: Router
@@ -386,6 +388,10 @@ async function startGateway(settings: Settings) {
zwave = new ZWaveClient(settings.zwave, socketManager.io)
}
+ if (settings.zniffer) {
+ zniffer = new ZnifferManager(settings.zniffer, socketManager.io)
+ }
+
backupManager.init(zwave)
gw = new Gateway(settings.gateway, zwave, mqtt)
@@ -730,6 +736,38 @@ function setupSocket(server: HttpServer) {
cb(result)
})
+
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
+ socket.on(inboundEvents.zniffer, async (data, cb = noop) => {
+ logger.info(`Zniffer api call: ${data.api}`)
+
+ let res: any, err: string
+ try {
+ switch (data.apiName) {
+ case 'start':
+ res = await zniffer.start()
+ break
+ case 'stop':
+ res = await zniffer.stop()
+ break
+ case 'capture':
+ res = await zniffer.saveCaptureToFile()
+ break
+ }
+ } catch (error) {
+ logger.error('Error while calling ZNIFFER api', error)
+ err = error.message
+ }
+
+ const result = {
+ success: !err,
+ message: err || 'Success ZNIFFER api call',
+ result: res,
+ api: data.apiName,
+ }
+
+ cb(result)
+ })
})
// emitted every time a new client connects/disconnects
diff --git a/api/config/store.ts b/api/config/store.ts
index eb6ae2492d..f27ce34f65 100644
--- a/api/config/store.ts
+++ b/api/config/store.ts
@@ -2,6 +2,7 @@
import { GatewayConfig } from '../lib/Gateway'
import { MqttConfig } from '../lib/MqttClient'
+import { ZnifferConfig } from '../lib/ZnifferManager'
import { ZwaveConfig, deviceConfigPriorityDir } from '../lib/ZwaveClient'
export type StoreKeys = 'settings' | 'scenes' | 'nodes' | 'users'
@@ -21,6 +22,7 @@ export interface Settings {
mqtt?: MqttConfig
zwave?: ZwaveConfig
gateway?: GatewayConfig
+ zniffer?: ZnifferConfig
}
const store: Record = {
diff --git a/api/lib/SocketEvents.ts b/api/lib/SocketEvents.ts
index ee4d183628..7a9e427cba 100644
--- a/api/lib/SocketEvents.ts
+++ b/api/lib/SocketEvents.ts
@@ -19,6 +19,8 @@ export enum socketEvents {
grantSecurityClasses = 'GRANT_SECURITY_CLASSES',
validateDSK = 'VALIDATE_DSK',
inclusionAborted = 'INCLUSION_ABORTED',
+ znifferFrame = 'ZNIFFER_FRAME',
+ znifferError = 'ZNIFFER_ERROR',
}
// events from client ---> server
@@ -27,4 +29,5 @@ export enum inboundEvents {
zwave = 'ZWAVE_API', // call a zwave api
hass = 'HASS_API', // call an hass api
mqtt = 'MQTT_API', // call an mqtt api
+ zniffer = 'ZNIFFER_API', // call a zniffer api
}
diff --git a/api/lib/ZnifferManager.ts b/api/lib/ZnifferManager.ts
new file mode 100644
index 0000000000..21716c66b6
--- /dev/null
+++ b/api/lib/ZnifferManager.ts
@@ -0,0 +1,147 @@
+import { CommandClass, Frame, Zniffer, ZnifferOptions } from 'zwave-js'
+import { TypedEventEmitter } from './EventEmitter'
+import { module } from './logger'
+import { Server as SocketServer } from 'socket.io'
+import { socketEvents } from './SocketEvents'
+import { ZwaveConfig } from './ZwaveClient'
+import { base, logsDir, storeDir } from '../config/app'
+import { joinPath, parseSecurityKeys } from './utils'
+import { isDocker } from '@zwave-js/shared'
+import { basename } from 'path'
+
+// eslint-disable-next-line @typescript-eslint/no-var-requires
+const loglevels = require('triple-beam').configs.npm.levels
+
+export type ZnifferConfig = Pick<
+ ZwaveConfig,
+ | 'securityKeys'
+ | 'securityKeysLongRange'
+ | 'maxFiles'
+ | 'logEnabled'
+ | 'logToFile'
+ | 'logLevel'
+> & {
+ port: string
+ enabled: boolean
+ convertRSSI?: boolean
+ defaultFrequency?: number
+}
+
+export interface ZnifferManagerEventCallbacks {}
+
+const logger = module('ZnifferManager')
+
+const ZNIFFER_LOG_FILE = joinPath(logsDir, 'zniffer_%DATE%.log')
+const ZNIFFER_CAPTURE_FILE = joinPath(storeDir, 'zniffer_capture_%DATE%.zlf')
+
+export type SocketFrame = Frame & { parsedPayload?: string; corrupted: boolean }
+
+export default class ZnifferManager extends TypedEventEmitter {
+ private zniffer: Zniffer
+
+ private config: ZnifferConfig
+
+ private socket: SocketServer
+
+ private error: string
+
+ constructor(config: ZnifferConfig, socket: SocketServer) {
+ super()
+
+ this.config = config
+ this.socket = socket
+
+ if (!config.enabled) {
+ logger.info('Zniffer is DISABLED')
+ return
+ }
+
+ const znifferOptions: ZnifferOptions = {
+ convertRSSI: config.convertRSSI,
+ defaultFrequency: config.defaultFrequency,
+ logConfig: {
+ enabled: config.logEnabled,
+ level: config.logLevel ? loglevels[config.logLevel] : 'info',
+ logToFile: config.logToFile,
+ filename: ZNIFFER_LOG_FILE,
+ forceConsole: isDocker() ? !config.logToFile : false,
+ maxFiles: config.maxFiles,
+ },
+ }
+
+ parseSecurityKeys(config, znifferOptions)
+
+ this.zniffer = new Zniffer(config.port, znifferOptions)
+
+ logger.info('Initing Zniffer...')
+ this.zniffer.init().catch((error) => this.onError(error))
+ }
+
+ private onError(error: Error) {
+ logger.error('Zniffer error:', error)
+ this.error = error.message
+ this.socket.emit(socketEvents.znifferError, error)
+ }
+
+ public async close() {
+ this.zniffer.removeAllListeners()
+ await this.stop()
+ }
+
+ public async start() {
+ logger.info('Starting...')
+ await this.zniffer.start()
+
+ logger.info('ZnifferManager started')
+
+ this.zniffer.on('frame', (frame) => {
+ const socketFrame: SocketFrame = { ...frame, corrupted: false }
+
+ // try parsing payload to something human-readable
+ const payload: CommandClass | Buffer = (frame as any).payload
+
+ if (payload instanceof CommandClass) {
+ socketFrame.parsedPayload = payload.toLogEntry(
+ this.zniffer,
+ ).message
+ }
+
+ this.socket.emit(socketEvents.znifferFrame, socketFrame)
+ })
+
+ this.zniffer.on('corrupted frame', (frame) => {
+ const socketFrame: SocketFrame = { ...frame, corrupted: true }
+
+ this.socket.emit(socketEvents.znifferFrame, socketFrame)
+ })
+
+ this.zniffer.on('error', (error) => {
+ this.onError(error)
+ })
+
+ this.zniffer.on('ready', () => {
+ logger.info('Zniffer ready')
+ })
+ }
+
+ public async stop() {
+ logger.info('Stopping...')
+ await this.zniffer.stop()
+
+ logger.info('ZnifferManager stopped')
+ }
+
+ public async saveCaptureToFile() {
+ const filePath = ZNIFFER_CAPTURE_FILE.replace(
+ '%DATE%',
+ new Date().toISOString(),
+ )
+ logger.info(`Saving capture to ${filePath}`)
+ await this.zniffer.saveCaptureToFile(filePath)
+ logger.info('Capture saved')
+ return {
+ path: filePath,
+ name: basename(filePath),
+ }
+ }
+}
diff --git a/api/lib/ZwaveClient.ts b/api/lib/ZwaveClient.ts
index ff731d7b19..31576be00e 100644
--- a/api/lib/ZwaveClient.ts
+++ b/api/lib/ZwaveClient.ts
@@ -2236,64 +2236,15 @@ class ZwaveClient extends TypedEventEmitter {
this.cfg.securityKeys = this.cfg.securityKeys || {}
+ // update settings to fix compatibility
if (s0Key && !this.cfg.securityKeys.S0_Legacy) {
this.cfg.securityKeys.S0_Legacy = s0Key
const settings = jsonStore.get(store.settings)
settings.zwave = this.cfg
await jsonStore.put(store.settings, settings)
- } else if (process.env.NETWORK_KEY) {
- this.cfg.securityKeys.S0_Legacy = process.env.NETWORK_KEY
}
- const availableKeys = [
- 'S2_Unauthenticated',
- 'S2_Authenticated',
- 'S2_AccessControl',
- 'S0_Legacy',
- ]
-
- const envKeys = Object.keys(process.env)
- .filter((k) => k?.startsWith('KEY_'))
- .map((k) => k.substring(4))
-
- // load security keys from env
- for (const k of envKeys) {
- if (availableKeys.includes(k)) {
- this.cfg.securityKeys[k] = process.env[`KEY_${k}`]
- }
- }
-
- zwaveOptions.securityKeys = {}
- zwaveOptions.securityKeysLongRange = {}
-
- // convert security keys to buffer
- for (const key in this.cfg.securityKeys) {
- if (
- availableKeys.includes(key) &&
- this.cfg.securityKeys[key].length === 32
- ) {
- zwaveOptions.securityKeys[key] = Buffer.from(
- this.cfg.securityKeys[key],
- 'hex',
- )
- }
- }
-
- this.cfg.securityKeysLongRange =
- this.cfg.securityKeysLongRange || {}
-
- // convert security keys to buffer
- for (const key in this.cfg.securityKeysLongRange) {
- if (
- availableKeys.includes(key) &&
- this.cfg.securityKeysLongRange[key].length === 32
- ) {
- zwaveOptions.securityKeysLongRange[key] = Buffer.from(
- this.cfg.securityKeysLongRange[key],
- 'hex',
- )
- }
- }
+ utils.parseSecurityKeys(this.cfg, zwaveOptions)
try {
// init driver here because if connect fails the driver is destroyed
diff --git a/api/lib/utils.ts b/api/lib/utils.ts
index 099279cae4..2f00e96e5d 100644
--- a/api/lib/utils.ts
+++ b/api/lib/utils.ts
@@ -1,8 +1,9 @@
// eslint-disable-next-line one-var
-import { ValueID } from 'zwave-js'
+import { PartialZWaveOptions, ValueID, ZnifferOptions } from 'zwave-js'
import path, { resolve } from 'path'
import crypto from 'crypto'
import { readFileSync } from 'fs'
+import type { ZwaveConfig } from './ZwaveClient'
// don't use import here, it will break the build
// eslint-disable-next-line @typescript-eslint/no-var-requires
@@ -311,3 +312,63 @@ export function parseJSON(str: string): any {
return v
})
}
+
+export function parseSecurityKeys(
+ config: ZwaveConfig,
+ options: PartialZWaveOptions | ZnifferOptions,
+): void {
+ config.securityKeys = config.securityKeys || {}
+
+ if (process.env.NETWORK_KEY) {
+ config.securityKeys.S0_Legacy = process.env.NETWORK_KEY
+ }
+
+ const availableKeys = [
+ 'S2_Unauthenticated',
+ 'S2_Authenticated',
+ 'S2_AccessControl',
+ 'S0_Legacy',
+ ]
+
+ const envKeys = Object.keys(process.env)
+ .filter((k) => k?.startsWith('KEY_'))
+ .map((k) => k.substring(4))
+
+ // load security keys from env
+ for (const k of envKeys) {
+ if (availableKeys.includes(k)) {
+ config.securityKeys[k] = process.env[`KEY_${k}`]
+ }
+ }
+
+ options.securityKeys = {}
+ options.securityKeysLongRange = {}
+
+ // convert security keys to buffer
+ for (const key in config.securityKeys) {
+ if (
+ availableKeys.includes(key) &&
+ config.securityKeys[key].length === 32
+ ) {
+ options.securityKeys[key] = Buffer.from(
+ config.securityKeys[key],
+ 'hex',
+ )
+ }
+ }
+
+ config.securityKeysLongRange = config.securityKeysLongRange || {}
+
+ // convert security keys to buffer
+ for (const key in config.securityKeysLongRange) {
+ if (
+ availableKeys.includes(key) &&
+ config.securityKeysLongRange[key].length === 32
+ ) {
+ options.securityKeysLongRange[key] = Buffer.from(
+ config.securityKeysLongRange[key],
+ 'hex',
+ )
+ }
+ }
+}
diff --git a/src/stores/base.js b/src/stores/base.js
index 5f0af0cd28..9ee1602bff 100644
--- a/src/stores/base.js
+++ b/src/stores/base.js
@@ -35,7 +35,6 @@ const useBaseStore = defineStore('base', {
measured0dBm: undefined,
},
},
- logEnabled: true,
securityKeys: {
S2_Unauthenticated: '',
S2_Authenticated: '',
@@ -47,6 +46,7 @@ const useBaseStore = defineStore('base', {
S2_AccessControl: '',
},
deviceConfigPriorityDir: '',
+ logEnabled: true,
logToFile: true,
maxFiles: 7,
serverEnabled: false,
@@ -81,6 +81,25 @@ const useBaseStore = defineStore('base', {
username: undefined,
password: undefined,
},
+ zniffer: {
+ enabled: false,
+ port: '',
+ logEnabled: true,
+ logToFile: true,
+ maxFiles: 7,
+ securityKeys: {
+ S2_Unauthenticated: '',
+ S2_Authenticated: '',
+ S2_AccessControl: '',
+ S0_Legacy: '',
+ },
+ securityKeysLongRange: {
+ S2_Authenticated: '',
+ S2_AccessControl: '',
+ },
+ convertRSSI: false,
+ defaultFrequency: undefined,
+ },
devices: [],
gateway: {
type: 0,
From 85692379caa34ddf2097aa0d47bf3cd98435f82b Mon Sep 17 00:00:00 2001
From: Daniel Lando
Date: Wed, 8 May 2024 14:04:41 +0200
Subject: [PATCH 002/120] fix: recursive frame parsing
---
api/app.ts | 1 +
api/lib/ZnifferManager.ts | 57 ++++--
src/stores/base.js | 1 +
src/views/Settings.vue | 420 +++++++++++++++++++++++++++++++++++---
4 files changed, 436 insertions(+), 43 deletions(-)
diff --git a/api/app.ts b/api/app.ts
index 71e3f4c0bd..a6bf00bb93 100644
--- a/api/app.ts
+++ b/api/app.ts
@@ -1115,6 +1115,7 @@ app.post(
restarting = true
await jsonStore.put(store.settings, settings)
await gw.close()
+ await zniffer.close()
await destroyPlugins()
// reload loggers settings
setupLogging(settings)
diff --git a/api/lib/ZnifferManager.ts b/api/lib/ZnifferManager.ts
index 21716c66b6..8659e83bd5 100644
--- a/api/lib/ZnifferManager.ts
+++ b/api/lib/ZnifferManager.ts
@@ -1,10 +1,18 @@
-import { CommandClass, Frame, Zniffer, ZnifferOptions } from 'zwave-js'
+import {
+ CommandClass,
+ CorruptedFrame,
+ Frame,
+ isEncapsulatingCommandClass,
+ isMultiEncapsulatingCommandClass,
+ Zniffer,
+ ZnifferOptions,
+} from 'zwave-js'
import { TypedEventEmitter } from './EventEmitter'
import { module } from './logger'
import { Server as SocketServer } from 'socket.io'
import { socketEvents } from './SocketEvents'
import { ZwaveConfig } from './ZwaveClient'
-import { base, logsDir, storeDir } from '../config/app'
+import { logsDir, storeDir } from '../config/app'
import { joinPath, parseSecurityKeys } from './utils'
import { isDocker } from '@zwave-js/shared'
import { basename } from 'path'
@@ -20,6 +28,7 @@ export type ZnifferConfig = Pick<
| 'logEnabled'
| 'logToFile'
| 'logLevel'
+ | 'nodeFilter'
> & {
port: string
enabled: boolean
@@ -34,7 +43,10 @@ const logger = module('ZnifferManager')
const ZNIFFER_LOG_FILE = joinPath(logsDir, 'zniffer_%DATE%.log')
const ZNIFFER_CAPTURE_FILE = joinPath(storeDir, 'zniffer_capture_%DATE%.zlf')
-export type SocketFrame = Frame & { parsedPayload?: string; corrupted: boolean }
+export type SocketFrame = (Frame | CorruptedFrame) & {
+ parsedPayload?: Record
+ corrupted: boolean
+}
export default class ZnifferManager extends TypedEventEmitter {
private zniffer: Zniffer
@@ -65,7 +77,11 @@ export default class ZnifferManager extends TypedEventEmitter 0
+ ? config.nodeFilter.map((n) => parseInt(n))
+ : undefined,
},
}
@@ -83,9 +99,29 @@ export default class ZnifferManager extends TypedEventEmitter {
+ const parsed: Record = commandClass.toLogEntry(
+ this.zniffer as any,
+ ).message
+
+ if (isEncapsulatingCommandClass(commandClass)) {
+ parsed.encapsulated = [
+ this.ccToLogRecord(commandClass.encapsulated),
+ ]
+ } else if (isMultiEncapsulatingCommandClass(commandClass)) {
+ parsed.encapsulated = [
+ commandClass.encapsulated.map((cc) => this.ccToLogRecord(cc)),
+ ]
+ }
+
+ return parsed
+ }
+
public async close() {
- this.zniffer.removeAllListeners()
- await this.stop()
+ if (this.zniffer) {
+ this.zniffer.removeAllListeners()
+ await this.stop()
+ }
}
public async start() {
@@ -97,13 +133,8 @@ export default class ZnifferManager extends TypedEventEmitter {
const socketFrame: SocketFrame = { ...frame, corrupted: false }
- // try parsing payload to something human-readable
- const payload: CommandClass | Buffer = (frame as any).payload
-
- if (payload instanceof CommandClass) {
- socketFrame.parsedPayload = payload.toLogEntry(
- this.zniffer,
- ).message
+ if ('payload' in frame && frame.payload instanceof CommandClass) {
+ socketFrame.parsedPayload = this.ccToLogRecord(frame.payload)
}
this.socket.emit(socketEvents.znifferFrame, socketFrame)
diff --git a/src/stores/base.js b/src/stores/base.js
index 9ee1602bff..331d961274 100644
--- a/src/stores/base.js
+++ b/src/stores/base.js
@@ -485,6 +485,7 @@ const useBaseStore = defineStore('base', {
this.zwave.rf.txPower = {}
}
Object.assign(this.mqtt, conf.mqtt || {})
+ Object.assign(this.zniffer, conf.zniffer || {})
Object.assign(this.gateway, conf.gateway || {})
Object.assign(this.backup, conf.backup || {})
Object.assign(this.ui, conf.ui || {})
diff --git a/src/views/Settings.vue b/src/views/Settings.vue
index acf108765c..38196086ff 100644
--- a/src/views/Settings.vue
+++ b/src/views/Settings.vue
@@ -51,7 +51,7 @@
-
+
General
@@ -476,7 +476,7 @@
-
+
Z-Wave
@@ -542,18 +542,22 @@
fixKey(
$event,
'S2_Unauthenticated',
+ newZwave.securityKeys,
)
"
:rules="[
rules.validKey,
rules.validLength,
- differentKeys(),
+ differentKeys(
+ newZwave.securityKeys,
+ ),
]"
persistent-hint
append-outer-icon="wifi_protected_setup"
@click:append-outer="
randomKey(
'S2_Unauthenticated',
+ newZwave.securityKeys,
)
"
>
@@ -568,6 +572,7 @@
fixKey(
$event,
'S2_Authenticated',
+ newZwave.securityKeys,
)
"
prepend-icon="vpn_key"
@@ -576,12 +581,15 @@
:rules="[
rules.validKey,
rules.validLength,
- differentKeys(),
+ differentKeys(
+ newZwave.securityKeys,
+ ),
]"
append-outer-icon="wifi_protected_setup"
@click:append-outer="
randomKey(
'S2_Authenticated',
+ newZwave.securityKeys,
)
"
>
@@ -596,6 +604,7 @@
fixKey(
$event,
'S2_AccessControl',
+ newZwave.securityKeys,
)
"
prepend-icon="vpn_key"
@@ -603,12 +612,15 @@
:rules="[
rules.validKey,
rules.validLength,
- differentKeys(),
+ differentKeys(
+ newZwave.securityKeys,
+ ),
]"
append-outer-icon="wifi_protected_setup"
@click:append-outer="
randomKey(
'S2_AccessControl',
+ newZwave.securityKeys,
)
"
>
@@ -627,11 +639,16 @@
:rules="[
rules.validKey,
rules.validLength,
- differentKeys(),
+ differentKeys(
+ newZwave.securityKeys,
+ ),
]"
append-outer-icon="wifi_protected_setup"
@click:append-outer="
- randomKey('S0_Legacy')
+ randomKey(
+ 'S0_Legacy',
+ newZwave.securityKeys,
+ )
"
>
@@ -658,7 +675,7 @@
fixKey(
$event,
'S2_Authenticated',
- true,
+ newZwave.securityKeysLongRange,
)
"
prepend-icon="vpn_key"
@@ -667,13 +684,15 @@
:rules="[
rules.validKey,
rules.validLength,
- differentKeys(true),
+ differentKeys(
+ newZwave.securityKeysLongRange,
+ ),
]"
append-outer-icon="wifi_protected_setup"
@click:append-outer="
randomKey(
'S2_Authenticated',
- true,
+ newZwave.securityKeysLongRange,
)
"
>
@@ -689,7 +708,7 @@
fixKey(
$event,
'S2_AccessControl',
- true,
+ newZwave.securityKeysLongRange,
)
"
prepend-icon="vpn_key"
@@ -697,13 +716,15 @@
:rules="[
rules.validKey,
rules.validLength,
- differentKeys(true),
+ differentKeys(
+ newZwave.securityKeysLongRange,
+ ),
]"
append-outer-icon="wifi_protected_setup"
@click:append-outer="
randomKey(
'S2_AccessControl',
- true,
+ newZwave.securityKeysLongRange,
)
"
>
@@ -964,6 +985,351 @@
+
+
+
+
+
+
+ Zniffer
+
+
+ Docs
+ launch
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Security Keys
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Security Keys (Long Range)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1443,6 +1809,7 @@
:devices="devices"
/>
+
{
- const keys = isLongRange
- ? this.newZwave.securityKeysLongRange
- : this.newZwave.securityKeys
- const values = Object.values(keys)
+ const values = Object.values(obj)
// ensure there are no duplicates
return (
@@ -1810,16 +2176,12 @@ export default {
)
}
},
- fixKey(event, key, isLongRange = false) {
+ fixKey(event, key, obj) {
let data = event.clipboardData?.getData('Text')
- const keys = isLongRange
- ? this.newZwave.securityKeysLongRange
- : this.newZwave.securityKeys
-
if (data) {
data = data.replace(/0x|,|\s/gi, '')
- this.$set(keys, key, data)
+ this.$set(obj, key, data)
event.preventDefault()
}
},
@@ -1844,11 +2206,7 @@ export default {
return item
}
},
- randomKey(k, isLongRange = false) {
- const keys = isLongRange
- ? this.newZwave.securityKeysLongRange
- : this.newZwave.securityKeys
-
+ randomKey(k, obj) {
let key = ''
while (key.length < 32) {
@@ -1858,7 +2216,7 @@ export default {
key += x.length === 2 ? x : '0' + x
}
- this.$set(keys, k, key)
+ this.$set(obj, k, key)
},
readFile(file, callback) {
const reader = new FileReader()
@@ -1900,6 +2258,7 @@ export default {
gateway: this.newGateway,
zwave: this.newZwave,
backup: this.newBackup,
+ zniffer: this.newZniffer,
ui: this.ui,
}
},
@@ -2065,6 +2424,7 @@ export default {
resetConfig() {
this.newGateway = copy(this.gateway)
this.newZwave = copy(this.zwave)
+ this.newZniffer = copy(this.zniffer)
this.newMqtt = copy(this.mqtt)
this.newBackup = copy(this.backup)
},
From 80e8fa04c1583144cca59662c815358eb0a36dcc Mon Sep 17 00:00:00 2001
From: Daniel Lando
Date: Wed, 8 May 2024 14:09:03 +0200
Subject: [PATCH 003/120] fix: build issues
---
api/lib/SocketManager.ts | 1 +
api/lib/ZnifferManager.ts | 2 +-
src/lib/SocketEvents.js | 11 +++++++----
3 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/api/lib/SocketManager.ts b/api/lib/SocketManager.ts
index 069bafb5aa..e768b40ccf 100644
--- a/api/lib/SocketManager.ts
+++ b/api/lib/SocketManager.ts
@@ -13,6 +13,7 @@ export interface SocketManagerEventCallbacks {
[inboundEvents.zwave]: (socket: Socket, data: any) => void
[inboundEvents.hass]: (socket: Socket, data: any) => void
[inboundEvents.mqtt]: (socket: Socket, data: any) => void
+ [inboundEvents.zniffer]: (socket: Socket, data: any) => void
clients: (
event: 'connection' | 'disconnect',
sockets: Map,
diff --git a/api/lib/ZnifferManager.ts b/api/lib/ZnifferManager.ts
index 8659e83bd5..341ad4d7b8 100644
--- a/api/lib/ZnifferManager.ts
+++ b/api/lib/ZnifferManager.ts
@@ -102,7 +102,7 @@ export default class ZnifferManager extends TypedEventEmitter {
const parsed: Record = commandClass.toLogEntry(
this.zniffer as any,
- ).message
+ )
if (isEncapsulatingCommandClass(commandClass)) {
parsed.encapsulated = [
diff --git a/src/lib/SocketEvents.js b/src/lib/SocketEvents.js
index 262fd4661a..67e6a82e8a 100644
--- a/src/lib/SocketEvents.js
+++ b/src/lib/SocketEvents.js
@@ -1,4 +1,4 @@
-export const socketEvents = {
+export const socketEvents = Object.freeze({
init: 'INIT', // automatically sent when a new client connects to the socket
controller: 'CONTROLLER_CMD', // controller status updates
connected: 'CONNECTED', // socket status
@@ -19,12 +19,15 @@ export const socketEvents = {
grantSecurityClasses: 'GRANT_SECURITY_CLASSES',
validateDSK: 'VALIDATE_DSK',
inclusionAborted: 'INCLUSION_ABORTED',
-}
+ znifferFrame: 'ZNIFFER_FRAME',
+ znifferError: 'ZNIFFER_ERROR',
+})
// events from client ---> server
-export const inboundEvents = {
+export const inboundEvents = Object.freeze({
init: 'INITED', // get all nodes
zwave: 'ZWAVE_API', // call a zwave api
hass: 'HASS_API', // call an hass api
mqtt: 'MQTT_API', // call an mqtt api
-}
+ zniffer: 'ZNIFFER_API', // call a zniffer api
+})
From cbe088c45bac6f2843b4ce4e174b21518e824401 Mon Sep 17 00:00:00 2001
From: Daniel Lando
Date: Wed, 8 May 2024 14:31:15 +0200
Subject: [PATCH 004/120] feat: start with ui implementation
---
api/lib/ZnifferManager.ts | 13 +++-
src/App.vue | 5 ++
src/router/index.js | 11 +++
src/views/Zniffer.vue | 149 ++++++++++++++++++++++++++++++++++++++
4 files changed, 176 insertions(+), 2 deletions(-)
create mode 100644 src/views/Zniffer.vue
diff --git a/api/lib/ZnifferManager.ts b/api/lib/ZnifferManager.ts
index 341ad4d7b8..8e739d77c5 100644
--- a/api/lib/ZnifferManager.ts
+++ b/api/lib/ZnifferManager.ts
@@ -46,6 +46,7 @@ const ZNIFFER_CAPTURE_FILE = joinPath(storeDir, 'zniffer_capture_%DATE%.zlf')
export type SocketFrame = (Frame | CorruptedFrame) & {
parsedPayload?: Record
corrupted: boolean
+ timestamp: number
}
export default class ZnifferManager extends TypedEventEmitter {
@@ -131,7 +132,11 @@ export default class ZnifferManager extends TypedEventEmitter {
- const socketFrame: SocketFrame = { ...frame, corrupted: false }
+ const socketFrame: SocketFrame = {
+ ...frame,
+ corrupted: false,
+ timestamp: Date.now(),
+ }
if ('payload' in frame && frame.payload instanceof CommandClass) {
socketFrame.parsedPayload = this.ccToLogRecord(frame.payload)
@@ -141,7 +146,11 @@ export default class ZnifferManager extends TypedEventEmitter {
- const socketFrame: SocketFrame = { ...frame, corrupted: true }
+ const socketFrame: SocketFrame = {
+ ...frame,
+ corrupted: true,
+ timestamp: Date.now(),
+ }
this.socket.emit(socketEvents.znifferFrame, socketFrame)
})
diff --git a/src/App.vue b/src/App.vue
index 635abfb542..ef4ffd5a6e 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -562,6 +562,11 @@ export default {
title: 'Control Panel',
path: Routes.controlPanel,
},
+ {
+ icon: 'preview',
+ title: 'Zniffer',
+ path: Routes.zniffer,
+ },
{
icon: 'qr_code_scanner',
title: 'Smart Start',
diff --git a/src/router/index.js b/src/router/index.js
index e1709120a1..814c6bb074 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -12,6 +12,7 @@ const Login = () => import('@/views/Login.vue')
const ErrorPage = () => import('@/views/ErrorPage.vue')
const SmartStart = () => import('@/views/SmartStart.vue')
const ControllerChart = () => import('@/views/ControllerChart.vue')
+const Zniffer = () => import('@/views/Zniffer.vue')
import ConfigApis from '../apis/ConfigApis'
import useBaseStore from '../stores/base'
@@ -29,6 +30,7 @@ export const Routes = {
mesh: '/mesh',
smartStart: '/smart-start',
controllerChart: '/controller-chart',
+ zniffer: '/zniffer',
}
Routes.main = Routes.controlPanel
@@ -55,6 +57,15 @@ const router = new Router({
requiresAuth: true,
},
},
+ {
+ path: Routes.zniffer,
+ name: 'Zniffer',
+ component: Zniffer,
+ props: true,
+ meta: {
+ requiresAuth: true,
+ },
+ },
{
path: Routes.smartStart,
name: 'Smart Start',
diff --git a/src/views/Zniffer.vue b/src/views/Zniffer.vue
new file mode 100644
index 0000000000..482cc3f156
--- /dev/null
+++ b/src/views/Zniffer.vue
@@ -0,0 +1,149 @@
+
+
+
+
+ Start
+ Stop
+ Capture
+
+
+
+
+
+
+
+
+ {{ new Date(item.timestamp).toLocaleString() }}
+
+
+
+ {{ item.type }}
+
+
+
+
+ {{ jsonToList(item.parsedPayload) }}
+
+
+ {{ item.payload }}
+
+ ---
+
+
+
+
+
+
+
+ Zniffer is disabled, enable it in settings
+
+
+
+
+
+
From 1e37d204db6781350c512528ff74a82a063d2701 Mon Sep 17 00:00:00 2001
From: Daniel Lando
Date: Wed, 8 May 2024 15:23:30 +0200
Subject: [PATCH 005/120] feat: add cc tree view
---
api/lib/ZnifferManager.ts | 8 +++
src/components/custom/CCTreeView.vue | 88 ++++++++++++++++++++++++++++
src/views/Zniffer.vue | 25 ++++++--
3 files changed, 117 insertions(+), 4 deletions(-)
create mode 100644 src/components/custom/CCTreeView.vue
diff --git a/api/lib/ZnifferManager.ts b/api/lib/ZnifferManager.ts
index 8e739d77c5..8ffa05299e 100644
--- a/api/lib/ZnifferManager.ts
+++ b/api/lib/ZnifferManager.ts
@@ -49,6 +49,14 @@ export type SocketFrame = (Frame | CorruptedFrame) & {
timestamp: number
}
+export interface FrameCCLogEntry {
+ tags: string[]
+ message?: {
+ encapsulated?: FrameCCLogEntry[]
+ [key: string]: string | number | boolean | FrameCCLogEntry[]
+ }
+}
+
export default class ZnifferManager extends TypedEventEmitter {
private zniffer: Zniffer
diff --git a/src/components/custom/CCTreeView.vue b/src/components/custom/CCTreeView.vue
new file mode 100644
index 0000000000..84df250e52
--- /dev/null
+++ b/src/components/custom/CCTreeView.vue
@@ -0,0 +1,88 @@
+
+
+
+
+
diff --git a/src/views/Zniffer.vue b/src/views/Zniffer.vue
index 482cc3f156..00413de2c1 100644
--- a/src/views/Zniffer.vue
+++ b/src/views/Zniffer.vue
@@ -32,9 +32,11 @@
-
- {{ jsonToList(item.parsedPayload) }}
-
+
+
{{ item.payload }}
@@ -65,7 +67,9 @@ export default {
props: {
socket: Object,
},
- watch: {},
+ components: {
+ ccTreeView: () => import('../components/custom/CCTreeView.vue'),
+ },
computed: {
...mapState(useBaseStore, ['zniffer']),
},
@@ -127,6 +131,19 @@ export default {
this.showSnackbar(`Zniffer stopped`, 'success')
}
},
+ async createCapture() {
+ const response = await this.sendAction({
+ apiName: 'saveCaptureToFile',
+ })
+
+ if (response.success) {
+ const result = response.result
+ this.showSnackbar(
+ `Capture "${result.name}" created in store`,
+ 'success',
+ )
+ }
+ },
},
mounted() {
// init socket events
From bd073a1c7bfcec651753a3c6883f869a1ead4270 Mon Sep 17 00:00:00 2001
From: Daniel Lando
Date: Wed, 8 May 2024 16:46:21 +0200
Subject: [PATCH 006/120] fix: add some other props to table
---
api/app.ts | 4 ++-
src/App.vue | 53 +++++++++++++++++-------------
src/views/Zniffer.vue | 76 ++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 109 insertions(+), 24 deletions(-)
diff --git a/api/app.ts b/api/app.ts
index a6bf00bb93..790f087a01 100644
--- a/api/app.ts
+++ b/api/app.ts
@@ -1115,7 +1115,9 @@ app.post(
restarting = true
await jsonStore.put(store.settings, settings)
await gw.close()
- await zniffer.close()
+ if (zniffer) {
+ await zniffer.close()
+ }
await destroyPlugins()
// reload loggers settings
setupLogging(settings)
diff --git a/src/App.vue b/src/App.vue
index ef4ffd5a6e..959c890b0f 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -439,11 +439,42 @@ export default {
'auth',
'appInfo',
'controllerNode',
+ 'zniffer',
]),
...mapState(useBaseStore, {
darkMode: (store) => store.ui.darkMode,
navTabs: (store) => store.ui.navTabs,
}),
+ pages() {
+ const pages = [
+ {
+ icon: 'widgets',
+ title: 'Control Panel',
+ path: Routes.controlPanel,
+ },
+
+ {
+ icon: 'qr_code_scanner',
+ title: 'Smart Start',
+ path: Routes.smartStart,
+ },
+ { icon: 'settings', title: 'Settings', path: Routes.settings },
+ { icon: 'movie_filter', title: 'Scenes', path: Routes.scenes },
+ { icon: 'bug_report', title: 'Debug', path: Routes.debug },
+ { icon: 'folder', title: 'Store', path: Routes.store },
+ { icon: 'share', title: 'Network graph', path: Routes.mesh },
+ ]
+
+ if (this.zniffer?.enabled) {
+ pages.splice(1, 0, {
+ icon: 'preview',
+ title: 'Zniffer',
+ path: Routes.zniffer,
+ })
+ }
+
+ return pages
+ },
updateAvailable() {
return this.appInfo.newConfigVersion ? 1 : 0
},
@@ -556,28 +587,6 @@ export default {
tooltip: 'Logout',
},
],
- pages: [
- {
- icon: 'widgets',
- title: 'Control Panel',
- path: Routes.controlPanel,
- },
- {
- icon: 'preview',
- title: 'Zniffer',
- path: Routes.zniffer,
- },
- {
- icon: 'qr_code_scanner',
- title: 'Smart Start',
- path: Routes.smartStart,
- },
- { icon: 'settings', title: 'Settings', path: Routes.settings },
- { icon: 'movie_filter', title: 'Scenes', path: Routes.scenes },
- { icon: 'bug_report', title: 'Debug', path: Routes.debug },
- { icon: 'folder', title: 'Store', path: Routes.store },
- { icon: 'share', title: 'Network graph', path: Routes.mesh },
- ],
status: '',
statusColor: '',
drawer: false,
diff --git a/src/views/Zniffer.vue b/src/views/Zniffer.vue
index 00413de2c1..05cac1777a 100644
--- a/src/views/Zniffer.vue
+++ b/src/views/Zniffer.vue
@@ -27,8 +27,24 @@
{{ new Date(item.timestamp).toLocaleString() }}
+
+ {{ item.channel }}
+
+
+
+ {{ getRegion(item.region) }}
+
+
+
+ {{ getRssi(item) }}
+
+
+
+ {{ getProtocolDataRate(item) }}
+
+
- {{ item.type }}
+ {{ getType(item) }}
@@ -42,6 +58,10 @@
---
+
+
+ {{ getRepeaters(item) }}
+
@@ -55,12 +75,20 @@
+
+
diff --git a/src/components/custom/MultipaneResizer.vue b/src/components/custom/MultipaneResizer.vue
new file mode 100644
index 0000000000..7413ccf73b
--- /dev/null
+++ b/src/components/custom/MultipaneResizer.vue
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/lib/SocketEvents.js b/src/lib/SocketEvents.js
index 67e6a82e8a..9641d9f806 100644
--- a/src/lib/SocketEvents.js
+++ b/src/lib/SocketEvents.js
@@ -20,7 +20,7 @@ export const socketEvents = Object.freeze({
validateDSK: 'VALIDATE_DSK',
inclusionAborted: 'INCLUSION_ABORTED',
znifferFrame: 'ZNIFFER_FRAME',
- znifferError: 'ZNIFFER_ERROR',
+ znifferState: 'ZNIFFER_STATE',
})
// events from client ---> server
diff --git a/src/stores/base.js b/src/stores/base.js
index 7cf51fa105..e515d91910 100644
--- a/src/stores/base.js
+++ b/src/stores/base.js
@@ -127,6 +127,10 @@ const useBaseStore = defineStore('base', {
controllerStatus: 'Unknown',
newConfigVersion: undefined,
},
+ znifferState: {
+ error: '',
+ started: false,
+ },
ui: {
darkMode: settings.load('dark', false),
navTabs: settings.load('navTabs', false),
@@ -189,6 +193,10 @@ const useBaseStore = defineStore('base', {
this.appInfo.serverVersion = data.serverVersion
this.appInfo.newConfigVersion = data.newConfigVersion
},
+ setZnifferState(data) {
+ this.znifferState.error = data?.error || ''
+ this.znifferState.started = data?.started || false
+ },
setValue(valueId) {
const toReplace = this.getValue(valueId)
const node = this.getNode(valueId.nodeId)
diff --git a/src/views/Zniffer.vue b/src/views/Zniffer.vue
index 3915e87932..78a7eef6c5 100644
--- a/src/views/Zniffer.vue
+++ b/src/views/Zniffer.vue
@@ -1,77 +1,144 @@
-
-
-
- Start
- Stop
- Capture
-
-
-
-
-
-
-
-
- {{ new Date(item.timestamp).toLocaleString() }}
-
-
-
- {{ item.channel }}
-
-
-
- {{ getRegion(item.region) }}
-
-
-
- {{ getRssi(item) }}
-
-
-
- {{ getProtocolDataRate(item) }}
-
-
-
- {{ getType(item) }}
-
-
-
-
+
+
+
+
+ Start
-
-
- {{ item.payload }}
-
- ---
-
-
-
- {{ getRepeaters(item) }}
-
-
-
-
-
-
-
- Zniffer is disabled, enable it in settings
-
-
-
+
Stop
+
Capture
+
+
+
+
+
+
+
+
+ {{ new Date(item.timestamp).toLocaleString() }}
+
+
+
+ {{ item.channel }}
+
+
+
+ {{ getRegion(item.region) }}
+
+
+
+ {{ getRssi(item) }}
+
+
+
+ {{ getProtocolDataRate(item) }}
+
+
+
+ {{ getType(item) }}
+
+
+
+
+
+
+ {{ item.payload.data }}
+
+ ---
+
+
+
+ {{ getRepeaters(item) }}
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ Zniffer is disabled, enable it in
+ settings
+
+
+
+
+
+
+
- this.socket.on(socketEvents.znifferFrame, (data) => {
- this.frames.push(data)
+
From 2fde83fd958a1ffb63ad223cbe76e5eb53e630ba Mon Sep 17 00:00:00 2001
From: Daniel Lando
Date: Fri, 10 May 2024 16:32:51 +0200
Subject: [PATCH 012/120] fix: improvements on scroll
---
src/views/Zniffer.vue | 56 ++++++++++++++++---------------------------
1 file changed, 21 insertions(+), 35 deletions(-)
diff --git a/src/views/Zniffer.vue b/src/views/Zniffer.vue
index 78a7eef6c5..818c1f2cb8 100644
--- a/src/views/Zniffer.vue
+++ b/src/views/Zniffer.vue
@@ -38,6 +38,7 @@
:headers="headers"
:items="framesLimited"
dense
+ v-scroll.self="onScroll"
:style="{
height: `${topPaneHeight - 80}px`,
maxHeight: `${topPaneHeight - 80}px`,
@@ -95,27 +96,33 @@
-
+
-
+ /> -->
|
-
+
-
+
|
@@ -175,6 +182,13 @@ export default {
totalFrames() {
return this.frames.length
},
+ startHeight() {
+ return this.start * this.rowHeight
+ },
+ endHeight() {
+ const lastIndex = this.start + this.perPage
+ return this.rowHeight * (this.totalFrames - lastIndex + 1)
+ },
},
mounted() {
this.socket.on(socketEvents.znifferFrame, (data) => {
@@ -218,7 +232,6 @@ export default {
data() {
return {
start: 0,
- endIndex: 22,
busy: false,
rowHeight: 32,
perPage: 22,
@@ -251,9 +264,6 @@ export default {
const el = this.$refs.framesTable?.$el
if (el) {
el.scrollTo(0, el.scrollHeight)
- this.$nextTick(() => {
- this.loadMore(null, null, true)
- })
}
},
scrollToRow(index) {
@@ -283,31 +293,7 @@ export default {
e.target.scrollTop = scrollTop
}, 10)
},
- loadMore(entries, observer, isIntersecting) {
- if (isIntersecting) {
- const indexesLeft = this.totalFrames - this.endIndex
- if (indexesLeft < this.perPage) {
- this.start = this.endIndex + indexesLeft - this.perPage
- this.endIndex = this.totalFrames
- } else {
- this.inventoryStartIndex += this.perPage
- this.endIndex += this.perPage
- }
- this.scrollToRow(this.perPage)
- }
- },
- loadLess(entries, observer, isIntersecting) {
- if (isIntersecting) {
- if (this.start < this.perPage) {
- this.start = 0
- this.endIndex = this.perPage
- } else {
- this.start -= this.perPage
- this.endIndex -= this.perPage
- }
- this.scrollToRow(5)
- }
- },
+
getRegion(region) {
return (
rfRegions.find((r) => r.value === region)?.text ||
From f057acee8cf455e66bc82b9315727efa735e2301 Mon Sep 17 00:00:00 2001
From: Daniel Lando
Date: Mon, 13 May 2024 16:37:19 +0200
Subject: [PATCH 013/120] fix: sticky header
---
src/views/Zniffer.vue | 33 ++++++++++++++++++++++++---------
1 file changed, 24 insertions(+), 9 deletions(-)
diff --git a/src/views/Zniffer.vue b/src/views/Zniffer.vue
index 818c1f2cb8..f5b1d7fa2a 100644
--- a/src/views/Zniffer.vue
+++ b/src/views/Zniffer.vue
@@ -37,8 +37,9 @@
- {{ getRegion(item.region) }}
-
-
{{ getRssi(item) }}
@@ -87,15 +83,11 @@
>
- {{ item.payload.data }}
+ {{ item.payload }}
---
-
- {{ getRepeaters(item) }}
-
-
Date: Mon, 13 May 2024 17:00:10 +0200
Subject: [PATCH 015/120] fix: cc not parsed
---
src/components/custom/CCTreeView.vue | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/components/custom/CCTreeView.vue b/src/components/custom/CCTreeView.vue
index 84df250e52..5ff96a5530 100644
--- a/src/components/custom/CCTreeView.vue
+++ b/src/components/custom/CCTreeView.vue
@@ -1,5 +1,5 @@
-
+
+
+
diff --git a/src/views/Zniffer.vue b/src/views/Zniffer.vue
index 4bf2ffbfec..4f156ca662 100644
--- a/src/views/Zniffer.vue
+++ b/src/views/Zniffer.vue
@@ -37,6 +37,8 @@
-
-
-
+
+ {{ item.parsedPayload.tags.join(' - ') }}
+
+
{{ item.payload }}
-
- ---
+
+ ---
@@ -135,8 +135,7 @@
@@ -155,6 +154,7 @@ import { mapState, mapActions } from 'pinia'
import useBaseStore from '../stores/base.js'
import { inboundEvents as socketActions } from '@server/lib/SocketEvents'
import { rfRegions } from '../lib/items.js'
+import { uuid } from '../lib/utils'
export default {
name: 'Zniffer',
@@ -162,10 +162,10 @@ export default {
socket: Object,
},
components: {
- ccTreeView: () => import('../components/custom/CCTreeView.vue'),
Multipane: () => import('../components/custom/Multipane.vue'),
MultipaneResizer: () =>
import('../components/custom/MultipaneResizer.vue'),
+ FrameDetails: () => import('../components//custom/FrameDetails.vue'),
},
computed: {
...mapState(useBaseStore, ['zniffer', 'znifferState']),
@@ -185,6 +185,7 @@ export default {
},
mounted() {
this.socket.on(socketEvents.znifferFrame, (data) => {
+ data.id = uuid()
this.frames.push(data)
this.bindScroll()
@@ -227,6 +228,7 @@ export default {
return {
start: 0,
busy: false,
+ selectedFrame: null,
scrollWrapper: null,
rowHeight: 32,
perPage: 22,
@@ -252,6 +254,15 @@ export default {
},
methods: {
...mapActions(useBaseStore, ['showSnackbar', 'setZnifferState']),
+ onRowClick(frame, { select, isSelected }) {
+ if (isSelected) {
+ this.selectedFrame = null
+ select(false)
+ } else {
+ this.selectedFrame = frame
+ select(true)
+ }
+ },
bindScroll() {
if (this.scrollWrapper) return
// find v-data-table__wrapper element inside #framesTable
From 10d5f9c18611b4a725350197661816079cabe09c Mon Sep 17 00:00:00 2001
From: Daniel Lando
Date: Tue, 14 May 2024 09:11:35 +0200
Subject: [PATCH 017/120] fix: scroll and resize
---
src/components/custom/FrameDetails.vue | 12 ++++++--
src/components/custom/Multipane.vue | 2 +-
src/views/Zniffer.vue | 42 ++++++++++++++++++++------
3 files changed, 42 insertions(+), 14 deletions(-)
diff --git a/src/components/custom/FrameDetails.vue b/src/components/custom/FrameDetails.vue
index 442297c9a5..e8eccb5bc0 100644
--- a/src/components/custom/FrameDetails.vue
+++ b/src/components/custom/FrameDetails.vue
@@ -1,9 +1,9 @@
-
+
{{ parsed }}
-
+
@@ -22,7 +22,13 @@ export default {
data: () => ({}),
computed: {
parsed() {
- return jsonToList(this.value, { ignore: ['parsedPayload', 'id'] })
+ if (!this.value) return ''
+
+ const ignore = ['id']
+ if (this.value.parsedPayload) {
+ ignore.push('parsedPayload', 'payload')
+ }
+ return jsonToList(this.value, { ignore })
},
},
methods: {},
diff --git a/src/components/custom/Multipane.vue b/src/components/custom/Multipane.vue
index 83847ad4ac..e4d8061e37 100644
--- a/src/components/custom/Multipane.vue
+++ b/src/components/custom/Multipane.vue
@@ -163,7 +163,7 @@ export default {
.multipane-resizer {
display: block;
position: relative;
- z-index: 2;
+ z-index: 2 !important;
margin: 0;
background-color: #ccc;
}
diff --git a/src/views/Zniffer.vue b/src/views/Zniffer.vue
index 4f156ca662..f7d5700a6c 100644
--- a/src/views/Zniffer.vue
+++ b/src/views/Zniffer.vue
@@ -3,12 +3,14 @@
-
+
+
+ {{ item.homeId?.toString(16) }}
+
+
{{ item.parsedPayload.tags.join(' - ') }}
@@ -134,7 +136,7 @@
-
+
@@ -183,12 +185,20 @@ export default {
return this.rowHeight * (this.totalFrames - lastIndex + 1)
},
},
+ watch: {
+ topPaneHeight(v) {
+ if (this.scrollWrapper) {
+ this.scrollWrapper.style.height = `${v - 80}px`
+ }
+ },
+ },
mounted() {
this.socket.on(socketEvents.znifferFrame, (data) => {
data.id = uuid()
+ const lastFrame = this.frames[this.frames.length - 1]
+ data.delta = lastFrame ? data.timestamp - lastFrame.timestamp : 0
this.frames.push(data)
- this.bindScroll()
this.scrollBottom()
})
@@ -202,7 +212,6 @@ export default {
}
this.ro = new ResizeObserver(onWindowResize)
-
this.ro.observe(this.$el)
onWindowResize()
@@ -215,6 +224,11 @@ export default {
this.ro.disconnect()
}
+ if (this.roTopPane) {
+ this.roTopPane.unobserve(this.$refs.topPane)
+ this.roTopPane.disconnect()
+ }
+
if (this.socket) {
// unbind events
this.socket.off(socketEvents.znifferFrame)
@@ -243,7 +257,7 @@ export default {
},
{ text: 'RSSI', value: 'rssi' },
{ text: 'Channel', value: 'channel' },
- { text: 'Delta', value: 'delta' },
+ { text: 'Delta [ms]', value: 'delta' },
{ text: 'Source', value: 'sourceNodeId' },
{ text: 'Destination', value: 'destinationNodeId' },
{ text: 'Home Id', value: 'homeId' },
@@ -263,6 +277,14 @@ export default {
select(true)
}
},
+ bindTopPaneObserver() {
+ const onTopPaneResize = (e) => {
+ this.topPaneHeight = e[0].contentRect.height
+ }
+
+ this.roTopPane = new ResizeObserver(onTopPaneResize)
+ this.roTopPane.observe(this.$refs.topPane)
+ },
bindScroll() {
if (this.scrollWrapper) return
// find v-data-table__wrapper element inside #framesTable
From 0a1677fb2da0302141045d0e6b7461c1d2c2012a Mon Sep 17 00:00:00 2001
From: Daniel Lando
Date: Tue, 14 May 2024 09:59:35 +0200
Subject: [PATCH 018/120] fix: protocol data rate
---
src/views/Zniffer.vue | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/views/Zniffer.vue b/src/views/Zniffer.vue
index f7d5700a6c..25a9659ff3 100644
--- a/src/views/Zniffer.vue
+++ b/src/views/Zniffer.vue
@@ -144,12 +144,12 @@
diff --git a/src/lib/utils.js b/src/lib/utils.js
index ae0fc9fd99..33ac654137 100644
--- a/src/lib/utils.js
+++ b/src/lib/utils.js
@@ -1,6 +1,18 @@
-import { isValidDSK, Protocols } from '@zwave-js/core/safe'
+import {
+ isValidDSK,
+ Protocols,
+ znifferProtocolDataRateToString,
+} from '@zwave-js/core/safe'
import colors from 'vuetify/lib/util/colors'
+import {
+ isRssiError,
+ rssiToString,
+ getEnumMemberName,
+ ZWaveFrameType,
+} from 'zwave-js/safe'
+import { znifferRegions } from './items'
+
export function copy(o) {
return JSON.parse(JSON.stringify(o))
}
@@ -202,3 +214,40 @@ export function getProtocolColor(node) {
return colors.grey.base
}
}
+
+export function getRegion(region) {
+ return (
+ znifferRegions.find((r) => r.value === region)?.text ||
+ `Unknown region ${region}`
+ )
+}
+export function getRepeaters(item) {
+ const repRSSI = item.repeaterRSSI || []
+ return item.repeaters?.length > 0
+ ? item.repeaters
+ .map(
+ (r, i) =>
+ `${r}${
+ repRSSI[i] && !isRssiError(repRSSI[i])
+ ? ` (${rssiToString(repRSSI[i])})`
+ : ''
+ }`,
+ )
+ .join(', ')
+ : 'None, direct connection'
+}
+export function getType(item) {
+ return getEnumMemberName(ZWaveFrameType, item.type)
+}
+export function getRssi(item) {
+ if (item.rssi && !isRssiError(item.rssi)) {
+ return rssiToString(item.rssi) + ' dBm'
+ }
+
+ return item.rssiRaw
+}
+export function getProtocolDataRate(item) {
+ return item.protocolDataRate !== undefined
+ ? znifferProtocolDataRateToString(item.protocolDataRate)
+ : '---'
+}
diff --git a/src/stores/base.js b/src/stores/base.js
index e515d91910..47a267ce1f 100644
--- a/src/stores/base.js
+++ b/src/stores/base.js
@@ -130,6 +130,7 @@ const useBaseStore = defineStore('base', {
znifferState: {
error: '',
started: false,
+ frequency: false,
},
ui: {
darkMode: settings.load('dark', false),
@@ -194,8 +195,9 @@ const useBaseStore = defineStore('base', {
this.appInfo.newConfigVersion = data.newConfigVersion
},
setZnifferState(data) {
- this.znifferState.error = data?.error || ''
- this.znifferState.started = data?.started || false
+ this.znifferState.error = data?.error ?? ''
+ this.znifferState.started = data?.started ?? false
+ this.znifferState.frequency = data?.frequency ?? false
},
setValue(valueId) {
const toReplace = this.getValue(valueId)
diff --git a/src/views/Zniffer.vue b/src/views/Zniffer.vue
index abe9422d25..f242d33b08 100644
--- a/src/views/Zniffer.vue
+++ b/src/views/Zniffer.vue
@@ -29,7 +29,7 @@
label="Search"
>
-
+
Save Capture
+
+
+
+
From b1dbff67434d61cc978070b2cc45fb2a8cee429f Mon Sep 17 00:00:00 2001
From: Dominic Griesel
Date: Tue, 14 May 2024 21:11:26 +0200
Subject: [PATCH 049/120] add trailing 0 to milliseconds
---
src/views/Zniffer.vue | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/views/Zniffer.vue b/src/views/Zniffer.vue
index ede964290d..5353d0783b 100644
--- a/src/views/Zniffer.vue
+++ b/src/views/Zniffer.vue
@@ -474,7 +474,9 @@ export default {
// format timestamp HH:mm:ss.fff
const date = new Date(timestamp)
const ms = date.getMilliseconds()
- return `${date.toTimeString().split(' ')[0]}.${ms}`
+ return `${date.toTimeString().split(' ')[0]}.${ms
+ .toString()
+ .padEnd(3, '0')}`
},
getRepeaters,
getType,
From e484a1c9ad03dfdf920de41dbf5a1e6b8ab56cfa Mon Sep 17 00:00:00 2001
From: Dominic Griesel
Date: Tue, 14 May 2024 21:13:09 +0200
Subject: [PATCH 050/120] fix double dBm in RSSI
---
src/lib/utils.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/lib/utils.js b/src/lib/utils.js
index 3b337790f8..af7fb5dd00 100644
--- a/src/lib/utils.js
+++ b/src/lib/utils.js
@@ -246,7 +246,7 @@ export function getType(item) {
}
export function getRssi(item) {
if (item.rssi && !isRssiError(item.rssi)) {
- return rssiToString(item.rssi) + ' dBm'
+ return rssiToString(item.rssi)
}
return item.rssiRaw
From 8a95870b55a33c574053451e4ea3fd5dbb20c528 Mon Sep 17 00:00:00 2001
From: Dominic Griesel
Date: Tue, 14 May 2024 21:15:41 +0200
Subject: [PATCH 051/120] fix typo
---
src/views/Zniffer.vue | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/views/Zniffer.vue b/src/views/Zniffer.vue
index 5353d0783b..bdf4da83a0 100644
--- a/src/views/Zniffer.vue
+++ b/src/views/Zniffer.vue
@@ -61,7 +61,7 @@
Date: Wed, 15 May 2024 08:43:24 +0200
Subject: [PATCH 052/120] fix: spacing and route info
---
src/components/custom/FrameDetails.vue | 12 +++++-------
src/lib/utils.js | 9 +++++----
src/views/Zniffer.vue | 4 ++--
3 files changed, 12 insertions(+), 13 deletions(-)
diff --git a/src/components/custom/FrameDetails.vue b/src/components/custom/FrameDetails.vue
index 708ae1ce62..0cef5d1ec1 100644
--- a/src/components/custom/FrameDetails.vue
+++ b/src/components/custom/FrameDetails.vue
@@ -12,14 +12,9 @@
Protocol |
{{ getProtocol(value) }} |
|
-
+
Payload |
-
-
- |
- {{ value.payload }} |
+ {{ value.payload }} |
Channel |
@@ -79,6 +74,9 @@
+
+
+
diff --git a/src/lib/utils.js b/src/lib/utils.js
index af7fb5dd00..91cf018074 100644
--- a/src/lib/utils.js
+++ b/src/lib/utils.js
@@ -223,6 +223,7 @@ export function getRegion(item) {
}
export function getRepeaters(item) {
const repRSSI = item.repeaterRSSI || []
+ const dir = item.direction === 'inbound' ? '←' : '→'
const repeatersString =
item.repeaters?.length > 0
? item.repeaters
@@ -234,12 +235,12 @@ export function getRepeaters(item) {
: ''
}`,
)
- .join(' > ')
+ .join(` ${dir} `)
: ''
- return `${item.sourceNodeId} >${
- repeatersString ? ' ' + repeatersString + ' ' : ''
- }> ${item.destinationNodeId}`
+ return `${item.sourceNodeId} ${
+ repeatersString ? ` ${dir} ${repeatersString} ${dir}` : dir
+ } ${item.destinationNodeId}`
}
export function getType(item) {
return getEnumMemberName(ZWaveFrameType, item.type)
diff --git a/src/views/Zniffer.vue b/src/views/Zniffer.vue
index bdf4da83a0..f7bb655f4f 100644
--- a/src/views/Zniffer.vue
+++ b/src/views/Zniffer.vue
@@ -1,5 +1,5 @@
-
+
-
+
Date: Wed, 15 May 2024 08:59:17 +0200
Subject: [PATCH 053/120] fix: route informations
---
src/components/custom/FrameDetails.vue | 14 +++-----------
src/lib/utils.js | 11 ++++++++---
src/views/Zniffer.vue | 11 +++++++----
3 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/src/components/custom/FrameDetails.vue b/src/components/custom/FrameDetails.vue
index 0cef5d1ec1..596c7c20c9 100644
--- a/src/components/custom/FrameDetails.vue
+++ b/src/components/custom/FrameDetails.vue
@@ -48,20 +48,12 @@
Route |
- {{ getRepeaters(value) }} |
+ |
Ack Requested |
{{ value.ackRequested }} |
-
- Direction |
- {{ value.direction }} |
-
-
- Hop |
- {{ value.hop }} |
-
Routed Ack |
{{ value.routedAck }} |
@@ -84,7 +76,7 @@
import {
jsonToList,
getRegion,
- getRepeaters,
+ getRoute,
getType,
getRssi,
getProtocol,
@@ -112,7 +104,7 @@ export default {
},
methods: {
getRegion,
- getRepeaters,
+ getRoute,
getType,
getRssi,
getProtocolDataRate,
diff --git a/src/lib/utils.js b/src/lib/utils.js
index 91cf018074..0887fbf1e1 100644
--- a/src/lib/utils.js
+++ b/src/lib/utils.js
@@ -221,19 +221,24 @@ export function getRegion(item) {
`Unknown region ${item?.region}`
)
}
-export function getRepeaters(item) {
+export function getRoute(item) {
const repRSSI = item.repeaterRSSI || []
const dir = item.direction === 'inbound' ? '←' : '→'
+ const hop = item.hop !== undefined ? item.hop : -1
const repeatersString =
item.repeaters?.length > 0
? item.repeaters
.map(
(r, i) =>
- `${r}${
+ `${
+ hop === i
+ ? ''
+ : ''
+ }${r}${
repRSSI[i] && !isRssiError(repRSSI[i])
? ` (${rssiToString(repRSSI[i])})`
: ''
- }`,
+ }${hop === i ? '' : ''}`,
)
.join(` ${dir} `)
: ''
diff --git a/src/views/Zniffer.vue b/src/views/Zniffer.vue
index f7bb655f4f..bb1a277b96 100644
--- a/src/views/Zniffer.vue
+++ b/src/views/Zniffer.vue
@@ -116,6 +116,10 @@
{{ getType(item) }}
+
+
+
+
{{ item.homeId?.toString(16) }}
@@ -192,7 +196,7 @@ import { inboundEvents as socketActions } from '@server/lib/SocketEvents'
import { znifferRegions } from '../lib/items.js'
import {
uuid,
- getRepeaters,
+ getRoute,
getType,
getRssi,
getProtocolDataRate,
@@ -322,8 +326,7 @@ export default {
{ text: 'RSSI', value: 'rssi' },
{ text: 'Ch', value: 'channel' },
{ text: 'Home Id', value: 'homeId' },
- { text: 'Src', value: 'sourceNodeId' },
- { text: 'Dest', value: 'destinationNodeId' },
+ { text: 'Route', value: 'sourceNodeId' },
{ text: 'Type', value: 'type' },
{ text: 'Payload', value: 'payload' },
],
@@ -478,7 +481,7 @@ export default {
.toString()
.padEnd(3, '0')}`
},
- getRepeaters,
+ getRoute,
getType,
getRssi,
getProtocolDataRate,
From bd5f9848484e345ab8f8993c281e2cb8fbeaf2e9 Mon Sep 17 00:00:00 2001
From: Daniel Lando
Date: Wed, 15 May 2024 09:03:12 +0200
Subject: [PATCH 054/120] fix: remove hint from frequency
---
src/views/Zniffer.vue | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/views/Zniffer.vue b/src/views/Zniffer.vue
index bb1a277b96..9006c0a449 100644
--- a/src/views/Zniffer.vue
+++ b/src/views/Zniffer.vue
@@ -62,9 +62,8 @@
Date: Wed, 15 May 2024 09:18:03 +0200
Subject: [PATCH 055/120] fix: clarify expression
---
src/views/Zniffer.vue | 60 ++++++++++++++++++++++++++++++++++++++++---
1 file changed, 57 insertions(+), 3 deletions(-)
diff --git a/src/views/Zniffer.vue b/src/views/Zniffer.vue
index 9006c0a449..d1e24ccf2b 100644
--- a/src/views/Zniffer.vue
+++ b/src/views/Zniffer.vue
@@ -17,7 +17,7 @@
clearable
flat
persistent-hint
- hint="Search expression. Valid values are: homeId, ch, src, dest, protocolDataRate. Ex: src === 1 && dest === 2"
+ hint="Search expression using JS. Click on info button for more info"
:error="searchError"
:error-messages="
searchError ? ['Invalid search'] : []
@@ -27,7 +27,57 @@
class="ma-2"
prepend-inner-icon="search"
label="Search"
- >
+ >
+
+
+
+ info
+
+
+
+
+ Search expression. Valid values
+ are: homeId, ch, src, dest,
+ protocolDataRate, hop, dir
+ (direction).
+
+ Examples:
+
+ -
+
src === 1 && dest ===
+ 2
+
+ -
+
protocolDataRate ===
+ '100kbps'
+
+ -
+
homeId ===
+ '12345678'
+
+ -
+
hop > 1
+
+
+ -
+
dir === 'inbound'
+
+
+
+
+
+
+
Date: Wed, 15 May 2024 09:19:19 +0200
Subject: [PATCH 056/120] fix: reset error on expression
---
src/views/Zniffer.vue | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/views/Zniffer.vue b/src/views/Zniffer.vue
index d1e24ccf2b..75a000e866 100644
--- a/src/views/Zniffer.vue
+++ b/src/views/Zniffer.vue
@@ -386,6 +386,7 @@ export default {
filterFrames(search) {
if (!search || search.trim() === '') {
this.framesFiltered = this.frames
+ this.searchError = false
return
}
From eed858cdc9472309d30804510aef92687b60f760 Mon Sep 17 00:00:00 2001
From: Daniel Lando
Date: Wed, 15 May 2024 09:32:16 +0200
Subject: [PATCH 057/120] fix: highlight hop
---
src/lib/utils.js | 51 +++++++++++++++++++++++++------------------
src/views/Zniffer.vue | 19 +++++++++++-----
2 files changed, 44 insertions(+), 26 deletions(-)
diff --git a/src/lib/utils.js b/src/lib/utils.js
index 0887fbf1e1..b8f14e30f4 100644
--- a/src/lib/utils.js
+++ b/src/lib/utils.js
@@ -225,27 +225,36 @@ export function getRoute(item) {
const repRSSI = item.repeaterRSSI || []
const dir = item.direction === 'inbound' ? '←' : '→'
const hop = item.hop !== undefined ? item.hop : -1
- const repeatersString =
- item.repeaters?.length > 0
- ? item.repeaters
- .map(
- (r, i) =>
- `${
- hop === i
- ? ''
- : ''
- }${r}${
- repRSSI[i] && !isRssiError(repRSSI[i])
- ? ` (${rssiToString(repRSSI[i])})`
- : ''
- }${hop === i ? '' : ''}`,
- )
- .join(` ${dir} `)
- : ''
-
- return `${item.sourceNodeId} ${
- repeatersString ? ` ${dir} ${repeatersString} ${dir}` : dir
- } ${item.destinationNodeId}`
+ const route = [
+ item.sourceNodeId,
+ ...(item.repeaters || []),
+ item.destinationNodeId,
+ ].map(
+ (r, i) =>
+ `${r}${
+ repRSSI[i] && !isRssiError(repRSSI[i - 1])
+ ? ` (${rssiToString(repRSSI[i - 1])})`
+ : ''
+ }`,
+ )
+
+ let routeString = ''
+
+ if (hop >= 0) {
+ // highlight the hop
+ for (let i = 0; i < route.length; i++) {
+ routeString += route[i]
+ if (i < route.length - 1) {
+ routeString += ` ${
+ hop === i ? '' : ''
+ }${dir}${hop === i ? '' : ''} `
+ }
+ }
+ } else {
+ routeString = route.join(` ${dir} `)
+ }
+
+ return routeString
}
export function getType(item) {
return getEnumMemberName(ZWaveFrameType, item.type)
diff --git a/src/views/Zniffer.vue b/src/views/Zniffer.vue
index 75a000e866..05e161dad0 100644
--- a/src/views/Zniffer.vue
+++ b/src/views/Zniffer.vue
@@ -38,10 +38,11 @@
- Search expression. Valid values
- are: homeId, ch, src, dest,
+ Write a custom filter function
+ in JS. Function arguments are:
+ homeId, ch, src, dest,
protocolDataRate, hop, dir
- (direction).
+ (direction), repeaters.
Examples:
@@ -72,6 +73,12 @@
>dir === 'inbound'
+ -
+
repeaters.length >
+ 0
+
@@ -392,7 +399,7 @@ export default {
try {
const fn = new Function(
- 'homeId, ch, src, dest, protocolDataRate, hop, dir',
+ 'homeId, ch, src, dest, protocolDataRate, hop, dir, repeaters',
`return ${search.replace(/\\/g, '\\\\')}`,
)
@@ -405,15 +412,17 @@ export default {
protocolDataRate,
hop,
direction,
+ repeaters,
} = frame
return fn(
- homeId?.toString(16),
+ homeId?.toString(16) || '',
channel,
sourceNodeId,
destinationNodeId,
protocolDataRate,
hop,
direction,
+ repeaters || [],
)
})
From c4b6e80fe7eda9063b867e3b80612990c5fc69f9 Mon Sep 17 00:00:00 2001
From: Daniel Lando
Date: Wed, 15 May 2024 09:33:02 +0200
Subject: [PATCH 058/120] fix: rssi error
---
src/lib/utils.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/lib/utils.js b/src/lib/utils.js
index b8f14e30f4..4eb827eebc 100644
--- a/src/lib/utils.js
+++ b/src/lib/utils.js
@@ -232,7 +232,7 @@ export function getRoute(item) {
].map(
(r, i) =>
`${r}${
- repRSSI[i] && !isRssiError(repRSSI[i - 1])
+ repRSSI[i - 1] && !isRssiError(repRSSI[i - 1])
? ` (${rssiToString(repRSSI[i - 1])})`
: ''
}`,
From f0af637fce3bd30eeb9496faabb323d55eb68f42 Mon Sep 17 00:00:00 2001
From: Daniel Lando
Date: Wed, 15 May 2024 09:34:58 +0200
Subject: [PATCH 059/120] fix: hide rssi from table
---
src/components/custom/FrameDetails.vue | 2 +-
src/lib/utils.js | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/components/custom/FrameDetails.vue b/src/components/custom/FrameDetails.vue
index 596c7c20c9..bcfb2c7e7c 100644
--- a/src/components/custom/FrameDetails.vue
+++ b/src/components/custom/FrameDetails.vue
@@ -48,7 +48,7 @@
Route |
- |
+ |
Ack Requested |
diff --git a/src/lib/utils.js b/src/lib/utils.js
index 4eb827eebc..c89895be3b 100644
--- a/src/lib/utils.js
+++ b/src/lib/utils.js
@@ -221,7 +221,7 @@ export function getRegion(item) {
`Unknown region ${item?.region}`
)
}
-export function getRoute(item) {
+export function getRoute(item, withRssi = false) {
const repRSSI = item.repeaterRSSI || []
const dir = item.direction === 'inbound' ? '←' : '→'
const hop = item.hop !== undefined ? item.hop : -1
@@ -232,7 +232,7 @@ export function getRoute(item) {
].map(
(r, i) =>
`${r}${
- repRSSI[i - 1] && !isRssiError(repRSSI[i - 1])
+ withRssi && repRSSI[i - 1] && !isRssiError(repRSSI[i - 1])
? ` (${rssiToString(repRSSI[i - 1])})`
: ''
}`,
From c9730bc2dc0eab37a6d5984f315e7880c63deb8f Mon Sep 17 00:00:00 2001
From: Daniel Lando
Date: Wed, 15 May 2024 09:41:56 +0200
Subject: [PATCH 060/120] fix: with speed modified
---
src/components/custom/FrameDetails.vue | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/src/components/custom/FrameDetails.vue b/src/components/custom/FrameDetails.vue
index bcfb2c7e7c..9f7e714a3f 100644
--- a/src/components/custom/FrameDetails.vue
+++ b/src/components/custom/FrameDetails.vue
@@ -30,7 +30,14 @@
Protocol Data Rate |
- {{ getProtocolDataRate(value) }} |
+
+ {{
+ getProtocolDataRate(value) +
+ (value.speedModified
+ ? ' (speed modified)'
+ : '')
+ }}
+ |
Sequence Number |
From 3e57de07cc7c74824bec938e8c1a3efc6655572b Mon Sep 17 00:00:00 2001
From: Daniel Lando
Date: Wed, 15 May 2024 10:53:29 +0200
Subject: [PATCH 061/120] fix: improve search filter by passing frame
---
src/components/custom/FrameDetails.vue | 18 +++++++++-----
src/views/Zniffer.vue | 33 +++++++++++---------------
2 files changed, 26 insertions(+), 25 deletions(-)
diff --git a/src/components/custom/FrameDetails.vue b/src/components/custom/FrameDetails.vue
index 9f7e714a3f..adfb65563c 100644
--- a/src/components/custom/FrameDetails.vue
+++ b/src/components/custom/FrameDetails.vue
@@ -12,10 +12,6 @@
Protocol |
{{ getProtocol(value) }} |
-
- Payload |
- {{ value.payload }} |
-
Channel |
{{ value.channel }} |
@@ -73,8 +69,18 @@
-
-
+
+
+
diff --git a/src/views/Zniffer.vue b/src/views/Zniffer.vue
index 05e161dad0..0918825c67 100644
--- a/src/views/Zniffer.vue
+++ b/src/views/Zniffer.vue
@@ -40,12 +40,16 @@
Write a custom filter function
in JS. Function arguments are:
+ frame (the full frame object),
homeId, ch, src, dest,
protocolDataRate, hop, dir
(direction), repeaters.
Examples:
+ -
+
frame.corrupted
+
-
src === 1 && dest ===
@@ -399,30 +403,21 @@ export default {
try {
const fn = new Function(
- 'homeId, ch, src, dest, protocolDataRate, hop, dir, repeaters',
+ 'frame, homeId, ch, src, dest, protocolDataRate, hop, dir, repeaters',
`return ${search.replace(/\\/g, '\\\\')}`,
)
this.framesFiltered = this.frames.filter((frame) => {
- const {
- homeId,
- channel,
- sourceNodeId,
- destinationNodeId,
- protocolDataRate,
- hop,
- direction,
- repeaters,
- } = frame
return fn(
- homeId?.toString(16) || '',
- channel,
- sourceNodeId,
- destinationNodeId,
- protocolDataRate,
- hop,
- direction,
- repeaters || [],
+ frame,
+ frame.homeId?.toString(16) || '',
+ frame.channel,
+ frame.sourceNodeId,
+ frame.destinationNodeId,
+ frame.protocolDataRate,
+ frame.hop,
+ frame.direction,
+ frame.repeaters || [],
)
})
From a159cf6c6b6714acb6f8a6d2ee76d001a61ac725 Mon Sep 17 00:00:00 2001
From: Daniel Lando
Date: Wed, 15 May 2024 11:13:23 +0200
Subject: [PATCH 062/120] fix: parsed payload not shown
---
src/components/custom/FrameDetails.vue | 20 ++++----------------
1 file changed, 4 insertions(+), 16 deletions(-)
diff --git a/src/components/custom/FrameDetails.vue b/src/components/custom/FrameDetails.vue
index adfb65563c..7596d901a1 100644
--- a/src/components/custom/FrameDetails.vue
+++ b/src/components/custom/FrameDetails.vue
@@ -1,7 +1,7 @@
-
+
-
+
@@ -69,7 +69,7 @@
-
+
@@ -87,7 +87,6 @@
-
+
From 0a42cfece6482d300a95a118c254b847ae0c2fca Mon Sep 17 00:00:00 2001
From: Daniel Lando
Date: Fri, 17 May 2024 11:39:25 +0200
Subject: [PATCH 074/120] fix: parsing of encapsulated cc
---
src/components/custom/CCTreeView.vue | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/src/components/custom/CCTreeView.vue b/src/components/custom/CCTreeView.vue
index 6db64e4c9a..6fb07e3411 100644
--- a/src/components/custom/CCTreeView.vue
+++ b/src/components/custom/CCTreeView.vue
@@ -65,15 +65,12 @@ export default {
if (prop === 'encapsulated') {
children.push({
id: `${root}.encapsulated`,
- name: entry.message.encapsulated.tags.join(
- ', ',
- ),
- children: entry.message.encapsulated?.map(
- (e, i) =>
- this.parseEntry(
- e,
- `${root}.encapsulated[${i}]`,
- ),
+ name: entry.encapsulated.tags.join(', '),
+ children: entry.encapsulated?.map((e, i) =>
+ this.parseEntry(
+ e,
+ `${root}.encapsulated[${i}]`,
+ ),
),
})
} else {
From 6d1eeb939ab26918e8098a964269221b7921f5c1 Mon Sep 17 00:00:00 2001
From: Daniel Lando
Date: Fri, 17 May 2024 11:48:54 +0200
Subject: [PATCH 075/120] fix: encapsulated parsing
---
src/components/custom/CCTreeView.vue | 29 ++++++++++++----------------
1 file changed, 12 insertions(+), 17 deletions(-)
diff --git a/src/components/custom/CCTreeView.vue b/src/components/custom/CCTreeView.vue
index 6fb07e3411..614f55d5fb 100644
--- a/src/components/custom/CCTreeView.vue
+++ b/src/components/custom/CCTreeView.vue
@@ -62,24 +62,19 @@ export default {
})
} else if (key === 'message') {
for (const prop in entry.message) {
- if (prop === 'encapsulated') {
- children.push({
- id: `${root}.encapsulated`,
- name: entry.encapsulated.tags.join(', '),
- children: entry.encapsulated?.map((e, i) =>
- this.parseEntry(
- e,
- `${root}.encapsulated[${i}]`,
- ),
- ),
- })
- } else {
- children.push({
- id: `${root}.${prop}`,
- name: `${prop}: ${entry.message[prop]}`,
- })
- }
+ children.push({
+ id: `${root}.${prop}`,
+ name: `${prop}: ${entry.message[prop]}`,
+ })
}
+ } else if (key === 'encapsulated') {
+ children.push({
+ id: `${root}.encapsulated`,
+ name: entry.encapsulated.tags.join(', '),
+ children: entry.encapsulated?.map((e, i) =>
+ this.parseEntry(e, `${root}.encapsulated[${i}]`),
+ ),
+ })
}
}
return items
From 3255db448ca0ef364ae050cddd5486891d1ef381 Mon Sep 17 00:00:00 2001
From: Daniel Lando
Date: Fri, 17 May 2024 11:57:37 +0200
Subject: [PATCH 076/120] fix: parsing of encapsulated cc
---
src/components/custom/CCTreeView.vue | 18 +++++++++++-------
1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/src/components/custom/CCTreeView.vue b/src/components/custom/CCTreeView.vue
index 614f55d5fb..0c738be20a 100644
--- a/src/components/custom/CCTreeView.vue
+++ b/src/components/custom/CCTreeView.vue
@@ -68,13 +68,17 @@ export default {
})
}
} else if (key === 'encapsulated') {
- children.push({
- id: `${root}.encapsulated`,
- name: entry.encapsulated.tags.join(', '),
- children: entry.encapsulated?.map((e, i) =>
- this.parseEntry(e, `${root}.encapsulated[${i}]`),
- ),
- })
+ for (let i = 0; i < entry.encapsulated.length; i++) {
+ const encapsulated = entry.encapsulated[i]
+ children.push({
+ id: `${root}.encapsulated[${i}]`,
+ name: encapsulated.tags.join(', '),
+ children: this.parseEntry(
+ encapsulated,
+ `${root}.encapsulated[${i}]`,
+ ),
+ })
+ }
}
}
return items
From fbe36b73a2869f8c4688fd67804936be1777e731 Mon Sep 17 00:00:00 2001
From: Daniel Lando
Date: Fri, 17 May 2024 14:16:18 +0200
Subject: [PATCH 077/120] fix: switch to custom tree view
---
src/components/custom/CCTreeView.vue | 86 +++++++++++++++++++++++-----
src/views/Zniffer.vue | 12 +++-
2 files changed, 83 insertions(+), 15 deletions(-)
diff --git a/src/components/custom/CCTreeView.vue b/src/components/custom/CCTreeView.vue
index 0c738be20a..1cd62b0fe7 100644
--- a/src/components/custom/CCTreeView.vue
+++ b/src/components/custom/CCTreeView.vue
@@ -1,20 +1,47 @@
-
+
+
+
+
+
+
+
+
{{
+ item.name
+ }}
+
+ {{ item.value }}
+
+
+
+
+
+
+
+
diff --git a/src/views/Zniffer.vue b/src/views/Zniffer.vue
index 1643589a05..fc823df47d 100644
--- a/src/views/Zniffer.vue
+++ b/src/views/Zniffer.vue
@@ -178,7 +178,7 @@
- {{ item.parsedPayload.tags.join(' - ') }}
+ {{ getPayloadTags(item.parsedPayload) }}
{{ item.payload }}
@@ -549,6 +549,16 @@ export default {
return style
},
+ getPayloadTags(payload, prev = []) {
+ const tags = [
+ ...prev,
+ ...(payload.tags || []),
+ ...(payload.encapsulated || []).map((e) =>
+ this.getPayloadTags(e, prev),
+ ),
+ ]
+ return tags.join(' > ')
+ },
bindTopPaneObserver() {
const onTopPaneResize = (e) => {
this.topPaneHeight = e[0].contentRect.height
From eee25a4086678b58c75dcdfb03c9fb375d7a31f8 Mon Sep 17 00:00:00 2001
From: Daniel Lando
Date: Fri, 17 May 2024 14:28:58 +0200
Subject: [PATCH 078/120] fix: switch back to treeview
---
src/components/custom/CCTreeView.vue | 33 ++++++++++++++++++++--------
1 file changed, 24 insertions(+), 9 deletions(-)
diff --git a/src/components/custom/CCTreeView.vue b/src/components/custom/CCTreeView.vue
index 1cd62b0fe7..9c878f4f96 100644
--- a/src/components/custom/CCTreeView.vue
+++ b/src/components/custom/CCTreeView.vue
@@ -1,12 +1,23 @@
-
+
-
+
{{
item.name
}}
@@ -30,7 +40,7 @@
-
+ -->
From b865ebdabcf3538fd8016cb9861434f8c435a672 Mon Sep 17 00:00:00 2001
From: Daniel Lando
Date: Fri, 17 May 2024 14:43:18 +0200
Subject: [PATCH 079/120] fix: tree view styling
---
src/components/custom/CCTreeView.vue | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/components/custom/CCTreeView.vue b/src/components/custom/CCTreeView.vue
index 9c878f4f96..b906c0a021 100644
--- a/src/components/custom/CCTreeView.vue
+++ b/src/components/custom/CCTreeView.vue
@@ -152,7 +152,11 @@ export default {
} */
.tree-item-name {
- width: 160px;
+}
+
+.tree-item-value {
+ color: #666;
+ padding-left: 5px;
}
.v-treeview::v-deep .v-treeview-node__root {
From 140d1d6ec05edd7a81836716a2d1292f510af9f0 Mon Sep 17 00:00:00 2001
From: Daniel Lando
Date: Fri, 17 May 2024 15:12:23 +0200
Subject: [PATCH 080/120] fix: expand all
---
src/components/custom/CCTreeView.vue | 15 +++++++++++++--
src/views/Zniffer.vue | 10 +++-------
2 files changed, 16 insertions(+), 9 deletions(-)
diff --git a/src/components/custom/CCTreeView.vue b/src/components/custom/CCTreeView.vue
index b906c0a021..6e3cb04a35 100644
--- a/src/components/custom/CCTreeView.vue
+++ b/src/components/custom/CCTreeView.vue
@@ -1,5 +1,11 @@
-
+
{{
@@ -88,7 +94,9 @@ export default {
default: 0,
},
},
- data: () => ({}),
+ data: () => ({
+ openIds: [],
+ }),
computed: {
items() {
return Array.isArray(this.value)
@@ -100,6 +108,7 @@ export default {
parseEntry(entry, root = 'root') {
const items = []
const children = []
+ this.openIds = []
for (const key in entry) {
if (key === 'tags') {
items.push({
@@ -127,6 +136,8 @@ export default {
}
}
}
+
+ this.openIds.push(...items.map((item) => item.id))
return items
},
},
diff --git a/src/views/Zniffer.vue b/src/views/Zniffer.vue
index fc823df47d..07b356a6a0 100644
--- a/src/views/Zniffer.vue
+++ b/src/views/Zniffer.vue
@@ -354,6 +354,7 @@ export default {
},
frames() {
this.filterFrames(this.search)
+ this.scrollBottom()
},
},
mounted() {
@@ -362,8 +363,6 @@ export default {
const lastFrame = this.frames[this.frames.length - 1]
data.delta = lastFrame ? data.timestamp - lastFrame.timestamp : 0
this.frames.push(data)
-
- this.scrollBottom()
})
this.onWindowResize = () => {
@@ -374,7 +373,6 @@ export default {
window.addEventListener('resize', this.onWindowResize)
this.onWindowResize()
- this.scrollBottom()
this.clearFrequency()
},
beforeDestroy() {
@@ -552,7 +550,7 @@ export default {
getPayloadTags(payload, prev = []) {
const tags = [
...prev,
- ...(payload.tags || []),
+ payload.tags?.join(' '),
...(payload.encapsulated || []).map((e) =>
this.getPayloadTags(e, prev),
),
@@ -611,9 +609,7 @@ export default {
this.perPage <= this.totalFrames
? this.totalFrames - this.perPage
: rows
- await this.$nextTick()
- e.target.scrollTop = scrollTop
- }, 10)
+ }, 100)
},
getTimestamp(timestamp) {
// format timestamp HH:mm:ss.fff
From 0fbb59ad02beaf41d113c8a42229f624c724680a Mon Sep 17 00:00:00 2001
From: Daniel Lando
Date: Fri, 17 May 2024 15:13:55 +0200
Subject: [PATCH 081/120] fix: expand all
---
src/components/custom/CCTreeView.vue | 13 ++-----------
1 file changed, 2 insertions(+), 11 deletions(-)
diff --git a/src/components/custom/CCTreeView.vue b/src/components/custom/CCTreeView.vue
index 6e3cb04a35..8803d9b506 100644
--- a/src/components/custom/CCTreeView.vue
+++ b/src/components/custom/CCTreeView.vue
@@ -1,11 +1,5 @@
-
+
{{
@@ -94,9 +88,7 @@ export default {
default: 0,
},
},
- data: () => ({
- openIds: [],
- }),
+ data: () => ({}),
computed: {
items() {
return Array.isArray(this.value)
@@ -137,7 +129,6 @@ export default {
}
}
- this.openIds.push(...items.map((item) => item.id))
return items
},
},
From e71aa6f1bec546bad3e36a2ba30c66685c810de1 Mon Sep 17 00:00:00 2001
From: Daniel Lando
Date: Fri, 17 May 2024 15:29:05 +0200
Subject: [PATCH 082/120] fix: improve frames rendiring
---
src/views/Zniffer.vue | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/src/views/Zniffer.vue b/src/views/Zniffer.vue
index 07b356a6a0..c71a8aed3e 100644
--- a/src/views/Zniffer.vue
+++ b/src/views/Zniffer.vue
@@ -343,6 +343,20 @@ export default {
}, 3000)
}
},
+ framesQueue() {
+ // used to improve performances when lot of frames comes all together
+ if (this.queueTimeout) {
+ clearTimeout(this.queueTimeout)
+ }
+
+ if (this.framesQueue.length > 30) {
+ this.emptyQueue()
+ } else {
+ this.queueTimeout = setTimeout(() => {
+ this.emptyQueue()
+ }, 100)
+ }
+ },
search(v) {
if (this.searchTimeout) {
clearTimeout(this.searchTimeout)
@@ -362,7 +376,7 @@ export default {
data.id = uuid()
const lastFrame = this.frames[this.frames.length - 1]
data.delta = lastFrame ? data.timestamp - lastFrame.timestamp : 0
- this.frames.push(data)
+ this.framesQueue.push(data)
})
this.onWindowResize = () => {
@@ -415,6 +429,7 @@ export default {
topPaneHeight: 500,
frames: [],
framesFiltered: [],
+ framesQueue: [],
headers: [
{
text: 'Timestamp',
@@ -450,6 +465,10 @@ export default {
},
methods: {
...mapActions(useBaseStore, ['showSnackbar']),
+ emptyQueue() {
+ this.frames.push(...this.framesQueue)
+ this.framesQueue = []
+ },
async clearFrequency() {
// needed to handle the clear event on select
await this.$nextTick()
From 25fa1a0b2ca6c6ef6a90cc2e7cf9b74f96320e4a Mon Sep 17 00:00:00 2001
From: Daniel Lando
Date: Fri, 17 May 2024 15:36:35 +0200
Subject: [PATCH 083/120] fix: remove queue check
---
src/views/Zniffer.vue | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/src/views/Zniffer.vue b/src/views/Zniffer.vue
index c71a8aed3e..9344f02772 100644
--- a/src/views/Zniffer.vue
+++ b/src/views/Zniffer.vue
@@ -349,13 +349,9 @@ export default {
clearTimeout(this.queueTimeout)
}
- if (this.framesQueue.length > 30) {
+ this.queueTimeout = setTimeout(() => {
this.emptyQueue()
- } else {
- this.queueTimeout = setTimeout(() => {
- this.emptyQueue()
- }, 100)
- }
+ }, 50)
},
search(v) {
if (this.searchTimeout) {
From 28a6a9b88bab0790fcbae23b5ed4c8ae403a691a Mon Sep 17 00:00:00 2001
From: Dominic Griesel
Date: Tue, 21 May 2024 12:05:01 +0200
Subject: [PATCH 084/120] chore: update zwave-js
---
package-lock.json | 88 +++++++++++++++++++++++------------------------
package.json | 2 +-
2 files changed, 45 insertions(+), 45 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 6cb985a0ae..7437ba3a8c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -58,7 +58,7 @@
"vuedraggable": "^2.24.3",
"vuetify": "^2.7.1",
"winston": "^3.11.0",
- "zwave-js": "^12.8.1"
+ "zwave-js": "^12.9.0"
},
"bin": {
"zwave-js-ui": "server/bin/www.js"
@@ -4171,13 +4171,13 @@
}
},
"node_modules/@zwave-js/cc": {
- "version": "12.8.1",
- "resolved": "https://registry.npmjs.org/@zwave-js/cc/-/cc-12.8.1.tgz",
- "integrity": "sha512-lKfJohiiNXW0vPemC7i5GZzO2qqWLj+zGnDloGHCILjt2AhWXUBDQMTqFQNEgJIz0wd9n/SoqxxVLBJd8kWwNA==",
+ "version": "12.9.0",
+ "resolved": "https://registry.npmjs.org/@zwave-js/cc/-/cc-12.9.0.tgz",
+ "integrity": "sha512-XTdWisSIN/GnfHGX0/0XY9JaoXJeuTkZnB5YFrHRQ+Nlw6bj1pfDLU6ZixNZKiwJtNsVHkD5Kl5auGk+f8GA5g==",
"dependencies": {
- "@zwave-js/core": "12.8.0",
- "@zwave-js/host": "12.8.0",
- "@zwave-js/serial": "12.8.0",
+ "@zwave-js/core": "12.9.0",
+ "@zwave-js/host": "12.9.0",
+ "@zwave-js/serial": "12.9.0",
"@zwave-js/shared": "12.5.3",
"alcalzone-shared": "^4.0.8",
"ansi-colors": "^4.1.3",
@@ -4191,11 +4191,11 @@
}
},
"node_modules/@zwave-js/config": {
- "version": "12.8.0",
- "resolved": "https://registry.npmjs.org/@zwave-js/config/-/config-12.8.0.tgz",
- "integrity": "sha512-jVxpkwOZ5KCftGbCYb7cAl3W+TQATlVXQ/8U4RqUOTM7lyZKMdDwBBoeQex7biMYGq5qotDiLIndFvvYSKzujg==",
+ "version": "12.9.0",
+ "resolved": "https://registry.npmjs.org/@zwave-js/config/-/config-12.9.0.tgz",
+ "integrity": "sha512-T7z1vDuSwg89G2ECfw9tYpYzAHZIUUu0l/zi/dfUU0SrPNxsdbdX3+TzzWP5Ca501OfOIMJkmlIzCaryHoR67Q==",
"dependencies": {
- "@zwave-js/core": "12.8.0",
+ "@zwave-js/core": "12.9.0",
"@zwave-js/shared": "12.5.3",
"alcalzone-shared": "^4.0.8",
"ansi-colors": "^4.1.3",
@@ -4224,9 +4224,9 @@
}
},
"node_modules/@zwave-js/core": {
- "version": "12.8.0",
- "resolved": "https://registry.npmjs.org/@zwave-js/core/-/core-12.8.0.tgz",
- "integrity": "sha512-cQqnzdnM2AgwWK5IpP6wdhMWk5pt0B3ILn3y+gjhM/8iLeMb+nuGA7eEz/rEC+gxYeHrWbyK1/A22swfvDgxiw==",
+ "version": "12.9.0",
+ "resolved": "https://registry.npmjs.org/@zwave-js/core/-/core-12.9.0.tgz",
+ "integrity": "sha512-ED3Ee2UZo+DqoRQAwuUf7IUprqYG/l4dADOk1wsop0HhgVxJ7/tZIGgg1b9LO597q9GpmDUX7IwEfWPFfsQIjQ==",
"dependencies": {
"@alcalzone/jsonl-db": "^3.1.1",
"@zwave-js/shared": "12.5.3",
@@ -4257,12 +4257,12 @@
}
},
"node_modules/@zwave-js/host": {
- "version": "12.8.0",
- "resolved": "https://registry.npmjs.org/@zwave-js/host/-/host-12.8.0.tgz",
- "integrity": "sha512-YnsttcEznk/jD6rOJH9e8U8IMSgXzMA2gDPS1EICMs96a03pG0mh0fnXuP51JH+Iw29p11oKDpQCGaA0BMqMsw==",
+ "version": "12.9.0",
+ "resolved": "https://registry.npmjs.org/@zwave-js/host/-/host-12.9.0.tgz",
+ "integrity": "sha512-cfrkH9ZlnS6qUcbb9OzeBAU5gGkODDrFEPqHbe88IlDIC1z1uCboSQn2pVxgvLC3/RsfDysXU4mJdBT7gfwIIw==",
"dependencies": {
- "@zwave-js/config": "12.8.0",
- "@zwave-js/core": "12.8.0",
+ "@zwave-js/config": "12.9.0",
+ "@zwave-js/core": "12.9.0",
"@zwave-js/shared": "12.5.3",
"alcalzone-shared": "^4.0.8"
},
@@ -4274,11 +4274,11 @@
}
},
"node_modules/@zwave-js/nvmedit": {
- "version": "12.8.0",
- "resolved": "https://registry.npmjs.org/@zwave-js/nvmedit/-/nvmedit-12.8.0.tgz",
- "integrity": "sha512-mVHLGxRfYbVwHV+kRiwJqOEac6pTje9riEbJoCD54aNDpozDPrnO/VXv05Hxy3KANXpYO6Nww2GU0H2fuprdtg==",
+ "version": "12.9.0",
+ "resolved": "https://registry.npmjs.org/@zwave-js/nvmedit/-/nvmedit-12.9.0.tgz",
+ "integrity": "sha512-Q/wj8YblVxAQWxUvZJcPoM+0BNRuW/PAVhGd3RGhK55qu8toQHCvZ0I3ksWMopaChWJ40wTFjhaZzpQRmu//bA==",
"dependencies": {
- "@zwave-js/core": "12.8.0",
+ "@zwave-js/core": "12.9.0",
"@zwave-js/shared": "12.5.3",
"alcalzone-shared": "^4.0.8",
"fs-extra": "^11.2.0",
@@ -4384,13 +4384,13 @@
}
},
"node_modules/@zwave-js/serial": {
- "version": "12.8.0",
- "resolved": "https://registry.npmjs.org/@zwave-js/serial/-/serial-12.8.0.tgz",
- "integrity": "sha512-shmznMKzQIUEtHHJJQSzsOGobfp71JxMH0ZYHMJS8XkYVcrM45wGHfXfboHTQTdEm81JoWqZVT2Tt2dntgaj/w==",
+ "version": "12.9.0",
+ "resolved": "https://registry.npmjs.org/@zwave-js/serial/-/serial-12.9.0.tgz",
+ "integrity": "sha512-wvdpjRPA4ICnc2I7DoULpYHjp3NExNTJZzOKwe3fN0/urT2Z0s8Yls47SBvKyZwLkwYY25zgvLlVmZwdewKcfw==",
"dependencies": {
"@serialport/stream": "^12.0.0",
- "@zwave-js/core": "12.8.0",
- "@zwave-js/host": "12.8.0",
+ "@zwave-js/core": "12.9.0",
+ "@zwave-js/host": "12.9.0",
"@zwave-js/shared": "12.5.3",
"alcalzone-shared": "^4.0.8",
"serialport": "^12.0.0",
@@ -4436,13 +4436,13 @@
}
},
"node_modules/@zwave-js/testing": {
- "version": "12.8.0",
- "resolved": "https://registry.npmjs.org/@zwave-js/testing/-/testing-12.8.0.tgz",
- "integrity": "sha512-Ok96uoYgnuurK2Mfu+67B+g70TEjq0RJGryvyWvvvQw09bS4Gpnh+7013rij9haW9R583rL/EkkwAQ96fINgkQ==",
+ "version": "12.9.0",
+ "resolved": "https://registry.npmjs.org/@zwave-js/testing/-/testing-12.9.0.tgz",
+ "integrity": "sha512-4HRXg1zJ1wUEPkJai1WmezhPjdwmXdab8ToZPVCps1noDbuwa5hdzC1oq1rWxQQpfsR2+P6haMN/liwchY+/8A==",
"dependencies": {
- "@zwave-js/core": "12.8.0",
- "@zwave-js/host": "12.8.0",
- "@zwave-js/serial": "12.8.0",
+ "@zwave-js/core": "12.9.0",
+ "@zwave-js/host": "12.9.0",
+ "@zwave-js/serial": "12.9.0",
"@zwave-js/shared": "12.5.3",
"alcalzone-shared": "^4.0.8",
"ansi-colors": "^4.1.3"
@@ -19382,20 +19382,20 @@
}
},
"node_modules/zwave-js": {
- "version": "12.8.1",
- "resolved": "https://registry.npmjs.org/zwave-js/-/zwave-js-12.8.1.tgz",
- "integrity": "sha512-OJ0xtYTlDDUm0U7WxBEqDRPHhuiswsVugGhO7fDw8goqzMf/i57ftCVveud68nM1roUf86deLw0ETM0yiK/XNg==",
+ "version": "12.9.0",
+ "resolved": "https://registry.npmjs.org/zwave-js/-/zwave-js-12.9.0.tgz",
+ "integrity": "sha512-o4tB0OuvYge99JZmKtDC31jA13q12UwJtBOPXDkNtN5vIZ0xs8i1/sofKmvCoN31SrDPhJcJlDorkIorUi/Okg==",
"dependencies": {
"@alcalzone/jsonl-db": "^3.1.1",
"@alcalzone/pak": "^0.10.1",
- "@zwave-js/cc": "12.8.1",
- "@zwave-js/config": "12.8.0",
- "@zwave-js/core": "12.8.0",
- "@zwave-js/host": "12.8.0",
- "@zwave-js/nvmedit": "12.8.0",
- "@zwave-js/serial": "12.8.0",
+ "@zwave-js/cc": "12.9.0",
+ "@zwave-js/config": "12.9.0",
+ "@zwave-js/core": "12.9.0",
+ "@zwave-js/host": "12.9.0",
+ "@zwave-js/nvmedit": "12.9.0",
+ "@zwave-js/serial": "12.9.0",
"@zwave-js/shared": "12.5.3",
- "@zwave-js/testing": "12.8.0",
+ "@zwave-js/testing": "12.9.0",
"alcalzone-shared": "^4.0.8",
"ansi-colors": "^4.1.3",
"execa": "^5.1.1",
diff --git a/package.json b/package.json
index b7fdbc085d..90cdf82889 100644
--- a/package.json
+++ b/package.json
@@ -109,7 +109,7 @@
"vuedraggable": "^2.24.3",
"vuetify": "^2.7.1",
"winston": "^3.11.0",
- "zwave-js": "^12.8.1"
+ "zwave-js": "^12.9.0"
},
"devDependencies": {
"@actions/github": "^6.0.0",
From 7e36bca11782e29b4e76ace3b07d9006095dfaf2 Mon Sep 17 00:00:00 2001
From: Dominic Griesel
Date: Tue, 21 May 2024 10:43:39 +0200
Subject: [PATCH 085/120] fix: correct type for LR frames
---
src/lib/utils.js | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/lib/utils.js b/src/lib/utils.js
index c89895be3b..c5ff121224 100644
--- a/src/lib/utils.js
+++ b/src/lib/utils.js
@@ -10,6 +10,7 @@ import {
rssiToString,
getEnumMemberName,
ZWaveFrameType,
+ LongRangeFrameType,
} from 'zwave-js/safe'
import { znifferRegions } from './items'
@@ -257,7 +258,11 @@ export function getRoute(item, withRssi = false) {
return routeString
}
export function getType(item) {
- return getEnumMemberName(ZWaveFrameType, item.type)
+ if (item.protocol === Protocols.ZWaveLongRange) {
+ return getEnumMemberName(LongRangeFrameType, item.type)
+ } else {
+ return getEnumMemberName(ZWaveFrameType, item.type)
+ }
}
export function getRssi(item) {
if (item.rssi && !isRssiError(item.rssi)) {
From 932fb1a496ae48c97f4d18090f120bb3f4d6755d Mon Sep 17 00:00:00 2001
From: Dominic Griesel
Date: Tue, 21 May 2024 10:44:04 +0200
Subject: [PATCH 086/120] fix: consistent colors for Z-Wave and LR frames
---
src/views/Zniffer.vue | 76 ++++++++++++++++++++++++++++---------------
1 file changed, 50 insertions(+), 26 deletions(-)
diff --git a/src/views/Zniffer.vue b/src/views/Zniffer.vue
index 9344f02772..6dc1978563 100644
--- a/src/views/Zniffer.vue
+++ b/src/views/Zniffer.vue
@@ -284,7 +284,8 @@