UNPKG

zwave-js

Version:

Z-Wave driver written entirely in JavaScript/TypeScript

346 lines (345 loc) 15.8 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var NotificationCC_exports = {}; __export(NotificationCC_exports, { getDefaultNotificationHandlerStore: () => getDefaultNotificationHandlerStore, handleNotificationReport: () => handleNotificationReport, manuallyIdleNotificationValueInternal: () => manuallyIdleNotificationValueInternal }); module.exports = __toCommonJS(NotificationCC_exports); var import_cc = require("@zwave-js/cc"); var import_NotificationCC = require("@zwave-js/cc/NotificationCC"); var import_core = require("@zwave-js/core"); var import_shared = require("@zwave-js/shared"); function getDefaultNotificationHandlerStore() { return { idleTimeouts: /* @__PURE__ */ new Map() }; } __name(getDefaultNotificationHandlerStore, "getDefaultNotificationHandlerStore"); function handleNotificationReport(ctx, node, command, store) { if (command.notificationType == void 0) { if (command.alarmType == void 0) { ctx.logNode(node.id, { message: `received unsupported notification ${(0, import_shared.stringify)(command)}`, direction: "inbound" }); } return; } const remappings = node.deviceConfig?.compat?.remapNotifications; if (remappings?.length) { const match = remappings.find((m) => m.from.notificationType === command.notificationType && m.from.notificationEvent === command.notificationEvent); if (match) { ctx.logNode(node.id, { message: `Notification remapped via compat flag`, direction: "inbound", level: "verbose" }); if (match.action.type === "clear" || match.action.type === "idle") { for (const target of match.action.targets) { const targetNotification = (0, import_core.getNotification)(target.notificationType); if (!targetNotification) continue; const targetValueConfig = (0, import_core.getNotificationValue)(targetNotification, target.notificationEvent); if (targetValueConfig?.type !== "state") continue; const valueId = import_cc.NotificationCCValues.notificationVariable(targetNotification.name, targetValueConfig.variableName).endpoint(command.endpointIndex); if (match.action.type === "clear") { if (node.valueDB.getValue(valueId) === target.notificationEvent) { node.valueDB.setValue(valueId, import_core.UNKNOWN_STATE); } if (target.notificationType === 6 && (target.notificationEvent === 22 || target.notificationEvent === 23)) { const simpleDoorStateId = import_cc.NotificationCCValues.deprecated_doorStateSimple.endpoint(command.endpointIndex); if (node.valueDB.getValue(simpleDoorStateId) === target.notificationEvent) { node.valueDB.setValue(simpleDoorStateId, import_core.UNKNOWN_STATE); } } } else { node.valueDB.setValue( valueId, 0 /* idle */ ); } } return; } else { const to = match.action.to; command.notificationType = to.notificationType; command.notificationEvent = to.notificationEvent; } } } const ccVersion = (0, import_cc.getEffectiveCCVersion)(ctx, command); const notification = (0, import_core.getNotification)(command.notificationType); if (notification) { const notificationName = notification.name; ctx.logNode(node.id, { message: `[handleNotificationReport] notificationName: ${notificationName}`, level: "silly" }); const setStateIdle = /* @__PURE__ */ __name((prevValue) => { manuallyIdleNotificationValueInternal(ctx, node, store, notification, prevValue, command.endpointIndex); }, "setStateIdle"); const setUnknownStateIdle = /* @__PURE__ */ __name((prevValue) => { const unknownNotificationVariableValueId = import_cc.NotificationCCValues.unknownNotificationVariable(command.notificationType, notificationName).endpoint(command.endpointIndex); const currentValue = node.valueDB.getValue(unknownNotificationVariableValueId); if (currentValue == void 0) return; if (prevValue == void 0 || currentValue === prevValue) { node.valueDB.setValue(unknownNotificationVariableValueId, 0); } }, "setUnknownStateIdle"); const value = command.notificationEvent; if (value === 0) { if ((0, import_shared.isUint8Array)(command.eventParameters) && command.eventParameters.length) { setStateIdle(command.eventParameters[0]); setUnknownStateIdle(command.eventParameters[0]); } else { const nonIdleValues = node.valueDB.getValues(import_core.CommandClasses.Notification).filter((v) => (v.endpoint || 0) === command.endpointIndex && v.property === notificationName && typeof v.value === "number" && v.value !== 0); for (const v of nonIdleValues) { setStateIdle(v.value); } setUnknownStateIdle(); } return; } const valueConfig = (0, import_core.getNotificationValue)(notification, value); if (valueConfig) { ctx.logNode(node.id, { message: `[handleNotificationReport] valueConfig: label: ${valueConfig.label} ${valueConfig.type === "event" ? "type: event" : `type: state variableName: ${valueConfig.variableName}`}`, level: "silly" }); } else { ctx.logNode(node.id, { message: `[handleNotificationReport] valueConfig: undefined`, level: "silly" }); } handleKnownNotification(ctx, node, command); let allowIdleReset; if (!valueConfig) { allowIdleReset = false; } else if (valueConfig.type === "state") { allowIdleReset = valueConfig.idle; } else { const endpoint = node.getEndpoint(command.endpointIndex) ?? node; const eventArgs = { type: command.notificationType, event: value, label: notification.name, eventLabel: valueConfig.label, parameters: command.eventParameters }; const prefs = ctx.getUserPreferences(); if (prefs.lookupUserIdInNotificationEvents && command.eventParameters != null && typeof command.eventParameters === "object" && !(0, import_shared.isUint8Array)(command.eventParameters) && "userId" in command.eventParameters && typeof command.eventParameters.userId === "number") { const userId = command.eventParameters.userId; const nodeEndpoint = { nodeId: node.id, index: command.endpointIndex, virtual: false }; const enhancedParameters = { ...command.eventParameters }; const userIdStatus = import_cc.UserCodeCC.getUserIdStatusCached(ctx, nodeEndpoint, userId); if (userIdStatus != null) { enhancedParameters.userIdStatus = userIdStatus; } const userCode = import_cc.UserCodeCC.getUserCodeCached(ctx, nodeEndpoint, userId); if (userCode != null) { enhancedParameters.userCode = userCode; } eventArgs.parameters = enhancedParameters; } node.emit("notification", endpoint, import_core.CommandClasses.Notification, eventArgs); if (valueConfig.idleVariables?.length) { for (const variable of valueConfig.idleVariables) { setStateIdle(variable); } } return; } let valueId; if (valueConfig) { valueId = import_cc.NotificationCCValues.notificationVariable(notificationName, valueConfig.variableName).endpoint(command.endpointIndex); extendNotificationValueMetadata(ctx, node, valueId, notification, valueConfig); } else { const unknownValue = import_cc.NotificationCCValues.unknownNotificationVariable(command.notificationType, notificationName); valueId = unknownValue.endpoint(command.endpointIndex); if (ccVersion >= 2) { if (!node.valueDB.hasMetadata(valueId)) { node.valueDB.setMetadata(valueId, unknownValue.meta); } } } if (typeof command.eventParameters === "number") { const enumBehavior = valueConfig ? (0, import_NotificationCC.getNotificationEnumBehavior)(notification, valueConfig) : "extend"; const valueWithEnum = enumBehavior === "replace" ? command.eventParameters : (0, import_NotificationCC.getNotificationStateValueWithEnum)(value, command.eventParameters); node.valueDB.setValue(valueId, valueWithEnum); } else { node.valueDB.setValue(valueId, value); } if (allowIdleReset && !!node.deviceConfig?.compat?.forceNotificationIdleReset) { ctx.logNode(node.id, { message: `[handleNotificationReport] scheduling idle reset`, level: "silly" }); scheduleNotificationIdleReset(store, valueId, () => setStateIdle(value)); } } else { const unknownValue = import_cc.NotificationCCValues.unknownNotificationType(command.notificationType); const valueId = unknownValue.endpoint(command.endpointIndex); if (ccVersion >= 2) { if (!node.valueDB.hasMetadata(valueId)) { node.valueDB.setMetadata(valueId, unknownValue.meta); } } node.valueDB.setValue(valueId, command.notificationEvent); } } __name(handleNotificationReport, "handleNotificationReport"); function handleKnownNotification(ctx, node, command) { const lockEvents = /* @__PURE__ */ new Set([1, 3, 5, 9]); const unlockEvents = /* @__PURE__ */ new Set([2, 4, 6]); const doorStatusEvents = [ // Actual status 22, 23, // Synthetic status with enum (deprecated) 5632, 5633 ]; if ( // Access Control, manual/keypad/rf/auto (un)lock operation command.notificationType === 6 && (lockEvents.has(command.notificationEvent) || unlockEvents.has(command.notificationEvent)) && (node.supportsCC(import_core.CommandClasses["Door Lock"]) || node.supportsCC(import_core.CommandClasses.Lock)) ) { const isLocked = lockEvents.has(command.notificationEvent); if (node.supportsCC(import_core.CommandClasses["Door Lock"])) { node.valueDB.setValue(import_cc.DoorLockCCValues.currentMode.endpoint(command.endpointIndex), isLocked ? import_cc.DoorLockMode.Secured : import_cc.DoorLockMode.Unsecured); } if (node.supportsCC(import_core.CommandClasses.Lock)) { node.valueDB.setValue(import_cc.LockCCValues.locked.endpoint(command.endpointIndex), isLocked); } } else if (command.notificationType === 6 && doorStatusEvents.includes(command.notificationEvent)) { const isTilted = command.notificationEvent === 22 && command.eventParameters === 1; const openingStateValue = import_cc.NotificationCCValues.openingState; const openingStateValueId = openingStateValue.endpoint(command.endpointIndex); const openingStateTiltMetadata = { ...openingStateValue.meta, states: { ...openingStateValue.meta.states, [2]: "Tilted" } }; const openingStateMetadata = node.valueDB.getMetadata(openingStateValueId); if (isTilted && !openingStateMetadata?.states?.[2]) { node.valueDB.setMetadata(openingStateValueId, openingStateTiltMetadata); } node.valueDB.setValue(openingStateValueId, command.notificationEvent === 23 ? 0 : isTilted ? 2 : 1); node.valueDB.setValue(import_cc.NotificationCCValues.deprecated_doorStateSimple.endpoint(command.endpointIndex), command.notificationEvent === 23 ? 23 : 22); const tiltValue = import_cc.NotificationCCValues.deprecated_doorTiltState; const tiltValueId = tiltValue.endpoint(command.endpointIndex); let tiltValueWasCreated = node.valueDB.hasMetadata(tiltValueId); if (isTilted && !tiltValueWasCreated) { node.valueDB.setMetadata(tiltValueId, tiltValue.meta); tiltValueWasCreated = true; } if (tiltValueWasCreated) { node.valueDB.setValue(tiltValueId, isTilted ? 1 : 0); } } else if ( // Access Control, all user codes deleted command.notificationType === 6 && command.notificationEvent === 12 && node.supportsCC(import_core.CommandClasses["User Code"]) ) { const endpoint = { nodeId: node.id, index: command.endpointIndex, virtual: false }; const numUsers = import_cc.UserCodeCC.getSupportedUsersCached(ctx, endpoint) ?? 0; for (let userId = 1; userId <= numUsers; userId++) { import_cc.UserCodeCC.setUserIdStatusCached(ctx, endpoint, userId, import_cc.UserIDStatus.Available); import_cc.UserCodeCC.setUserCodeCached(ctx, endpoint, userId, ""); } } } __name(handleKnownNotification, "handleKnownNotification"); function manuallyIdleNotificationValueInternal(ctx, node, store, notification, prevValue, endpointIndex) { const valueConfig = (0, import_core.getNotificationValue)(notification, prevValue); if (!valueConfig || valueConfig.type !== "state") return; if (!valueConfig.idle) return; const notificationName = notification.name; const variableName = valueConfig.variableName; const valueId = import_cc.NotificationCCValues.notificationVariable(notificationName, variableName).endpoint(endpointIndex); if (node.valueDB.getValue(valueId) !== prevValue) return; clearNotificationIdleReset(store, valueId); extendNotificationValueMetadata(ctx, node, valueId, notification, valueConfig); node.valueDB.setValue( valueId, 0 /* idle */ ); } __name(manuallyIdleNotificationValueInternal, "manuallyIdleNotificationValueInternal"); function scheduleNotificationIdleReset(store, valueId, handler) { clearNotificationIdleReset(store, valueId); const key = (0, import_core.valueIdToString)(valueId); store.idleTimeouts.set( key, // Unref'ing long running timeouts allows to quit the application before the timeout elapses (0, import_shared.setTimer)( handler, 5 * 60 * 1e3 /* 5 minutes */ ).unref() ); } __name(scheduleNotificationIdleReset, "scheduleNotificationIdleReset"); function clearNotificationIdleReset(store, valueId) { const key = (0, import_core.valueIdToString)(valueId); if (store.idleTimeouts.has(key)) { store.idleTimeouts.get(key)?.clear(); store.idleTimeouts.delete(key); } } __name(clearNotificationIdleReset, "clearNotificationIdleReset"); function extendNotificationValueMetadata(ctx, node, valueId, notification, valueConfig) { const ccVersion = ctx.getSupportedCCVersion(import_core.CommandClasses.Notification, node.id, node.index); if (ccVersion === 2 || !node.valueDB.hasMetadata(valueId)) { const metadata = (0, import_NotificationCC.getNotificationValueMetadata)(node.valueDB.getMetadata(valueId), notification, valueConfig); node.valueDB.setMetadata(valueId, metadata); } } __name(extendNotificationValueMetadata, "extendNotificationValueMetadata"); // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { getDefaultNotificationHandlerStore, handleNotificationReport, manuallyIdleNotificationValueInternal }); //# sourceMappingURL=NotificationCC.js.map