Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: add compat flag to always encode Set-type commands using target node's CC version #6918

Merged
merged 2 commits into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/config-files/file-format.md
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,10 @@ Without the additional integrity checks that encapsulation CCs like `CRC-16`, `S

Some devices incorrectly encode this support information though, making the checks discard otherwise correct data. To disable the checks, set `disableStrictMeasurementValidation` to `true`.

### `encodeCCsUsingTargetVersion`

Because command classes are extended in a backwards-compatible way, the Z-Wave specifications recommend encoding command classes using the version the sender supports, regardless of the receiver's version. However it has been found that some devices do not correctly parse commands from a newer version and do not react to them. When `encodeCCsUsingTargetVersion` is set to `true` for a device, Z-Wave JS will encode commands using the version the receiver supports instead.

### `forceNotificationIdleReset`

Version 8 of the `Notification CC` added the requirement that devices must issue an idle notification after a notification variable is no longer active. Several legacy devices and some misbehaving V8 devices do not return their variables to idle automatically. By setting `forceNotificationIdleReset` to `true`, `zwave-js` auto-idles supporting notification variables after 5 minutes.
Expand Down
3 changes: 3 additions & 0 deletions maintenance/schemas/device-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,9 @@
"disableStrictMeasurementValidation": {
"const": true
},
"encodeCCsUsingTargetVersion": {
"const": true
},
"forceNotificationIdleReset": {
"const": true
},
Expand Down
10 changes: 10 additions & 0 deletions packages/cc/src/cc/BasicCC.ts
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,16 @@ export class BasicCCReport extends BasicCC {
this.targetValue ?? 0xfe,
(this.duration ?? Duration.unknown()).serializeReport(),
]);

if (
this.version < 2 && this.host.getDeviceConfig?.(
this.nodeId as number,
)?.compat?.encodeCCsUsingTargetVersion
) {
// When forcing CC version 1, only send the current value
this.payload = this.payload.subarray(0, 1);
}

return super.serialize();
}

Expand Down
10 changes: 10 additions & 0 deletions packages/cc/src/cc/BinarySwitchCC.ts
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,16 @@ export class BinarySwitchCCSet extends BinarySwitchCC {
this.targetValue ? 0xff : 0x00,
(this.duration ?? Duration.default()).serializeSet(),
]);

if (
this.version < 2 && this.host.getDeviceConfig?.(
this.nodeId as number,
)?.compat?.encodeCCsUsingTargetVersion
) {
// When forcing CC version 1, only send the target value
this.payload = this.payload.subarray(0, 1);
}

return super.serialize();
}

Expand Down
20 changes: 20 additions & 0 deletions packages/cc/src/cc/ColorSwitchCC.ts
Original file line number Diff line number Diff line change
Expand Up @@ -945,6 +945,16 @@ export class ColorSwitchCCSet extends ColorSwitchCC {
this.payload[i] = (
this.duration ?? Duration.default()
).serializeSet();

if (
this.version < 2 && this.host.getDeviceConfig?.(
this.nodeId as number,
)?.compat?.encodeCCsUsingTargetVersion
) {
// When forcing CC version 1, omit the duration byte
this.payload = this.payload.subarray(0, -1);
}

return super.serialize();
}

Expand Down Expand Up @@ -1027,6 +1037,16 @@ export class ColorSwitchCCStartLevelChange extends ColorSwitchCC {
this.startLevel,
(this.duration ?? Duration.default()).serializeSet(),
]);

if (
this.version < 3 && this.host.getDeviceConfig?.(
this.nodeId as number,
)?.compat?.encodeCCsUsingTargetVersion
) {
// When forcing CC version 1 or 2, omit the duration byte
this.payload = this.payload.subarray(0, -1);
}

return super.serialize();
}

Expand Down
20 changes: 20 additions & 0 deletions packages/cc/src/cc/MultilevelSwitchCC.ts
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,16 @@ export class MultilevelSwitchCCSet extends MultilevelSwitchCC {
this.targetValue,
(this.duration ?? Duration.default()).serializeSet(),
]);

if (
this.version < 2 && this.host.getDeviceConfig?.(
this.nodeId as number,
)?.compat?.encodeCCsUsingTargetVersion
) {
// When forcing CC version 1, only include the target value
this.payload = this.payload.subarray(0, 1);
}

return super.serialize();
}

Expand Down Expand Up @@ -796,6 +806,16 @@ export class MultilevelSwitchCCStartLevelChange extends MultilevelSwitchCC {
this.startLevel,
(this.duration ?? Duration.default()).serializeSet(),
]);

if (
this.version < 2 && this.host.getDeviceConfig?.(
this.nodeId as number,
)?.compat?.encodeCCsUsingTargetVersion
) {
// When forcing CC version 1, omit the duration byte
this.payload = this.payload.subarray(0, -1);
}

return super.serialize();
}

Expand Down
10 changes: 10 additions & 0 deletions packages/cc/src/cc/ProtectionCC.ts
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,16 @@ export class ProtectionCCSet extends ProtectionCC {
this.local & 0b1111,
(this.rf ?? RFProtectionState.Unprotected) & 0b1111,
]);

if (
this.version < 2 && this.host.getDeviceConfig?.(
this.nodeId as number,
)?.compat?.encodeCCsUsingTargetVersion
) {
// When forcing CC version 1, only include the local state
this.payload = this.payload.subarray(0, 1);
}

return super.serialize();
}

Expand Down
4 changes: 4 additions & 0 deletions packages/config/config/devices/0x0118/tz67.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@
]
}
],
"compat": {
// The device does not react to Multilevel Switch commands that include a duration field
"encodeCCsUsingTargetVersion": true
},
"metadata": {
"manual": "https://products.z-wavealliance.org/ProductManual/File?folder=&filename=MarketCertificationFiles/1951/TZ67%20User%20Manual.pdf"
}
Expand Down
15 changes: 15 additions & 0 deletions packages/config/src/devices/CompatConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,19 @@ compat option disableStrictMeasurementValidation must be true or omitted`,
definition.disableStrictMeasurementValidation;
}

if (definition.encodeCCsUsingTargetVersion != undefined) {
if (definition.encodeCCsUsingTargetVersion !== true) {
throwInvalidConfig(
"devices",
`config/devices/${filename}:
compat option encodeCCsUsingTargetVersion must be true or omitted`,
);
}

this.encodeCCsUsingTargetVersion =
definition.encodeCCsUsingTargetVersion;
}

if (definition.forceNotificationIdleReset != undefined) {
if (definition.forceNotificationIdleReset !== true) {
throwInvalidConfig(
Expand Down Expand Up @@ -602,6 +615,7 @@ compat option overrideQueries must be an object!`,
public readonly disableStrictEntryControlDataValidation?: boolean;
public readonly disableStrictMeasurementValidation?: boolean;
public readonly disableCallbackFunctionTypeCheck?: number[];
public readonly encodeCCsUsingTargetVersion?: boolean;
public readonly forceNotificationIdleReset?: boolean;
public readonly forceSceneControllerGroupCount?: number;
public readonly manualValueRefreshDelayMs?: number;
Expand Down Expand Up @@ -646,6 +660,7 @@ compat option overrideQueries must be an object!`,
"disableCallbackFunctionTypeCheck",
"disableStrictEntryControlDataValidation",
"disableStrictMeasurementValidation",
"encodeCCsUsingTargetVersion",
"forceNotificationIdleReset",
"forceSceneControllerGroupCount",
"manualValueRefreshDelayMs",
Expand Down
Loading