zwave-js
Version:
Z-Wave driver written entirely in JavaScript/TypeScript
91 lines (90 loc) • 4.52 kB
JavaScript
import { CentralSceneCCValues, CentralSceneKeys, } from "@zwave-js/cc";
import { setTimer, stringify } from "@zwave-js/shared";
export function getDefaultCentralSceneHandlerStore() {
return {
keyHeldDownContext: undefined,
lastSequenceNumber: undefined,
forcedKeyUp: false,
};
}
/** Handles the receipt of a ThermostatModeCC Set */
export function handleCentralSceneNotification(ctx, node, command, store) {
// Did we already receive this command?
if (command.sequenceNumber === store.lastSequenceNumber) {
return;
}
else {
store.lastSequenceNumber = command.sequenceNumber;
}
/*
If the Slow Refresh field is false:
- A new Key Held Down notification MUST be sent every 200ms until the key is released.
- The Sequence Number field MUST be updated at each notification transmission.
- If not receiving a new Key Held Down notification within 400ms, a controlling node SHOULD use an adaptive timeout approach as described in 4.17.1:
A controller SHOULD apply an adaptive approach based on the reception of the Key Released Notification.
Initially, the controller SHOULD time out if not receiving any Key Held Down Notification refresh after
400ms and consider this to be a Key Up Notification. If, however, the controller subsequently receives a
Key Released Notification, the controller SHOULD consider the sending node to be operating with the Slow
Refresh capability enabled.
If the Slow Refresh field is true:
- A new Key Held Down notification MUST be sent every 55 seconds until the key is released.
- The Sequence Number field MUST be updated at each notification refresh.
- If not receiving a new Key Held Down notification within 60 seconds after the most recent Key Held Down
notification, a receiving node MUST respond as if it received a Key Release notification.
*/
const setSceneValue = (sceneNumber, key) => {
const valueId = CentralSceneCCValues.scene(sceneNumber).id;
node.valueDB.setValue(valueId, key, { stateful: false });
};
const forceKeyUp = () => {
store.forcedKeyUp = true;
// force key up event
setSceneValue(store.keyHeldDownContext.sceneNumber, CentralSceneKeys.KeyReleased);
// clear old timer
store.keyHeldDownContext?.timeout?.clear();
// clear the key down context
store.keyHeldDownContext = undefined;
};
if (store.keyHeldDownContext
&& store.keyHeldDownContext.sceneNumber
!== command.sceneNumber) {
// The user pressed another button, force release
forceKeyUp();
}
const slowRefreshValueId = CentralSceneCCValues.slowRefresh.endpoint(command.endpointIndex);
if (command.keyAttribute === CentralSceneKeys.KeyHeldDown) {
// Set or refresh timer to force a release of the key
store.forcedKeyUp = false;
store.keyHeldDownContext?.timeout?.clear();
// If the node does not advertise support for the slow refresh capability, we might still be dealing with a
// slow refresh node. We use the stored value for fallback behavior
const slowRefresh = command.slowRefresh
// Prefer the stored value, even if the command claims slowRefresh == false
|| node.valueDB.getValue(slowRefreshValueId);
store.keyHeldDownContext = {
sceneNumber: command.sceneNumber,
// Unref'ing long running timers allows the process to exit mid-timeout
timeout: setTimer(forceKeyUp, slowRefresh ? 60000 : 400).unref(),
};
}
else if (command.keyAttribute === CentralSceneKeys.KeyReleased) {
// Stop the release timer
if (store.keyHeldDownContext) {
store.keyHeldDownContext.timeout.clear();
store.keyHeldDownContext = undefined;
}
else if (store.forcedKeyUp) {
// If we timed out and the controller subsequently receives a Key Released Notification,
// we SHOULD consider the sending node to be operating with the Slow Refresh capability enabled.
node.valueDB.setValue(slowRefreshValueId, true);
// Do not raise the duplicate event
return;
}
}
setSceneValue(command.sceneNumber, command.keyAttribute);
ctx.logNode(node.id, {
message: `received CentralScene notification ${stringify(command)}`,
direction: "inbound",
});
}
//# sourceMappingURL=CentralSceneCC.js.map