Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: zwave-js/zwave-js-ui
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v9.33.1
Choose a base ref
...
head repository: zwave-js/zwave-js-ui
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v10.0.0
Choose a head ref
  • 2 commits
  • 7 files changed
  • 3 contributors

Commits on Mar 19, 2025

  1. feat!: bump zwave-js@15 and fix breaking changes (#4136)

    Co-authored-by: Dominic Griesel <dominic.griesel@nabucasa.com>
    robertsLando and AlCalzone authored Mar 19, 2025

    Verified

    This commit was signed with the committer’s verified signature.
    renovate-bot Mend Renovate
    Copy the full SHA
    c8c57e5 View commit details
  2. Release 10.0.0

    zwave-js-bot committed Mar 19, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    3f4db9b View commit details
Showing with 1,315 additions and 2,198 deletions.
  1. +2 −0 CHANGELOG.md
  2. +1 −1 api/lib/ZnifferManager.ts
  3. +45 −54 api/lib/ZwaveClient.ts
  4. +27 −1 api/lib/utils.ts
  5. +1,235 −2,122 package-lock.json
  6. +4 −6 package.json
  7. +1 −14 src/components/nodes-table/ExpandedNode.vue
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@


# [10.0.0](https://github.com/zwave-js/zwave-js-ui/compare/v9.33.1...v10.0.0) (2025-03-19)

## [9.33.1](https://github.com/zwave-js/zwave-js-ui/compare/v9.33.0...v9.33.1) (2025-03-18)


2 changes: 1 addition & 1 deletion api/lib/ZnifferManager.ts
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@ import { socketEvents } from './SocketEvents'
import { ZwaveConfig } from './ZwaveClient'
import { logsDir, storeDir } from '../config/app'
import { buffer2hex, joinPath, parseSecurityKeys } from './utils'
import { isDocker } from '@zwave-js/shared'
import { isDocker } from './utils'
import { basename } from 'path'

// eslint-disable-next-line @typescript-eslint/no-var-requires
99 changes: 45 additions & 54 deletions api/lib/ZwaveClient.ts
Original file line number Diff line number Diff line change
@@ -16,19 +16,19 @@ import {
ZWaveDataRate,
ZWaveErrorCodes,
Protocols,
createDefaultTransportFormat,
FirmwareFileFormat,
tryUnzipFirmwareFile,
extractFirmwareAsync,
extractFirmware,
} from '@zwave-js/core'
import { createDefaultTransportFormat } from '@zwave-js/core/bindings/log/node'
import { JSONTransport } from '@zwave-js/log-transport-json'
import { isDocker } from '@zwave-js/shared'
import { isDocker } from './utils'
import {
AssociationAddress,
AssociationGroup,
ControllerFirmwareUpdateProgress,
ControllerFirmwareUpdateResult,
ControllerFirmwareUpdateStatus,
OTWFirmwareUpdateProgress,
OTWFirmwareUpdateResult,
OTWFirmwareUpdateStatus,
ControllerStatistics,
ControllerStatus,
DataRate,
@@ -108,6 +108,7 @@ import {
ProvisioningEntryStatus,
AssociationCheckResult,
LinkReliabilityCheckResult,
DriverMode,
} from 'zwave-js'
import { getEnumMemberName, parseQRCodeString } from 'zwave-js/Utils'
import { configDbDir, logsDir, nvmBackupsDir, storeDir } from '../config/app'
@@ -466,7 +467,7 @@ export interface BackgroundRSSIPoint {

export interface FwFile {
name: string
data: Buffer | Uint8Array
data: Uint8Array
target?: number
}

@@ -2140,7 +2141,7 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {

// extend options with hidden `options`
const zwaveOptions: PartialZWaveOptions = {
allowBootloaderOnly: this.cfg.allowBootloaderOnly || false,
bootloaderMode: this.cfg.allowBootloaderOnly ? 'allow' : 'recover',
storage: {
cacheDir: storeDir,
deviceConfigPriorityDir:
@@ -2282,6 +2283,14 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
'bootloader ready',
this._onBootLoaderReady.bind(this),
)
this._driver.on(
'firmware update progress',
this._onOTWFirmwareUpdateProgress.bind(this),
)
this._driver.on(
'firmware update finished',
this._onOTWFirmwareUpdateFinished.bind(this),
)

logger.info(`Connecting to ${this.cfg.port}`)

@@ -2988,7 +2997,7 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
if (strategy === InclusionStrategy.Security_S2) {
let inclusionOptions: ReplaceNodeOptions
if (options?.qrString) {
const parsedQr = parseQRCodeString(options.qrString)
const parsedQr = await parseQRCodeString(options.qrString)

if (parsedQr) {
// when replacing a failed node you cannot use smart start so always use qrcode for provisioning
@@ -3226,7 +3235,9 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
break
case InclusionStrategy.Security_S2:
if (options?.qrString) {
const parsedQr = parseQRCodeString(options.qrString)
const parsedQr = await parseQRCodeString(
options.qrString,
)
if (!parsedQr) {
throw Error(`Invalid QR code string`)
}
@@ -3236,7 +3247,7 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
} else if (
parsedQr.version === QRCodeVersion.SmartStart
) {
this.provisionSmartStartNode(parsedQr)
await this.provisionSmartStartNode(parsedQr)
return true
} else {
throw Error(`Invalid QR code version`)
@@ -3902,9 +3913,7 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
/**
* Used to trigger an update of controller FW
*/
async firmwareUpdateOTW(
file: FwFile,
): Promise<ControllerFirmwareUpdateResult> {
async firmwareUpdateOTW(file: FwFile): Promise<OTWFirmwareUpdateResult> {
try {
if (backupManager.backupOnEvent) {
this.nvmEvent = 'before_controller_fw_update_otw'
@@ -3914,15 +3923,13 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {

try {
const format = guessFirmwareFileFormat(file.name, file.data)
firmware = await extractFirmwareAsync(file.data, format)
firmware = await extractFirmware(file.data, format)
} catch (err) {
throw Error(
`Unable to extract firmware from file '${file.name}'`,
)
}
const result = await this.driver.controller.firmwareUpdateOTW(
firmware.data,
)
const result = await this.driver.firmwareUpdateOTW(firmware.data)
return result
} catch (e) {
throw Error(`Error while updating firmware: ${e.message}`)
@@ -3959,7 +3966,7 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {

for (const f of files) {
let { data, name } = f
if (data instanceof Buffer) {
if (isUint8Array(data)) {
try {
let format: FirmwareFileFormat
if (name.endsWith('.zip')) {
@@ -3977,10 +3984,7 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
format = guessFirmwareFileFormat(name, data)
}

const firmware = await extractFirmwareAsync(
data,
format,
)
const firmware = await extractFirmware(data, format)
if (f.target !== undefined) {
firmware.firmwareTarget = f.target
}
@@ -4163,7 +4167,7 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {

logger.log('info', 'Calling api %s with args: %o', apiName, args)

if (this.driverReady || this.driver?.isInBootloader()) {
if (this.driverReady || this.driver?.mode === DriverMode.Bootloader) {
try {
const allowed =
typeof this[apiName] === 'function' &&
@@ -4438,14 +4442,6 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
'statistics updated',
this._onControllerStatisticsUpdated.bind(this),
)
.on(
'firmware update progress',
this._onControllerFirmwareUpdateProgress.bind(this),
)
.on(
'firmware update finished',
this._onControllerFirmwareUpdateFinished.bind(this),
)
.on(
'status changed',
this._onControllerStatusChanged.bind(this),
@@ -4523,9 +4519,7 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
}
}

private _onControllerFirmwareUpdateProgress(
progress: ControllerFirmwareUpdateProgress,
) {
private _onOTWFirmwareUpdateProgress(progress: OTWFirmwareUpdateProgress) {
const nodeId = this.driver.controller.ownNodeId
const node = this.nodes.get(nodeId)
if (node) {
@@ -4539,7 +4533,7 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {

// send at most 4msg per second
this.throttle(
this._onControllerFirmwareUpdateProgress.name,
this._onOTWFirmwareUpdateProgress.name,
this.emitNodeUpdate.bind(this, node, {
firmwareUpdate: node.firmwareUpdate,
} as utils.DeepPartial<ZUINode>),
@@ -4556,9 +4550,7 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
)
}

private _onControllerFirmwareUpdateFinished(
result: ControllerFirmwareUpdateResult,
) {
private _onOTWFirmwareUpdateFinished(result: OTWFirmwareUpdateResult) {
const nodeId = this.driver.controller.ownNodeId
const node = this.nodes.get(nodeId)
const zwaveNode = this.driver.controller.nodes.get(nodeId)
@@ -4571,7 +4563,7 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
firmwareUpdateResult: {
success: result.success,
status: getEnumMemberName(
ControllerFirmwareUpdateStatus,
OTWFirmwareUpdateStatus,
result.status,
),
},
@@ -4582,7 +4574,7 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
`Controller ${zwaveNode.id} firmware update OTW finished ${
result.success ? 'successfully' : 'with error'
}.\n Status: ${getEnumMemberName(
ControllerFirmwareUpdateStatus,
OTWFirmwareUpdateStatus,
result.status,
)}. Result: ${JSON.stringify(result)}.`,
)
@@ -5027,7 +5019,7 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
this._updateControllerStatus(`Backup NVM progress: ${progress}%`)
}

async restoreNVM(data: Buffer, useRaw = false) {
async restoreNVM(data: Uint8Array, useRaw = false) {
if (!this.driverReady) {
throw new DriverNotReadyError()
}
@@ -5113,12 +5105,12 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
this.driver.controller.unprovisionSmartStartNode(dskOrNodeId)
}

parseQRCodeString(qrString: string): {
async parseQRCodeString(qrString: string): Promise<{
parsed?: QRProvisioningInformation
nodeId?: number
exists: boolean
} {
const parsed = parseQRCodeString(qrString)
}> {
const parsed = await parseQRCodeString(qrString)
let node: ZWaveNode | undefined
let exists = false

@@ -5137,14 +5129,14 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
}
}

provisionSmartStartNode(entry: PlannedProvisioningEntry | string) {
async provisionSmartStartNode(entry: PlannedProvisioningEntry | string) {
if (!this.driverReady) {
throw new DriverNotReadyError()
}

if (typeof entry === 'string') {
// it's a qrcode
entry = parseQRCodeString(entry)
entry = await parseQRCodeString(entry)
}

if (!entry.dsk) {
@@ -5739,10 +5731,9 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
} else if (ccId === CommandClasses['Entry Control']) {
valueId.property = args.eventType.toString()
valueId.propertyKey = args.dataType
data =
args.eventData instanceof Buffer
? utils.buffer2hex(args.eventData)
: args.eventData
data = isUint8Array(args.eventData)
? utils.buffer2hex(args.eventData)
: args.eventData
} else if (ccId === CommandClasses['Multilevel Switch']) {
valueId.property = getEnumMemberName(
MultilevelSwitchCommand,
@@ -6793,8 +6784,8 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
let api: 'firmwareUpdateOTW' | 'firmwareUpdateOTA'
if (this.nodes.get(nodeId).isControllerNode) {
api = 'firmwareUpdateOTW'
this._onControllerFirmwareUpdateFinished({
status: ControllerFirmwareUpdateStatus.OK,
this._onOTWFirmwareUpdateFinished({
status: OTWFirmwareUpdateStatus.OK,
success: true,
})
} else {
@@ -6838,7 +6829,7 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
.catch(() => {
//noop
})
this._onControllerFirmwareUpdateProgress({
this._onOTWFirmwareUpdateProgress({
sentFragments: progress.sentFragments,
totalFragments: progress.totalFragments,
progress: progress.progress,
28 changes: 27 additions & 1 deletion api/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
import { PartialZWaveOptions, ValueID, ZnifferOptions } from 'zwave-js'
import path, { resolve } from 'path'
import crypto from 'crypto'
import { readFileSync } from 'fs'
import { readFileSync, statSync } from 'fs'
import type { ZwaveConfig } from './ZwaveClient'

// don't use import here, it will break the build
@@ -383,3 +383,29 @@ export function parseSecurityKeys(
}
}
}

function hasDockerEnv() {
try {
statSync('/.dockerenv')
return true
} catch {
return false
}
}

function hasDockerCGroup() {
try {
return readFileSync('/proc/self/cgroup', 'utf8').includes('docker')
} catch {
return false
}
}

let isDockerCached: boolean

export function isDocker(): boolean {
// TODO: Use `??=` when targeting Node.js 16.
isDockerCached ??= hasDockerEnv() || hasDockerCGroup()

return isDockerCached
}
Loading