Skip to content

Commit

Permalink
feat: long range support zwave-js@12.5.0 (#3545)
Browse files Browse the repository at this point in the history
  • Loading branch information
robertsLando authored Apr 3, 2024
1 parent 604b759 commit bbf5ee6
Show file tree
Hide file tree
Showing 15 changed files with 641 additions and 970 deletions.
62 changes: 61 additions & 1 deletion api/lib/ZwaveClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
ValueMetadataString,
ZWaveDataRate,
ZWaveErrorCodes,
Protocols,
} from '@zwave-js/core'
import { isDocker } from '@zwave-js/shared'
import {
Expand Down Expand Up @@ -100,6 +101,7 @@ import {
PartialZWaveOptions,
InclusionUserCallbacks,
InclusionState,
ProvisioningEntryStatus,
} from 'zwave-js'
import { getEnumMemberName, parseQRCodeString } from 'zwave-js/Utils'
import { logsDir, nvmBackupsDir, storeDir } from '../config/app'
Expand Down Expand Up @@ -555,6 +557,8 @@ export type ZUINode = {
}
defaultTransitionDuration?: string
defaultVolume?: number
protocol?: Protocols
supportsLongRange?: boolean
}

export type NodeEvent = {
Expand All @@ -573,6 +577,10 @@ export type ZwaveConfig = {
S2_AccessControl: string
S0_Legacy: string
}>
securityKeysLongRange?: utils.DeepPartial<{
S2_Authenticated: string
S2_AccessControl: string
}>
serverEnabled?: boolean
enableSoftReset?: boolean
deviceConfigPriorityDir?: string
Expand Down Expand Up @@ -2028,6 +2036,12 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
throw new DriverNotReadyError()
}

const zwaveNode = this.getNode(nodeId)

if (zwaveNode.protocol === Protocols.ZWaveLongRange) {
return []
}

const neighbors =
await this._driver.controller.getNodeNeighbors(nodeId)
this.logNode(nodeId, 'debug', `Neighbors: ${neighbors.join(', ')}`)
Expand Down Expand Up @@ -2249,6 +2263,7 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
}

zwaveOptions.securityKeys = {}
zwaveOptions.securityKeysLongRange = {}

// convert security keys to buffer
for (const key in this.cfg.securityKeys) {
Expand All @@ -2263,6 +2278,22 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
}
}

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',
)
}
}

try {
// init driver here because if connect fails the driver is destroyed
// this could throw so include in the try/catch
Expand Down Expand Up @@ -4973,6 +5004,16 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
throw Error('DSK is required')
}

const isNew = !this.driver.controller.getProvisioningEntry(entry.dsk)

// disable it so user can choose the protocol to use
if (
isNew &&
entry.supportedProtocols?.includes(Protocols.ZWaveLongRange)
) {
entry.status = ProvisioningEntryStatus.Inactive
}

this.driver.controller.provisionSmartStartNode(entry)

return entry
Expand Down Expand Up @@ -5133,6 +5174,7 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
node.ready = true

if (node.isControllerNode) {
node.supportsLongRange = this.driver.controller.supportsLongRange
this.updateControllerNodeProps(node).catch((error) => {
this.logNode(
zwaveNode,
Expand Down Expand Up @@ -5182,7 +5224,11 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
)
}

if (!zwaveNode.isControllerNode) {
// Long range nodes use a star topology, so they don't have return/priority routes
if (
!zwaveNode.isControllerNode &&
zwaveNode.protocol !== Protocols.ZWaveLongRange
) {
this.getPriorityRoute(zwaveNode.id).catch((error) => {
this.logNode(
zwaveNode,
Expand Down Expand Up @@ -5947,6 +5993,7 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
node.firmwareCapabilities =
zwaveNode.getFirmwareUpdateCapabilitiesCached()

node.protocol = zwaveNode.protocol
const storedNode = this.storeNodes[nodeId]

if (storedNode) {
Expand Down Expand Up @@ -6012,12 +6059,22 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
} else {
logger.info('RF region is not supported by controller')
}

// when RF region changes, check if long range is supported
if (
this.driver.controller.supportsLongRange !==
node.supportsLongRange
) {
node.supportsLongRange =
this.driver.controller.supportsLongRange
}
}

this.emitNodeUpdate(node, {
powerlevel: node.powerlevel,
measured0dBm: node.measured0dBm,
RFRegion: node.RFRegion,
supportsLongRange: node.supportsLongRange,
})
}

Expand Down Expand Up @@ -6397,6 +6454,7 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
| 'manufacturer'
| 'productDescription'
| 'productLabel'
| 'supportsLongRange'
>
> {
const zuiNode = this.nodes.get(node.id)
Expand Down Expand Up @@ -6433,6 +6491,8 @@ class ZwaveClient extends TypedEventEmitter<ZwaveClientEventCallbacks> {
productLabel: zuiNode?.productLabel,
deviceDatabaseUrl: node.deviceDatabaseUrl,
keepAwake: node.keepAwake,
protocol: node.protocol,
supportsLongRange: zuiNode?.supportsLongRange,
}
}

Expand Down
Loading

0 comments on commit bbf5ee6

Please sign in to comment.