UNPKG

inventoresed

Version:

Z-Wave driver written entirely in JavaScript/TypeScript

608 lines (521 loc) 15.4 kB
import { getEnumMemberName } from "@zwave-js/shared/safe"; import type { Duration } from "./Duration"; import { IntegerLimits } from "./Primitive"; const isIntegerRegex = /^\d+$/; /** Returns an array with the values of a numeric enum */ export function getNumericEnumValues<T extends Record<string, any>>( enumeration: T, ): readonly number[] { return Object.keys(enumeration) .filter((val) => isIntegerRegex.test(val)) .map((val) => parseInt(val, 10)); } /** Takes an enumeration and an array of values of this enumeration and returns a states record to be used as metadata */ export function enumValuesToMetadataStates<T extends Record<string, any>>( enumeration: T, values?: readonly number[], ): Record<number, string> { const ret: Record<number, string> = {}; if (values == undefined) values = getNumericEnumValues(enumeration); for (const value of values) { ret[value] = getEnumMemberName(enumeration, value); } return ret; } export type ValueType = | "number" | "boolean" | "string" | "number[]" | "boolean[]" | "string[]" | "duration" | "color" | "buffer" | "any"; /** * Defines options that can be provided when changing a value on a device via its value ID. * Each implementation will choose the options that are relevant for it, so the same options can be used everywhere. */ export interface ValueChangeOptions { /** A duration to be used for transitions like dimming lights or activating scenes. */ transitionDuration: Duration | string; /** A volume level to be used for activating a Sound Switch CC. */ volume: number; } export interface ValueMetadataAny { /** The type of the value */ type: ValueType; /** The default value */ default?: any; /** Whether the value can be read. By default all values are assumed readable */ readable: boolean; /** Whether the value can be written. By default all values are assumed writeable */ writeable: boolean; /** A description of the value */ description?: string; /** A human-readable name for the property */ label?: string; /** CC-specific information to help identify this value */ ccSpecific?: Record<string, any>; /** Options that can be provided when changing this value on a device via its value ID. */ valueChangeOptions?: readonly (keyof ValueChangeOptions)[]; } /** * Helper function to define metadata templates while checking that they satisfy a constraint. */ // TODO: Revisit this when https://github.com/microsoft/TypeScript/issues/47920 is solved const define = <TBase extends ValueMetadataAny>() => // The chained function pattern is necessary for partial application of generic types <T extends TBase>(definition: T): T => { return definition; }; const defineAny = define<ValueMetadataAny>(); export interface ValueMetadataNumeric extends ValueMetadataAny { type: "number"; /** The minimum value that can be assigned to a CC value (optional) */ min?: number; /** The maximum value that can be assigned to a CC value (optional) */ max?: number; /** When only certain values between min and max are allowed, this determines the step size */ steps?: number; /** The default value */ default?: number; /** Speaking names for numeric values */ states?: Record<number, string>; /** An optional unit for numeric values */ unit?: string; } const defineNumeric = define<ValueMetadataNumeric>(); export interface ValueMetadataBoolean extends ValueMetadataAny { type: "boolean"; /** The default value */ default?: number; } const defineBoolean = define<ValueMetadataBoolean>(); export interface ValueMetadataString extends ValueMetadataAny { type: "string" | "color"; /** The minimum length this string must have (optional) */ minLength?: number; /** The maximum length this string may have (optional) */ maxLength?: number; /** The default value */ default?: string; } const defineString = define<ValueMetadataString>(); export interface ValueMetadataBuffer extends ValueMetadataAny { type: "buffer"; /** The minimum length this buffer must have (optional) */ minLength?: number; /** The maximum length this buffer may have (optional) */ maxLength?: number; } const defineBuffer = define<ValueMetadataBuffer>(); export interface ValueMetadataDuration extends ValueMetadataAny { type: "duration"; default?: Duration; } const defineDuration = define<ValueMetadataDuration>(); /** * Defines how a configuration value is encoded */ export enum ConfigValueFormat { SignedInteger = 0x00, UnsignedInteger = 0x01, Enumerated = 0x02, // UnsignedInt, Radio Buttons BitField = 0x03, // Check Boxes } /** * @publicAPI * A configuration value is either a single number or a bit map */ export type ConfigValue = number | Set<number>; export interface ConfigurationMetadata extends ValueMetadataAny { // readable and writeable are inherited from ValueMetadataAny min?: ConfigValue; max?: ConfigValue; default?: ConfigValue; unit?: string; valueSize?: number; format?: ConfigValueFormat; name?: string; info?: string; noBulkSupport?: boolean; isAdvanced?: boolean; requiresReInclusion?: boolean; // The following information cannot be detected by scanning. // We have to rely on configuration to support them // options?: readonly ConfigOption[]; states?: Record<number, string>; allowManualEntry?: boolean; isFromConfig?: boolean; } export type ValueMetadata = | ValueMetadataAny | ValueMetadataNumeric | ValueMetadataBoolean | ValueMetadataString | ValueMetadataDuration | ValueMetadataBuffer | ConfigurationMetadata; // TODO: lists of allowed values, etc... // Mixins for value metadata const _default = defineAny({ type: "any", readable: true, writeable: true, } as const); const _readonly = { writeable: false, } as const; const _writeonly = { readable: false, } as const; /** The default value for metadata: readable and writeable */ const Any = defineAny({ ..._default, } as const); /** The default value for readonly metadata */ const ReadOnly = defineAny({ ..._default, ..._readonly, } as const); /** The default value for writeonly metadata */ const WriteOnly = defineAny({ ..._default, ..._writeonly, } as const); /** A boolean value */ const Boolean = defineBoolean({ ..._default, type: "boolean", } as const); /** A boolean value (readonly) */ const ReadOnlyBoolean = defineBoolean({ ...Boolean, ..._readonly, } as const); /** A boolean value (writeonly) */ const WriteOnlyBoolean = defineBoolean({ ...Boolean, ..._writeonly, } as const); /** Any number */ const Number = defineNumeric({ ..._default, type: "number", } as const); /** Unsigned number (readonly) */ const ReadOnlyNumber = defineNumeric({ ...Number, ..._readonly, } as const); /** Unsigned number (writeonly) */ const WriteOnlyNumber = defineNumeric({ ...Number, ..._writeonly, } as const); /** Unsigned 8-bit integer */ const UInt8 = defineNumeric({ ..._default, type: "number", ...IntegerLimits.UInt8, } as const); /** Unsigned 8-bit integer (readonly) */ const ReadOnlyUInt8 = defineNumeric({ ...UInt8, ..._readonly, } as const); /** Unsigned 8-bit integer (writeonly) */ const WriteOnlyUInt8 = defineNumeric({ ...UInt8, ..._writeonly, } as const); /** Unsigned 16-bit integer */ const UInt16 = defineNumeric({ ..._default, type: "number", ...IntegerLimits.UInt16, } as const); /** Unsigned 16-bit integer (readonly) */ const ReadOnlyUInt16 = defineNumeric({ ...UInt16, ..._readonly, } as const); /** Unsigned 16-bit integer (writeonly) */ const WriteOnlyUInt16 = defineNumeric({ ...UInt16, ..._writeonly, } as const); /** Unsigned 24-bit integer */ const UInt24 = defineNumeric({ ..._default, type: "number", ...IntegerLimits.UInt24, } as const); /** Unsigned 24-bit integer (readonly) */ const ReadOnlyUInt24 = defineNumeric({ ...UInt24, ..._readonly, } as const); /** Unsigned 24-bit integer (writeonly) */ const WriteOnlyUInt24 = defineNumeric({ ...UInt24, ..._writeonly, } as const); /** Unsigned 32-bit integer */ const UInt32 = defineNumeric({ ..._default, type: "number", ...IntegerLimits.UInt32, } as const); /** Unsigned 32-bit integer (readonly) */ const ReadOnlyUInt32 = defineNumeric({ ...UInt32, ..._readonly, } as const); /** Unsigned 32-bit integer (writeonly) */ const WriteOnlyUInt32 = defineNumeric({ ...UInt32, ..._writeonly, } as const); /** Signed 8-bit integer */ const Int8 = defineNumeric({ ..._default, type: "number", ...IntegerLimits.Int8, } as const); /** Signed 8-bit integer (readonly) */ const ReadOnlyInt8 = defineNumeric({ ...Int8, ..._readonly, } as const); /** Signed 8-bit integer (writeonly) */ const WriteOnlyInt8 = defineNumeric({ ...Int8, ..._writeonly, } as const); /** Signed 16-bit integer */ const Int16 = defineNumeric({ ..._default, type: "number", ...IntegerLimits.Int16, } as const); /** Signed 16-bit integer (readonly) */ const ReadOnlyInt16 = defineNumeric({ ...Int16, ..._readonly, } as const); /** Signed 16-bit integer (writeonly) */ const WriteOnlyInt16 = defineNumeric({ ...Int16, ..._writeonly, } as const); /** Signed 24-bit integer */ const Int24 = defineNumeric({ ..._default, type: "number", ...IntegerLimits.Int24, } as const); /** Signed 24-bit integer (readonly) */ const ReadOnlyInt24 = defineNumeric({ ...Int24, ..._readonly, } as const); /** Signed 24-bit integer (writeonly) */ const WriteOnlyInt24 = defineNumeric({ ...Int24, ..._writeonly, } as const); /** Signed 32-bit integer */ const Int32 = defineNumeric({ ..._default, type: "number", ...IntegerLimits.Int32, } as const); /** Signed 32-bit integer (readonly) */ const ReadOnlyInt32 = defineNumeric({ ...Int32, ..._readonly, } as const); /** Signed 32-bit integer (writeonly) */ const WriteOnlyInt32 = defineNumeric({ ...Int32, ..._writeonly, } as const); /** Any string */ const String = defineString({ ..._default, type: "string", } as const); /** Any string (readonly) */ const ReadOnlyString = defineString({ ...String, ..._readonly, } as const); /** Any string (writeonly) */ const WriteOnlyString = defineString({ ...String, ..._writeonly, } as const); /** A (hex) string that represents a color */ const Color = defineString({ ...String, type: "color", } as const); /** A (hex) string that represents a color (readonly) */ const ReadOnlyColor = defineString({ ...Color, ..._readonly, } as const); /** A (hex) string that represents a color (writeonly) */ const WriteOnlyColor = defineString({ ...Color, ..._writeonly, } as const); // Some predefined CC-specific metadata /** The level of a Switch */ const Level = defineNumeric({ ...UInt8, max: 99, } as const); /** The level of a Switch (readonly) */ const ReadOnlyLevel = defineNumeric({ ...Level, ..._readonly, } as const); /** The level of a Switch (writeonly) */ const WriteOnlyLevel = defineNumeric({ ...Level, ..._writeonly, } as const); /** A duration value */ const _Duration = defineDuration({ ..._default, type: "duration", } as const); /** A duration value (readonly) */ const ReadOnlyDuration = defineDuration({ ..._Duration, ..._readonly, } as const); /** A duration value (writeonly) */ const WriteOnlyDuration = defineDuration({ ..._Duration, ..._writeonly, } as const); /** A buffer */ const _Buffer = defineBuffer({ ..._default, type: "buffer", } as const); /** A buffer (readonly) */ const ReadOnlyBuffer = defineBuffer({ ..._Buffer, ..._readonly, } as const); /** A buffer (writeonly) */ const WriteOnlyBuffer = defineBuffer({ ..._Buffer, ..._writeonly, }); /** A collection of predefined CC value metadata */ export const ValueMetadata = { /** The default value for metadata: readable and writeable */ Any: Object.freeze(Any), /** The default value for readonly metadata */ ReadOnly: Object.freeze(ReadOnly), /** The default value for writeonly metadata */ WriteOnly: Object.freeze(WriteOnly), /** A numeric value */ Number: Object.freeze(Number), /** A numeric value (readonly) */ ReadOnlyNumber: Object.freeze(ReadOnlyNumber), /** A numeric value (writeonly) */ WriteOnlyNumber: Object.freeze(WriteOnlyNumber), /** Unsigned 8-bit integer */ UInt8: Object.freeze(UInt8), /** Unsigned 16-bit integer */ UInt16: Object.freeze(UInt16), /** Unsigned 24-bit integer */ UInt24: Object.freeze(UInt24), /** Unsigned 32-bit integer */ UInt32: Object.freeze(UInt32), /** Signed 8-bit integer */ Int8: Object.freeze(Int8), /** Signed 16-bit integer */ Int16: Object.freeze(Int16), /** Signed 24-bit integer */ Int24: Object.freeze(Int24), /** Signed 32-bit integer */ Int32: Object.freeze(Int32), /** Unsigned 8-bit integer (readonly) */ ReadOnlyUInt8: Object.freeze(ReadOnlyUInt8), /** Unsigned 16-bit integer (readonly) */ ReadOnlyUInt16: Object.freeze(ReadOnlyUInt16), /** Unsigned 24-bit integer (readonly) */ ReadOnlyUInt24: Object.freeze(ReadOnlyUInt24), /** Unsigned 32-bit integer (readonly) */ ReadOnlyUInt32: Object.freeze(ReadOnlyUInt32), /** Signed 8-bit integer (readonly) */ ReadOnlyInt8: Object.freeze(ReadOnlyInt8), /** Signed 16-bit integer (readonly) */ ReadOnlyInt16: Object.freeze(ReadOnlyInt16), /** Signed 24-bit integer (readonly) */ ReadOnlyInt24: Object.freeze(ReadOnlyInt24), /** Signed 32-bit integer (readonly) */ ReadOnlyInt32: Object.freeze(ReadOnlyInt32), /** Unsigned 8-bit integer (writeonly) */ WriteOnlyUInt8: Object.freeze(WriteOnlyUInt8), /** Unsigned 16-bit integer (writeonly) */ WriteOnlyUInt16: Object.freeze(WriteOnlyUInt16), /** Unsigned 24-bit integer (writeonly) */ WriteOnlyUInt24: Object.freeze(WriteOnlyUInt24), /** Unsigned 32-bit integer (writeonly) */ WriteOnlyUInt32: Object.freeze(WriteOnlyUInt32), /** Signed 8-bit integer (writeonly) */ WriteOnlyInt8: Object.freeze(WriteOnlyInt8), /** Signed 16-bit integer (writeonly) */ WriteOnlyInt16: Object.freeze(WriteOnlyInt16), /** Signed 24-bit integer (writeonly) */ WriteOnlyInt24: Object.freeze(WriteOnlyInt24), /** Signed 32-bit integer (writeonly) */ WriteOnlyInt32: Object.freeze(WriteOnlyInt32), /** The level of a Switch (0-99) */ Level: Object.freeze(Level), /** The level of a Switch (0-99, readonly) */ ReadOnlyLevel: Object.freeze(ReadOnlyLevel), /** The level of a Switch (0-99, writeonly) */ WriteOnlyLevel: Object.freeze(WriteOnlyLevel), /** A boolean value */ Boolean: Object.freeze(Boolean), /** A boolean value (readonly) */ ReadOnlyBoolean: Object.freeze(ReadOnlyBoolean), /** A boolean value (writeonly) */ WriteOnlyBoolean: Object.freeze(WriteOnlyBoolean), /** A string */ String: Object.freeze(String), /** A string (readonly) */ ReadOnlyString: Object.freeze(ReadOnlyString), /** A string (writeonly) */ WriteOnlyString: Object.freeze(WriteOnlyString), /** A (hex) string that represents a color */ Color: Object.freeze(Color), /** A (hex) string that represents a color (readonly) */ ReadOnlyColor: Object.freeze(ReadOnlyColor), /** A (hex) string that represents a color (writeonly) */ WriteOnlyColor: Object.freeze(WriteOnlyColor), /** A duration value */ Duration: Object.freeze(_Duration), /** A duration value (readonly) */ ReadOnlyDuration: Object.freeze(ReadOnlyDuration), /** A duration value (writeonly) */ WriteOnlyDuration: Object.freeze(WriteOnlyDuration), /** A buffer */ Buffer: Object.freeze(_Buffer), /** A buffer (readonly) */ ReadOnlyBuffer: Object.freeze(ReadOnlyBuffer), /** A buffer (writeonly) */ WriteOnlyBuffer: Object.freeze(WriteOnlyBuffer), };