Skip to content

Commit

Permalink
feat: add methods to get/set max. LR powerlevel, add driver option to…
Browse files Browse the repository at this point in the history
… automatically configure it (#6824)
  • Loading branch information
AlCalzone authored May 8, 2024
1 parent 892698e commit d127c77
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 6 deletions.
94 changes: 94 additions & 0 deletions packages/zwave-js/src/lib/controller/Controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ import {
SerialAPISetup_CommandUnsupportedResponse,
SerialAPISetup_GetLongRangeMaximumPayloadSizeRequest,
type SerialAPISetup_GetLongRangeMaximumPayloadSizeResponse,
SerialAPISetup_GetLongRangeMaximumTxPowerRequest,
type SerialAPISetup_GetLongRangeMaximumTxPowerResponse,
SerialAPISetup_GetMaximumPayloadSizeRequest,
type SerialAPISetup_GetMaximumPayloadSizeResponse,
SerialAPISetup_GetPowerlevel16BitRequest,
Expand All @@ -180,6 +182,8 @@ import {
type SerialAPISetup_GetRFRegionResponse,
SerialAPISetup_GetSupportedCommandsRequest,
type SerialAPISetup_GetSupportedCommandsResponse,
SerialAPISetup_SetLongRangeMaximumTxPowerRequest,
type SerialAPISetup_SetLongRangeMaximumTxPowerResponse,
SerialAPISetup_SetNodeIDTypeRequest,
type SerialAPISetup_SetNodeIDTypeResponse,
SerialAPISetup_SetPowerlevel16BitRequest,
Expand Down Expand Up @@ -1323,6 +1327,54 @@ export class ZWaveController
);
}
}

// Check and possibly update the Long Range powerlevel settings
if (
this.isSerialAPISetupCommandSupported(
SerialAPISetupCommand.GetLongRangeMaximumTxPower,
)
&& this.isSerialAPISetupCommandSupported(
SerialAPISetupCommand.SetLongRangeMaximumTxPower,
)
&& this.driver.options.rf?.maxLongRangePowerlevel != undefined
) {
const desired = this.driver.options.rf.maxLongRangePowerlevel;
this.driver.controllerLog.print(
`Querying configured max. Long Range powerlevel...`,
);
const current = await this.getMaxLongRangePowerlevel().catch(() =>
undefined
);
if (current != undefined) {
if (
current !== desired
) {
this.driver.controllerLog.print(
`Current max. Long Range powerlevel ${current} dBm differs from desired powerlevel ${desired} dBm, configuring it...`,
);

const resp = await this.setMaxLongRangePowerlevel(desired)
.catch((e) => (e as Error).message);
if (resp === true) {
this.driver.controllerLog.print(
`max. Long Range powerlevel updated`,
);
} else {
this.driver.controllerLog.print(
`Changing the max. Long Range powerlevel failed!${
resp ? ` Reason: ${resp}` : ""
}`,
"warn",
);
}
}
} else {
this.driver.controllerLog.print(
`Querying the max. Long Range powerlevel failed!`,
"warn",
);
}
}
}

/**
Expand Down Expand Up @@ -6022,6 +6074,48 @@ ${associatedNodes.join(", ")}`,
return pick(result, ["powerlevel", "measured0dBm"]);
}

/** Configure the maximum TX powerlevel for Z-Wave Long Range */
public async setMaxLongRangePowerlevel(
limit: number,
): Promise<boolean> {
const request = new SerialAPISetup_SetLongRangeMaximumTxPowerRequest(
this.driver,
{ limit },
);

const result = await this.driver.sendMessage<
| SerialAPISetup_SetLongRangeMaximumTxPowerResponse
| SerialAPISetup_CommandUnsupportedResponse
>(request);

if (result instanceof SerialAPISetup_CommandUnsupportedResponse) {
throw new ZWaveError(
`Your hardware does not support setting the max. Long Range powerlevel!`,
ZWaveErrorCodes.Driver_NotSupported,
);
}
return result.success;
}

/** Request the maximum TX powerlevel setting for Z-Wave Long Range */
public async getMaxLongRangePowerlevel(): Promise<number> {
const request = new SerialAPISetup_GetLongRangeMaximumTxPowerRequest(
this.driver,
);
const result = await this.driver.sendMessage<
| SerialAPISetup_GetLongRangeMaximumTxPowerResponse
| SerialAPISetup_CommandUnsupportedResponse
>(request);

if (result instanceof SerialAPISetup_CommandUnsupportedResponse) {
throw new ZWaveError(
`Your hardware does not support getting the max. Long Range powerlevel!`,
ZWaveErrorCodes.Driver_NotSupported,
);
}
return result.limit;
}

/**
* @internal
* Configure whether the Z-Wave API should use short (8 bit) or long (16 bit) Node IDs
Expand Down
3 changes: 3 additions & 0 deletions packages/zwave-js/src/lib/driver/ZWaveOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,9 @@ export interface ZWaveOptions extends ZWaveHostOptions {
/** A hardware-specific calibration value. */
measured0dBm: number;
};

/** The desired max. powerlevel setting for Z-Wave Long Range in dBm. */
maxLongRangePowerlevel?: number;
};

apiKeys?: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -810,7 +810,7 @@ export class SerialAPISetup_GetLongRangeMaximumTxPowerResponse
this.limit = this.payload.readInt16BE(0) / 10;
}

/** The maximum LR TX power dBm */
/** The maximum LR TX power in dBm */
public readonly limit: number;

public toLogEntry(): MessageOrCCLogEntry {
Expand Down Expand Up @@ -863,11 +863,12 @@ export class SerialAPISetup_SetLongRangeMaximumTxPowerRequest
}
}

/** The maximum LR TX power in dBm */
public limit: number;

public serialize(): Buffer {
this.payload = Buffer.allocUnsafe(2);
// The values are in 0.1 dBm
// The values are in 0.1 dBm, signed
this.payload.writeInt16BE(Math.round(this.limit * 10), 0);

return super.serialize();
Expand Down
23 changes: 19 additions & 4 deletions test/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ process.on("unhandledRejection", (_r) => {

// const port = "tcp://Z-Net-R2v2.local:2001";
// 500/700 series
const port = require("node:os").platform() === "win32"
? "COM5"
: "/dev/ttyACM0";
// const port = require("node:os").platform() === "win32"
// ? "COM5"
// : "/dev/ttyACM0";
// const port = require("os").platform() === "win32" ? "COM5" : "/dev/ttyUSB0";
// 800 series
// const port = require("node:os").platform() === "win32" ? "COM5" : "/dev/serial/by-id/usb-1a86_USB_Single_Serial_5479014030-if00";
const port = require("node:os").platform() === "win32"
? "COM5"
: "/dev/serial/by-id/usb-Zooz_800_Z-Wave_Stick_533D004242-if00";

const driver = new Driver(port, {
// logConfig: {
Expand All @@ -43,6 +45,19 @@ const driver = new Driver(port, {
"hex",
),
},
securityKeysLongRange: {
S2_Authenticated: Buffer.from(
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"hex",
),
S2_AccessControl: Buffer.from(
"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
"hex",
),
},
rf: {
maxLongRangePowerlevel: 14,
},
storage: {
cacheDir: path.join(__dirname, "cache"),
lockDir: path.join(__dirname, "cache/locks"),
Expand Down

0 comments on commit d127c77

Please sign in to comment.