Skip to content

Commit

Permalink
refactor: split up ZWaveApplicationHost more, remove unnecessary methods
Browse files Browse the repository at this point in the history
  • Loading branch information
AlCalzone committed Oct 16, 2024
1 parent 7f0342c commit 4c342cd
Show file tree
Hide file tree
Showing 10 changed files with 83 additions and 127 deletions.
22 changes: 2 additions & 20 deletions packages/cc/src/cc/FirmwareUpdateMetaDataCC.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ import { V } from "../lib/Values";
import {
FirmwareDownloadStatus,
FirmwareUpdateActivationStatus,
type FirmwareUpdateInitResult,
type FirmwareUpdateMetaData,
FirmwareUpdateMetaDataCommand,
FirmwareUpdateRequestStatus,
Expand Down Expand Up @@ -161,12 +160,12 @@ export class FirmwareUpdateMetaDataCCAPI extends PhysicalCCAPI {

/**
* Requests the device to start the firmware update process.
* WARNING: This method may wait up to 60 seconds for a reply.
* This does not wait for the reply - that is up to the caller of this method.
*/
@validateArgs()
public async requestUpdate(
options: FirmwareUpdateMetaDataCCRequestGetOptions,
): Promise<FirmwareUpdateInitResult> {
): Promise<void> {
this.assertSupportsCommand(
FirmwareUpdateMetaDataCommand,
FirmwareUpdateMetaDataCommand.RequestGet,
Expand All @@ -177,29 +176,12 @@ export class FirmwareUpdateMetaDataCCAPI extends PhysicalCCAPI {
endpoint: this.endpoint.index,
...options,
});
// Since the response may take longer than with other commands,
// we do not use the built-in waiting functionality, which would block
// all other communication.

await this.applHost.sendCommand(cc, {
...this.commandOptions,
// Do not wait for Nonce Reports
s2VerifyDelivery: false,
});
const result = await this.applHost
.waitForCommand<
FirmwareUpdateMetaDataCCRequestReport
>(
(cc) =>
cc instanceof FirmwareUpdateMetaDataCCRequestReport
&& cc.nodeId === this.endpoint.nodeId,
60000,
);
return pick(result, [
"status",
"resume",
"nonSecureTransfer",
]);
}

/**
Expand Down
4 changes: 2 additions & 2 deletions packages/cc/src/cc/ManufacturerSpecificCC.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ export class ManufacturerSpecificCC extends CommandClass {
endpoint,
).withOptions({ priority: MessagePriority.NodeQuery });

if (!applHost.isControllerNode(node.id)) {
if (node.id !== applHost.ownNodeId) {
applHost.controllerLog.logNode(node.id, {
endpoint: this.endpointIndex,
message: `Interviewing ${this.ccName}...`,
Expand All @@ -207,7 +207,7 @@ export class ManufacturerSpecificCC extends CommandClass {
const logMessage =
`received response for manufacturer information:
manufacturer: ${
applHost.configManager.lookupManufacturer(
applHost.lookupManufacturer(
mfResp.manufacturerId,
)
|| "unknown"
Expand Down
2 changes: 1 addition & 1 deletion packages/cc/src/cc/WakeUpCC.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ export class WakeUpCC extends CommandClass {
direction: "none",
});

if (applHost.isControllerNode(node.id)) {
if (node.id === applHost.ownNodeId) {
applHost.controllerLog.logNode(
node.id,
`skipping wakeup configuration for the controller`,
Expand Down
8 changes: 6 additions & 2 deletions packages/cc/src/lib/CommandClass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,12 +143,16 @@ export type CCNode =

export function getEffectiveCCVersion(
ctx: GetSupportedCCVersion,
cc: CommandClass,
cc: CCId,
defaultVersion?: number,
): number {
// For multicast and broadcast CCs, just use the highest implemented version to serialize
// Older nodes will ignore the additional fields
if (!cc.isSinglecast()) {
if (
typeof cc.nodeId !== "number"
|| cc.nodeId === NODE_ID_BROADCAST
|| cc.nodeId === NODE_ID_BROADCAST_LR
) {
return getImplementedVersion(cc.ccId);
}
// For singlecast CCs, set the CC version as high as possible
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/abstractions/ICommandClass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface SecurityManagers {
/** A basic abstraction of a Z-Wave Command Class providing access to the relevant functionality */
export interface CCId {
nodeId: number | MulticastDestination;
endpointIndex?: number;
ccId: CommandClasses;
ccCommand?: number;
}
Expand Down
88 changes: 37 additions & 51 deletions packages/host/src/ZWaveHost.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import type { ConfigManager, DeviceConfig } from "@zwave-js/config";
import type { DeviceConfig } from "@zwave-js/config";
import type {
CCId,
CommandClasses,
ControllerLogger,
FrameType,
MaybeNotKnown,
NodeIDType,
NodeId,
SecurityClass,
SecurityManagers,
Expand Down Expand Up @@ -51,6 +50,19 @@ export interface GetSupportedCCVersion {
): number;
}

export interface GetSafeCCVersion {
/**
* Retrieves the maximum version of a command class that can be used to communicate with a node.
* Returns 1 if the node claims that it does not support a CC.
* Returns `undefined` for CCs that are not implemented in this library yet.
*/
getSafeCCVersion(
cc: CommandClasses,
nodeId: number,
endpointIndex?: number,
): number | undefined;
}

/** Additional context needed for deserializing CCs */
export interface CCParsingContext
extends Readonly<SecurityManagers>, GetDeviceConfig, HostIDs
Expand Down Expand Up @@ -118,73 +130,47 @@ export interface GetAllNodes<T extends NodeId> {
getAllNodes(): T[];
}

/** Allows looking up Z-Wave manufacturers by manufacturer ID */
export interface LookupManufacturer {
/** Looks up the name of the manufacturer with the given ID in the configuration DB */
lookupManufacturer(manufacturerId: number): string | undefined;
}

/** Allows sending commands to one or more nodes */
export interface SendCommand {
sendCommand<TResponse extends CCId | undefined = undefined>(
command: CCId,
options?: SendCommandOptions,
): Promise<SendCommandReturnType<TResponse>>;
}

export interface ZWaveApplicationHost<TNode extends NodeId = NodeId>
extends
GetValueDB,
HostIDs,
GetNode<TNode>,
GetAllNodes<TNode>,
SecurityManagers,
GetDeviceConfig
GetDeviceConfig,
LookupManufacturer,
SchedulePoll,
GetSupportedCCVersion,
GetSafeCCVersion,
SendCommand
{
/** Gives access to the configuration files */
configManager: ConfigManager;

options: ZWaveHostOptions;

readonly nodeIdType?: NodeIDType;

// TODO: There's probably a better fitting name for this now
controllerLog: ControllerLogger;
}

/** Whether the node with the given ID is the controller */
isControllerNode(nodeId: number): boolean;

sendCommand<TResponse extends CCId | undefined = undefined>(
command: CCId,
options?: SendCommandOptions,
): Promise<SendCommandReturnType<TResponse>>;

waitForCommand<T extends CCId>(
predicate: (cc: CCId) => boolean,
timeout: number,
): Promise<T>;

/** Allows scheduling a value refresh (poll) for a later time */
export interface SchedulePoll {
schedulePoll(
nodeId: number,
valueId: ValueID,
options: NodeSchedulePollOptions,
): boolean;

/**
* Retrieves the maximum version of a command class that can be used to communicate with a node.
* Returns 1 if the node claims that it does not support a CC.
* Returns `undefined` for CCs that are not implemented in this library yet.
*/
getSafeCCVersion(
cc: CommandClasses,
nodeId: number,
endpointIndex?: number,
): number | undefined;

/**
* Retrieves the maximum version of a command class the given node/endpoint has reported support for.
* Returns 0 when the CC is not supported or that information is not known yet.
*/
getSupportedCCVersion(
cc: CommandClasses,
nodeId: number,
endpointIndex?: number,
): number;

/**
* Determines whether a CC must be secure for a given node and endpoint.
*/
isCCSecure(
cc: CommandClasses,
nodeId: number,
endpointIndex?: number,
): boolean;
}

export interface NodeSchedulePollOptions {
Expand Down
18 changes: 1 addition & 17 deletions packages/host/src/mocks.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
/* eslint-disable @typescript-eslint/require-await */
import { ConfigManager } from "@zwave-js/config";
import {
type EndpointId,
type GetEndpoint,
type IsCCSecure,
NodeIDType,
type NodeId,
type QuerySecurityClasses,
type SetSecurityClass,
Expand Down Expand Up @@ -54,8 +52,6 @@ export function createTestingHost<
const ret: TestingHost<TNode> = {
homeId: options.homeId ?? 0x7e570001,
ownNodeId: options.ownNodeId ?? 1,
nodeIdType: NodeIDType.Short,
isControllerNode: (nodeId) => nodeId === ret.ownNodeId,
securityManager: undefined,
securityManager2: undefined,
securityManagerLR: undefined,
Expand All @@ -67,7 +63,7 @@ export function createTestingHost<
};
},
}),
configManager: new ConfigManager(),
lookupManufacturer: () => undefined,
options: {
attempts: {
nodeInterview: 1,
Expand Down Expand Up @@ -114,15 +110,6 @@ export function createTestingHost<
tryGetValueDB: (nodeId) => {
return ret.getValueDB(nodeId);
},
isCCSecure: (ccId, nodeId, endpointIndex = 0) => {
const node = nodes.get(nodeId);
const endpoint = node?.getEndpoint(endpointIndex);
return (
node?.isSecure !== false
&& !!(endpoint ?? node)?.isCCSecure(ccId)
&& !!(ret.securityManager || ret.securityManager2)
);
},
// getHighestSecurityClass: (nodeId) => {
// const node = nodes.getOrThrow(nodeId);
// return node.getHighestSecurityClass();
Expand All @@ -138,9 +125,6 @@ export function createTestingHost<
sendCommand: async (_command, _options) => {
return undefined as any;
},
waitForCommand: async (_predicate, _timeout) => {
return undefined as any;
},
schedulePoll: (_nodeId, _valueId, _options) => {
return false;
},
Expand Down
22 changes: 6 additions & 16 deletions packages/zwave-js/src/lib/driver/Driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -726,7 +726,7 @@ export class Driver extends TypedEventEmitter<DriverEventCallbacks>
...this.messageEncodingContext,
ownNodeId: this.controller.ownNodeId!,
homeId: this.controller.homeId!,
nodeIdType: this.nodeIdType,
nodeIdType: this._controller?.nodeIdType ?? NodeIDType.Short,
securityManager: this.securityManager,
securityManager2: this.securityManager2,
securityManagerLR: this.securityManagerLR,
Expand All @@ -740,7 +740,7 @@ export class Driver extends TypedEventEmitter<DriverEventCallbacks>
...this.messageParsingContext,
ownNodeId: this.controller.ownNodeId!,
homeId: this.controller.homeId!,
nodeIdType: this.nodeIdType,
nodeIdType: this._controller?.nodeIdType ?? NodeIDType.Short,
securityManager: this.securityManager,
securityManager2: this.securityManager2,
securityManagerLR: this.securityManagerLR,
Expand Down Expand Up @@ -983,10 +983,6 @@ export class Driver extends TypedEventEmitter<DriverEventCallbacks>
return this.controller.ownNodeId!;
}

public get nodeIdType(): NodeIDType {
return this._controller?.nodeIdType ?? NodeIDType.Short;
}

/** @internal Used for compatibility with the ZWaveApplicationHost interface */
public getNode(nodeId: number): ZWaveNode | undefined {
return this.controller.nodes.get(nodeId);
Expand Down Expand Up @@ -1042,6 +1038,10 @@ export class Driver extends TypedEventEmitter<DriverEventCallbacks>
return this.controller.nodes.get(nodeId)?.deviceConfig;
}

public lookupManufacturer(manufacturerId: number): string | undefined {
return this.configManager.lookupManufacturer(manufacturerId);
}

public getHighestSecurityClass(
nodeId: number,
): MaybeNotKnown<SecurityClass> {
Expand Down Expand Up @@ -1074,16 +1074,6 @@ export class Driver extends TypedEventEmitter<DriverEventCallbacks>
node.setSecurityClass(securityClass, granted);
}

/**
* **!!! INTERNAL !!!**
*
* Not intended to be used by applications. Use `node.isControllerNode` instead!
*/
public isControllerNode(nodeId: number): boolean {
// This is needed for the ZWaveHost interface
return nodeId === this.ownNodeId;
}

/** Updates the logging configuration without having to restart the driver. */
public updateLogConfig(config: Partial<LogConfig>): void {
this._logContainer.updateConfiguration(config);
Expand Down
Loading

0 comments on commit 4c342cd

Please sign in to comment.