Skip to content

Commit

Permalink
fix: add compat flag to always encode Set-type commands using target …
Browse files Browse the repository at this point in the history
…node's CC version (zwave-js#6918)
  • Loading branch information
AlCalzone authored Jun 11, 2024
1 parent 09118c9 commit 1760cd7
Show file tree
Hide file tree
Showing 9 changed files with 96 additions and 0 deletions.
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

0 comments on commit 1760cd7

Please sign in to comment.