Skip to content

Commit

Permalink
feat: add Thermostat Setback mocks, fix state encoding, remove CC values
Browse files Browse the repository at this point in the history
  • Loading branch information
AlCalzone committed Oct 10, 2024
1 parent e888a54 commit 81f9530
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 50 deletions.
86 changes: 40 additions & 46 deletions packages/cc/src/cc/ThermostatSetbackCC.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ import {
CommandClasses,
type MaybeNotKnown,
MessagePriority,
ValueMetadata,
ZWaveError,
ZWaveErrorCodes,
validatePayload,
} from "@zwave-js/core/safe";
import type {
Expand All @@ -33,44 +30,18 @@ import {
import {
API,
CCCommand,
ccValue,
ccValues,
commandClass,
expectedCCResponse,
implementedVersion,
useSupervision,
} from "../lib/CommandClassDecorators";
import { V } from "../lib/Values";
import {
type SetbackState,
SetbackType,
ThermostatSetbackCommand,
} from "../lib/_Types";
import { decodeSetbackState, encodeSetbackState } from "../lib/serializers";

export const ThermostatSetbackCCValues = Object.freeze({
...V.defineStaticCCValues(CommandClasses["Thermostat Setback"], {
...V.staticProperty(
"setbackType",
{
// TODO: This should be a value list
...ValueMetadata.Any,
label: "Setback type",
} as const,
),

...V.staticProperty(
"setbackState",
{
...ValueMetadata.Int8,
min: -12.8,
max: 12,
label: "Setback state",
} as const,
),
}),
});

// @noSetValueAPI
// The setback state consist of two values that must be set together

Expand Down Expand Up @@ -145,7 +116,6 @@ export class ThermostatSetbackCCAPI extends CCAPI {

@commandClass(CommandClasses["Thermostat Setback"])
@implementedVersion(1)
@ccValues(ThermostatSetbackCCValues)
export class ThermostatSetbackCC extends CommandClass {
declare ccCommand: ThermostatSetbackCommand;

Expand Down Expand Up @@ -212,11 +182,12 @@ export class ThermostatSetbackCCSet extends ThermostatSetbackCC {
) {
super(host, options);
if (gotDeserializationOptions(options)) {
// TODO: Deserialize payload
throw new ZWaveError(
`${this.constructor.name}: deserialization not implemented`,
ZWaveErrorCodes.Deserialization_NotImplemented,
);
validatePayload(this.payload.length >= 2);
this.setbackType = this.payload[0] & 0b11;
// If we receive an unknown setback state, return the raw value
const rawSetbackState = this.payload.readInt8(1);
this.setbackState = decodeSetbackState(rawSetbackState)
|| rawSetbackState;
} else {
this.setbackType = options.setbackType;
this.setbackState = options.setbackState;
Expand All @@ -243,34 +214,55 @@ export class ThermostatSetbackCCSet extends ThermostatSetbackCC {
SetbackType,
this.setbackType,
),
"setback state": this.setbackState,
"setback state": typeof this.setbackState === "number"
? `${this.setbackState} K`
: this.setbackState,
},
};
}
}

// @publicAPI
export interface ThermostatSetbackCCReportOptions {
setbackType: SetbackType;
setbackState: SetbackState;
}

@CCCommand(ThermostatSetbackCommand.Report)
export class ThermostatSetbackCCReport extends ThermostatSetbackCC {
public constructor(
host: ZWaveHost,
options: CommandClassDeserializationOptions,
options:
| CommandClassDeserializationOptions
| (CCCommandOptions & ThermostatSetbackCCReportOptions),
) {
super(host, options);

validatePayload(this.payload.length >= 2);
this.setbackType = this.payload[0] & 0b11;
// If we receive an unknown setback state, return the raw value
this.setbackState = decodeSetbackState(this.payload[1])
|| this.payload[1];
if (gotDeserializationOptions(options)) {
validatePayload(this.payload.length >= 2);
this.setbackType = this.payload[0] & 0b11;
// If we receive an unknown setback state, return the raw value
const rawSetbackState = this.payload.readInt8(1);
this.setbackState = decodeSetbackState(rawSetbackState)
|| rawSetbackState;
} else {
this.setbackType = options.setbackType;
this.setbackState = options.setbackState;
}
}

@ccValue(ThermostatSetbackCCValues.setbackType)
public readonly setbackType: SetbackType;

@ccValue(ThermostatSetbackCCValues.setbackState)
/** The offset from the setpoint in 0.1 Kelvin or a special mode */
public readonly setbackState: SetbackState;

public serialize(): Buffer {
this.payload = Buffer.from([
this.setbackType & 0b11,
encodeSetbackState(this.setbackState),
]);
return super.serialize();
}

public toLogEntry(host?: ZWaveValueHost): MessageOrCCLogEntry {
return {
...super.toLogEntry(host),
Expand All @@ -279,7 +271,9 @@ export class ThermostatSetbackCCReport extends ThermostatSetbackCC {
SetbackType,
this.setbackType,
),
"setback state": this.setbackState,
"setback state": typeof this.setbackState === "number"
? `${this.setbackState} K`
: this.setbackState,
},
};
}
Expand Down
7 changes: 5 additions & 2 deletions packages/cc/src/cc/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,7 @@ export type {
MultilevelSwitchCCReportOptions,
MultilevelSwitchCCSetOptions,
MultilevelSwitchCCStartLevelChangeOptions,
MultilevelSwitchCCSupportedReportOptions,
} from "./MultilevelSwitchCC";
export {
MultilevelSwitchCC,
Expand Down Expand Up @@ -735,13 +736,15 @@ export {
ThermostatOperatingStateCCReport,
ThermostatOperatingStateCCValues,
} from "./ThermostatOperatingStateCC";
export type { ThermostatSetbackCCSetOptions } from "./ThermostatSetbackCC";
export type {
ThermostatSetbackCCReportOptions,
ThermostatSetbackCCSetOptions,
} from "./ThermostatSetbackCC";
export {
ThermostatSetbackCC,
ThermostatSetbackCCGet,
ThermostatSetbackCCReport,
ThermostatSetbackCCSet,
ThermostatSetbackCCValues,
} from "./ThermostatSetbackCC";
export type {
ThermostatSetpointCCCapabilitiesGetOptions,
Expand Down
2 changes: 0 additions & 2 deletions packages/cc/src/lib/Values.ts
Original file line number Diff line number Diff line change
Expand Up @@ -643,8 +643,6 @@ export interface CCValues {
typeof import("../cc/ThermostatModeCC").ThermostatModeCCValues;
"Thermostat Operating State":
typeof import("../cc/ThermostatOperatingStateCC").ThermostatOperatingStateCCValues;
"Thermostat Setback":
typeof import("../cc/ThermostatSetbackCC").ThermostatSetbackCCValues;
"Thermostat Setpoint":
typeof import("../cc/ThermostatSetpointCC").ThermostatSetpointCCValues;
"Time Parameters":
Expand Down
2 changes: 2 additions & 0 deletions packages/zwave-js/src/lib/node/MockNodeBehaviors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import { NotificationCCBehaviors } from "./mockCCBehaviors/Notification";
import { ScheduleEntryLockCCBehaviors } from "./mockCCBehaviors/ScheduleEntryLock";
import { SoundSwitchCCBehaviors } from "./mockCCBehaviors/SoundSwitch";
import { ThermostatModeCCBehaviors } from "./mockCCBehaviors/ThermostatMode";
import { ThermostatSetbackCCBehaviors } from "./mockCCBehaviors/ThermostatSetback";
import { ThermostatSetpointCCBehaviors } from "./mockCCBehaviors/ThermostatSetpoint";
import { UserCodeCCBehaviors } from "./mockCCBehaviors/UserCode";
import { WindowCoveringCCBehaviors } from "./mockCCBehaviors/WindowCovering";
Expand Down Expand Up @@ -193,6 +194,7 @@ export function createDefaultBehaviors(): MockNodeBehavior[] {
...SoundSwitchCCBehaviors,
...ThermostatModeCCBehaviors,
...ThermostatSetpointCCBehaviors,
...ThermostatSetbackCCBehaviors,
...UserCodeCCBehaviors,
...WindowCoveringCCBehaviors,
];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { type SetbackState, SetbackType } from "@zwave-js/cc";
import {
ThermostatSetbackCCGet,
ThermostatSetbackCCReport,
ThermostatSetbackCCSet,
} from "@zwave-js/cc/ThermostatSetbackCC";
import { type MockNodeBehavior } from "@zwave-js/testing";

const STATE_KEY_PREFIX = "ThermostatSetback_";
const StateKeys = {
setbackType: `${STATE_KEY_PREFIX}setbackType`,
setbackState: `${STATE_KEY_PREFIX}setbackState`,
} as const;

const respondToThermostatSetbackSet: MockNodeBehavior = {
handleCC(controller, self, receivedCC) {
if (receivedCC instanceof ThermostatSetbackCCSet) {
self.state.set(StateKeys.setbackType, receivedCC.setbackType);
self.state.set(StateKeys.setbackState, receivedCC.setbackState);
return { action: "ok" };
}
},
};

const respondToThermostatSetbackGet: MockNodeBehavior = {
handleCC(controller, self, receivedCC) {
if (receivedCC instanceof ThermostatSetbackCCGet) {
const setbackType = (
self.state.get(StateKeys.setbackType)
?? SetbackType.None
) as SetbackType;
const setbackState = (
self.state.get(StateKeys.setbackState)
?? "Unused"
) as SetbackState;

const cc = new ThermostatSetbackCCReport(self.host, {
nodeId: controller.host.ownNodeId,
setbackType,
setbackState,
});
return { action: "sendCC", cc };
}
},
};

export const ThermostatSetbackCCBehaviors = [
respondToThermostatSetbackGet,
respondToThermostatSetbackSet,
];

0 comments on commit 81f9530

Please sign in to comment.