zwave-js
Version:
Z-Wave driver written entirely in JavaScript/TypeScript
187 lines • 7.46 kB
JavaScript
import { SwitchType } from "@zwave-js/cc";
import { MultilevelSwitchCCGet, MultilevelSwitchCCReport, MultilevelSwitchCCSet, MultilevelSwitchCCStartLevelChange, MultilevelSwitchCCStopLevelChange, MultilevelSwitchCCSupportedGet, MultilevelSwitchCCSupportedReport, } from "@zwave-js/cc/MultilevelSwitchCC";
import { CommandClasses, Duration, UNKNOWN_STATE, } from "@zwave-js/core";
import { setTimer } from "@zwave-js/shared";
import { getTransitionCurrentValue, getTransitionRemainingDuration, startTransition, stopTransition, } from "./MockTransition.js";
const defaultCapabilities = {
defaultValue: 0,
primarySwitchType: SwitchType["Down/Up"],
travelTime: 0,
};
const STATE_KEY_PREFIX = "MultilevelSwitch_";
const StateKeys = {
currentValue: `${STATE_KEY_PREFIX}currentValue`,
transition: `${STATE_KEY_PREFIX}transition`,
};
/** Stops any running transition and snaps state. */
function stopCurrentTransition(self) {
const existing = self.state.get(StateKeys.transition);
if (existing) {
const value = stopTransition(existing);
self.state.set(StateKeys.currentValue, value);
self.state.delete(StateKeys.transition);
return { wasSupervised: existing.supervised };
}
}
/**
* Stops any existing transition, then starts a new one.
* Manages all state reads/writes.
*/
function beginTransition(controller, self, receivedCC, targetValue, travelTime, defaultValue, supervised) {
stopCurrentTransition(self);
const currentValue = (self.state.get(StateKeys.currentValue)
?? defaultValue
?? 0);
const transition = startTransition({
currentValue,
targetValue,
duration: travelTime,
supervised,
onComplete: async () => {
self.state.set(StateKeys.currentValue, targetValue);
self.state.delete(StateKeys.transition);
if (supervised) {
await self.sendResponse(receivedCC, {
action: "ok",
});
return;
}
const cc = new MultilevelSwitchCCReport({
nodeId: controller.ownNodeId,
currentValue: targetValue,
targetValue,
duration: new Duration(0, "seconds"),
});
await self.sendResponse(receivedCC, {
action: "sendCC",
cc,
});
},
onAbort: async () => {
if (!supervised)
return;
await self.sendResponse(receivedCC, {
action: "fail",
});
},
});
if (transition) {
self.state.set(StateKeys.transition, transition);
return transition.durationMs;
}
else {
self.state.set(StateKeys.currentValue, targetValue);
return 0;
}
}
const respondToMultilevelSwitchGet = {
handleCC(controller, self, receivedCC) {
if (receivedCC instanceof MultilevelSwitchCCGet) {
const capabilities = {
...defaultCapabilities,
...self.getCCCapabilities(CommandClasses["Multilevel Switch"], receivedCC.endpointIndex),
};
const transition = self.state.get(StateKeys.transition);
let currentValue;
let targetValue;
let duration;
if (transition) {
currentValue = getTransitionCurrentValue(transition);
targetValue = transition.targetValue;
duration = getTransitionRemainingDuration(transition);
}
else {
currentValue = (self.state.get(StateKeys.currentValue)
?? capabilities.defaultValue
?? UNKNOWN_STATE);
targetValue = currentValue;
duration = new Duration(0, "seconds");
}
const cc = new MultilevelSwitchCCReport({
nodeId: controller.ownNodeId,
currentValue,
targetValue,
duration,
});
return { action: "sendCC", cc };
}
},
};
const respondToMultilevelSwitchSet = {
handleCC(controller, self, receivedCC) {
if (receivedCC instanceof MultilevelSwitchCCSet) {
const capabilities = {
...defaultCapabilities,
...self.getCCCapabilities(CommandClasses["Multilevel Switch"], receivedCC.endpointIndex),
};
const durationMs = beginTransition(controller, self, receivedCC, receivedCC.targetValue, capabilities.travelTime, capabilities.defaultValue, receivedCC.isEncapsulatedWith(CommandClasses.Supervision));
return {
action: "ok",
durationMs,
};
}
},
};
const respondToMultilevelSwitchSupportedGet = {
handleCC(controller, self, receivedCC) {
if (receivedCC instanceof MultilevelSwitchCCSupportedGet) {
const capabilities = {
...defaultCapabilities,
...self.getCCCapabilities(CommandClasses["Multilevel Switch"], receivedCC.endpointIndex),
};
const cc = new MultilevelSwitchCCSupportedReport({
nodeId: controller.ownNodeId,
switchType: capabilities.primarySwitchType,
});
return { action: "sendCC", cc };
}
},
};
const respondToMultilevelSwitchStartLevelChange = {
handleCC(controller, self, receivedCC) {
if (receivedCC instanceof MultilevelSwitchCCStartLevelChange) {
const capabilities = {
...defaultCapabilities,
...self.getCCCapabilities(CommandClasses["Multilevel Switch"], receivedCC.endpointIndex),
};
const targetValue = receivedCC.direction === "up" ? 99 : 0;
const durationMs = beginTransition(controller, self, receivedCC, targetValue, capabilities.travelTime, capabilities.defaultValue, receivedCC.isEncapsulatedWith(CommandClasses.Supervision));
return {
action: "ok",
durationMs,
};
}
},
};
const respondToMultilevelSwitchStopLevelChange = {
handleCC(controller, self, receivedCC) {
if (receivedCC instanceof MultilevelSwitchCCStopLevelChange) {
const stoppedTransition = stopCurrentTransition(self);
const currentValue = (self.state.get(StateKeys.currentValue) ?? 0);
if (!stoppedTransition?.wasSupervised) {
// Send a delayed report with the final state
setTimer(async () => {
const cc = new MultilevelSwitchCCReport({
nodeId: controller.ownNodeId,
currentValue,
targetValue: currentValue,
duration: new Duration(0, "seconds"),
});
await self.sendResponse(receivedCC, {
action: "sendCC",
cc,
});
}, 100).unref();
}
return { action: "ok" };
}
},
};
export const MultilevelSwitchCCBehaviors = [
respondToMultilevelSwitchGet,
respondToMultilevelSwitchSet,
respondToMultilevelSwitchSupportedGet,
respondToMultilevelSwitchStartLevelChange,
respondToMultilevelSwitchStopLevelChange,
];
//# sourceMappingURL=MultilevelSwitch.js.map