UNPKG

zwave-js

Version:

Z-Wave driver written entirely in JavaScript/TypeScript

146 lines 7.5 kB
import { BasicCCReport, BasicCCSet, BasicCCValues, } from "@zwave-js/cc"; import { CommandClasses, EncapsulationFlags, ZWaveError, ZWaveErrorCodes, } from "@zwave-js/core"; /** * Returns the CC that Basic Set/Report commands should be mapped to * based on the endpoint's device class, or undefined if no mapping exists. */ export function getBasicMappingTarget(deviceClass) { switch (deviceClass?.generic.key) { case 0x20: // Binary Sensor return CommandClasses["Binary Sensor"]; case 0x10: // Binary Switch return CommandClasses["Binary Switch"]; case 0x11: // Multilevel Switch return CommandClasses["Multilevel Switch"]; case 0x12: // Remote Switch switch (deviceClass.specific.key) { case 0x01: // Binary Remote Switch return CommandClasses["Binary Switch"]; case 0x02: // Multilevel Remote Switch return CommandClasses["Multilevel Switch"]; } } } /** Handles the receipt of a BasicCC Set or Report */ export function handleBasicCommand(ctx, node, command) { // Retrieve the endpoint the command is coming from const sourceEndpoint = node.getEndpoint(command.endpointIndex ?? 0) ?? node; // Depending on the generic device class, we may need to map the basic command to other CCs const mappedTargetCCId = getBasicMappingTarget(sourceEndpoint.deviceClass); let mappedTargetCC; if (mappedTargetCCId != undefined) { mappedTargetCC = sourceEndpoint.createCCInstanceUnsafe(mappedTargetCCId); } if (command instanceof BasicCCReport) { // By default, map Basic CC Reports to a more appropriate CC, unless stated otherwise in a config file const basicReportMapping = node.deviceConfig?.compat?.mapBasicReport ?? "auto"; if (basicReportMapping === "Binary Sensor") { // Treat the command as a BinarySensorCC Report, regardless of the device class mappedTargetCC = sourceEndpoint.createCCInstanceUnsafe(CommandClasses["Binary Sensor"]); if (typeof command.currentValue === "number") { if (mappedTargetCC) { ctx.logNode(node.id, { endpoint: command.endpointIndex, message: "treating BasicCC::Report as a BinarySensorCC::Report", }); mappedTargetCC.setMappedBasicValue(ctx, command.currentValue); } else { ctx.logNode(node.id, { endpoint: command.endpointIndex, message: "cannot treat BasicCC::Report as a BinarySensorCC::Report, because the Binary Sensor CC is not supported", level: "warn", }); } } else { ctx.logNode(node.id, { endpoint: command.endpointIndex, message: "cannot map BasicCC::Report to a different CC, because the current value is unknown", level: "warn", }); } } else if (basicReportMapping === "auto" || basicReportMapping === false) { // Try to set the mapped value on the target CC const didSetMappedValue = typeof command.currentValue === "number" // ... unless forbidden && basicReportMapping === "auto" && mappedTargetCC?.setMappedBasicValue(ctx, command.currentValue); // Otherwise fall back to setting it ourselves if (!didSetMappedValue) { // Store the value in the value DB now command.persistValues(ctx); } } } else if (command instanceof BasicCCSet) { // By default, map Basic CC Set to Basic CC Report, unless stated otherwise in a config file const basicSetMapping = node.deviceConfig?.compat?.mapBasicSet ?? "report"; if (basicSetMapping === "event") { // Treat BasicCCSet as value events if desired ctx.logNode(node.id, { endpoint: command.endpointIndex, message: "treating BasicCC::Set as a value event", }); node.valueDB.setValue(BasicCCValues.compatEvent.endpoint(command.endpointIndex), command.targetValue, { stateful: false, }); } else if (basicSetMapping === "Binary Sensor") { // Treat the Set command as a BinarySensorCC Report, regardless of the device class mappedTargetCC = sourceEndpoint.createCCInstanceUnsafe(CommandClasses["Binary Sensor"]); if (mappedTargetCC) { ctx.logNode(node.id, { endpoint: command.endpointIndex, message: "treating BasicCC::Set as a BinarySensorCC::Report", }); mappedTargetCC.setMappedBasicValue(ctx, command.targetValue); } else { ctx.logNode(node.id, { endpoint: command.endpointIndex, message: "cannot treat BasicCC::Set as a BinarySensorCC::Report, because the Binary Sensor CC is not supported", level: "warn", }); } } else if (!node.deviceConfig?.compat?.mapBasicSet && !!(command.encapsulationFlags & EncapsulationFlags.Supervision)) { // A controller MUST not support Basic CC per the specifications. While we can interpret its contents, // we MUST respond to supervised Basic CC Set with "no support". // All known devices that use BasicCCSet for reporting send it unsupervised, so this should be safe to do. if (command.encapsulationFlags & EncapsulationFlags.Supervision) { throw new ZWaveError("Basic CC is not supported", ZWaveErrorCodes.CC_NotSupported); } } else if (basicSetMapping === "auto" || basicSetMapping === "report") { // Some devices send their current state using BasicCCSet to their associations // instead of using reports. We still interpret them like reports ctx.logNode(node.id, { endpoint: command.endpointIndex, message: "treating BasicCC::Set as a report", }); // In "auto" mode, try to set the mapped value on the target CC first const didSetMappedValue = basicSetMapping === "auto" && !!mappedTargetCC?.setMappedBasicValue(ctx, command.targetValue); // Otherwise handle the command ourselves if (!didSetMappedValue) { // Basic Set commands cannot store their value automatically, so store the values manually node.valueDB.setValue(BasicCCValues.currentValue.endpoint(command.endpointIndex), command.targetValue); // Since the node sent us a Basic Set, we are sure that it is at least controlled // Add it to the support list, so the information lands in the network cache if (!sourceEndpoint.controlsCC(CommandClasses.Basic)) { sourceEndpoint.addCC(CommandClasses.Basic, { isControlled: true, }); } } } } } //# sourceMappingURL=BasicCC.js.map