UNPKG

inventoresed

Version:

Z-Wave driver written entirely in JavaScript/TypeScript

260 lines (225 loc) 9.11 kB
import { padStart } from "alcalzone-shared/strings"; /** * Used to identify errors from this library without relying on the specific wording of the error message */ export enum ZWaveErrorCodes { PacketFormat_Truncated, PacketFormat_Invalid, PacketFormat_Checksum, // This differs from the above three. It means that the packet has a valid format and checksum, // but the data does not match the expectations. This error does not reset the Z-Wave stack PacketFormat_InvalidPayload, PacketFormat_DecryptionFailed, /** The driver failed to start */ Driver_Failed = 100, Driver_Reset, Driver_Destroyed, Driver_NotReady, Driver_InvalidDataReceived, Driver_NotSupported, Driver_NoPriority, Driver_InvalidCache, Driver_InvalidOptions, /** The driver tried to do something that requires security */ Driver_NoSecurity, Driver_NoErrorHandler, Driver_FeatureDisabled, /** There was a timeout while waiting for a message from the controller */ Controller_Timeout = 200, /** There was a timeout while waiting for a response from a node */ Controller_NodeTimeout, Controller_MessageDropped, Controller_ResponseNOK, Controller_CallbackNOK, Controller_InclusionFailed, Controller_ExclusionFailed, /** Tried to do something the controller does not support */ Controller_NotSupported, /** The interview for this node was restarted by the user */ Controller_InterviewRestarted, /** The node with the given node ID was not found */ Controller_NodeNotFound, /** The endpoint with the given index was not found on the node */ Controller_EndpointNotFound, /** The node was removed from the network */ Controller_NodeRemoved, /** Communication with the node will be insecure (no security configured) */ Controller_NodeInsecureCommunication, /** The message has expired (the given timeout has elapsed) */ Controller_MessageExpired, /** A Serial API command resulted in an error response */ Controller_CommandError, /** Could not fetch some information to determine firmware upgrades from a node */ FWUpdateService_MissingInformation = 260, /** Any error related to HTTP requests during firmware update communication */ FWUpdateService_RequestError, /** The integrity check of the downloaded firmware update failed */ FWUpdateService_IntegrityCheckFailed, /** The given NVM version/format is unsupported */ NVM_NotSupported = 280, /** Could not parse the JSON representation of an NVM due to invalid data */ NVM_InvalidJSON, /** A required NVM3 object was not found while deserializing the NVM */ NVM_ObjectNotFound, /** The parsed NVM or NVM content has an invalid format */ NVM_InvalidFormat, /** Not enough space in the NVM */ NVM_NoSpace, CC_Invalid = 300, CC_NoNodeID, CC_NotSupported, CC_NotImplemented, CC_NoAPI, Deserialization_NotImplemented = 320, Arithmetic, Argument_Invalid, Config_Invalid = 340, Config_NotFound, /** A compound config file has circular imports */ Config_CircularImport, /** Failed to download the npm registry info for config updates */ Config_Update_RegistryError, /** Could not detect which package manager to use for updates */ Config_Update_PackageManagerNotFound, /** Installing the configuration update failed */ Config_Update_InstallFailed, // Here follow message specific errors /** The removal process could not be started or completed due to one or several reasons */ RemoveFailedNode_Failed = 360, /** The removal process was aborted because the node has responded */ RemoveFailedNode_NodeOK, /** The replace process could not be started or completed due to one or several reasons */ ReplaceFailedNode_Failed, /** The replace process was aborted because the node has responded */ ReplaceFailedNode_NodeOK, // Here follow CC specific errors /** * Used to report the first existing parameter number * available in a node's configuration */ ConfigurationCC_FirstParameterNumber = 1000, /** * Used to report that a V3+ node should not have its parameters scanned with get/set commands */ ConfigurationCC_NoLegacyScanOnNewDevices, /** * Used to report that a node using V3 or less MUST not use the resetToDefault flag */ ConfigurationCC_NoResetToDefaultOnLegacyDevices, /** * Used to report that the command was not executed by the target node */ SupervisionCC_CommandFailed = 1100, /** * Used to report that a ManufacturerProprietaryCC could not be instantiated * because of a missing manufacturer ID. */ ManufacturerProprietaryCC_NoManufacturerId = 1200, /** * Used to report that an invalid group ID was used to address a (Multi Channel) Association */ AssociationCC_InvalidGroup = 1300, /** Cannot add an association because it is not allowed */ AssociationCC_NotAllowed, /** Used to report that no nonce exists */ SecurityCC_NoNonce = 1400, /** Used to report that no SPAN is established between the nodes yet. The context should be an object that contains the peer node ID */ Security2CC_NoSPAN, /** Used to report that the inner state required for this action was not initialized */ Security2CC_NotInitialized, /** Used to report that secure communication with a node is not possible because the node is not secure */ Security2CC_NotSecure, /** Gets thrown when a Security S2 command is missing a required extension */ Security2CC_MissingExtension, /** Gets thrown when a Security S2 encapsulated command cannot be decoded by the target node */ Security2CC_CannotDecode, /** Gets thrown when parsing an invalid QR code */ Security2CC_InvalidQRCode, /** The firmware update process is already active */ FirmwareUpdateCC_Busy = 1500, /** The selected firmware target is not upgradable */ FirmwareUpdateCC_NotUpgradable, /** The selected firmware target does not exist */ FirmwareUpdateCC_TargetNotFound, /** The node reported that it could not start the update */ FirmwareUpdateCC_FailedToStart, /** The node did not confirm the aborted update */ FirmwareUpdateCC_FailedToAbort, /** The node did not confirm the completed update or the process stalled for too long */ FirmwareUpdateCC_Timeout, /** An invalid firmware file was provided that cannot be handled by this library */ Invalid_Firmware_File, /** An firmware file with an unsupported format was provided */ Unsupported_Firmware_Format, /** Unsupported target node for a powerlevel test */ PowerlevelCC_UnsupportedTestNode = 1600, } export function getErrorSuffix(code: ZWaveErrorCodes): string { return `ZW${padStart(code.toString(), 4, "0")}`; } function appendErrorSuffix(message: string, code: ZWaveErrorCodes): string { const suffix = ` (${getErrorSuffix(code)})`; if (!message.endsWith(suffix)) message += suffix; return message; } /** * Errors thrown in this library are of this type. The `code` property identifies what went wrong. */ export class ZWaveError extends Error { public constructor( public readonly message: string, public readonly code: ZWaveErrorCodes, /** Additional info required to handle this error (e.g. the Z-Wave message indicating the failure) */ public readonly context?: unknown, /** If this error corresponds to a failed transaction, this contains the stack where it was created */ public readonly transactionSource?: string, ) { super(); // Add the error code to the message to be able to identify it even when the stack trace is garbled somehow this.message = appendErrorSuffix(message, code); // We need to set the prototype explicitly Object.setPrototypeOf(this, ZWaveError.prototype); Object.getPrototypeOf(this).name = "ZWaveError"; // If there's a better stack, use it if (typeof transactionSource === "string") { this.stack = `ZWaveError: ${this.message}\n${transactionSource}`; } } } export function isZWaveError(e: unknown): e is ZWaveError { return e instanceof Error && Object.getPrototypeOf(e).name === "ZWaveError"; } export function isTransmissionError(e: unknown): e is ZWaveError & { code: | ZWaveErrorCodes.Controller_Timeout | ZWaveErrorCodes.Controller_MessageDropped | ZWaveErrorCodes.Controller_CallbackNOK | ZWaveErrorCodes.Controller_ResponseNOK | ZWaveErrorCodes.Controller_NodeTimeout | ZWaveErrorCodes.Security2CC_CannotDecode; } { return ( isZWaveError(e) && (e.code === ZWaveErrorCodes.Controller_Timeout || e.code === ZWaveErrorCodes.Controller_MessageDropped || e.code === ZWaveErrorCodes.Controller_CallbackNOK || e.code === ZWaveErrorCodes.Controller_ResponseNOK || e.code === ZWaveErrorCodes.Controller_NodeTimeout || e.code === ZWaveErrorCodes.Security2CC_CannotDecode) ); } /** * Tests is the given error is a "recoverable" error - i.e. something that shouldn't happen unless * someone interacted with zwave-js in a weird way, but something we can deal with. * * This explicitly does not include transmission errors. */ export function isRecoverableZWaveError(e: unknown): e is ZWaveError { if (!isZWaveError(e)) return false; switch (e.code) { case ZWaveErrorCodes.Controller_InterviewRestarted: case ZWaveErrorCodes.Controller_NodeRemoved: return true; } return false; }