UNPKG

hap-nodejs

Version:

HAP-NodeJS is a Node.js implementation of HomeKit Accessory Server.

1,623 lines (1,622 loc) 87.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Characteristic = exports.CharacteristicEventTypes = exports.ChangeReason = exports.Access = exports.Perms = exports.Units = exports.Formats = void 0; const tslib_1 = require("tslib"); const assert_1 = tslib_1.__importDefault(require("assert")); const debug_1 = tslib_1.__importDefault(require("debug")); const events_1 = require("events"); const HAPServer_1 = require("./HAPServer"); const clone_1 = require("./util/clone"); const hapStatusError_1 = require("./util/hapStatusError"); const once_1 = require("./util/once"); const request_util_1 = require("./util/request-util"); const uuid_1 = require("./util/uuid"); const checkName_1 = require("./util/checkName"); const debug = (0, debug_1.default)("HAP-NodeJS:Characteristic"); /** * @group Characteristic */ var Formats; (function (Formats) { Formats["BOOL"] = "bool"; /** * Signed 32-bit integer */ Formats["INT"] = "int"; /** * Signed 64-bit floating point */ Formats["FLOAT"] = "float"; /** * String encoded in utf8 */ Formats["STRING"] = "string"; /** * Unsigned 8-bit integer. */ Formats["UINT8"] = "uint8"; /** * Unsigned 16-bit integer. */ Formats["UINT16"] = "uint16"; /** * Unsigned 32-bit integer. */ Formats["UINT32"] = "uint32"; /** * Unsigned 64-bit integer. */ Formats["UINT64"] = "uint64"; /** * Data is base64 encoded string. */ Formats["DATA"] = "data"; /** * Base64 encoded tlv8 string. */ Formats["TLV8"] = "tlv8"; })(Formats || (exports.Formats = Formats = {})); /** * @group Characteristic */ var Units; (function (Units) { /** * Celsius is the only temperature unit in the HomeKit Accessory Protocol. * Unit conversion is always done on the client side e.g. on the iPhone in the Home App depending on * the configured unit on the device itself. */ Units["CELSIUS"] = "celsius"; Units["PERCENTAGE"] = "percentage"; Units["ARC_DEGREE"] = "arcdegrees"; Units["LUX"] = "lux"; Units["SECONDS"] = "seconds"; })(Units || (exports.Units = Units = {})); /** * @group Characteristic */ var Perms; (function (Perms) { // eslint-disable-next-line @typescript-eslint/no-duplicate-enum-values Perms["PAIRED_READ"] = "pr"; // eslint-disable-next-line @typescript-eslint/no-duplicate-enum-values Perms["PAIRED_WRITE"] = "pw"; Perms["NOTIFY"] = "ev"; // eslint-disable-next-line @typescript-eslint/no-duplicate-enum-values Perms["EVENTS"] = "ev"; Perms["ADDITIONAL_AUTHORIZATION"] = "aa"; Perms["TIMED_WRITE"] = "tw"; Perms["HIDDEN"] = "hd"; Perms["WRITE_RESPONSE"] = "wr"; })(Perms || (exports.Perms = Perms = {})); /** * Describes the abstract access to a {@link Characteristic}. * It abstracts the more granular access described by {@link Perms}. * * It is used in {@link CharacteristicProps.adminOnlyAccess}. * * @group Characteristic */ var Access; (function (Access) { Access[Access["READ"] = 0] = "READ"; Access[Access["WRITE"] = 1] = "WRITE"; Access[Access["NOTIFY"] = 2] = "NOTIFY"; })(Access || (exports.Access = Access = {})); /** * @group Characteristic */ var ChangeReason; (function (ChangeReason) { /** * Reason used when HomeKit writes a value or the API user calls {@link Characteristic.setValue}. */ ChangeReason["WRITE"] = "write"; /** * Reason used when the API user calls the method {@link Characteristic.updateValue}. */ ChangeReason["UPDATE"] = "update"; /** * Used when HomeKit reads a value or the API user calls the deprecated method `Characteristic.getValue`. */ ChangeReason["READ"] = "read"; /** * Used when call to {@link Characteristic.sendEventNotification} was made. */ ChangeReason["EVENT"] = "event"; })(ChangeReason || (exports.ChangeReason = ChangeReason = {})); /** * @group Characteristic */ var CharacteristicEventTypes; (function (CharacteristicEventTypes) { /** * This event is thrown when a HomeKit controller wants to read the current value of the characteristic. * The event handler should call the supplied callback as fast as possible. * * HAP-NodeJS will complain about slow running get handlers after 3 seconds and terminate the request after 10 seconds. */ CharacteristicEventTypes["GET"] = "get"; /** * This event is thrown when a HomeKit controller wants to write a new value to the characteristic. * The event handler should call the supplied callback as fast as possible. * * HAP-NodeJS will complain about slow running set handlers after 3 seconds and terminate the request after 10 seconds. */ CharacteristicEventTypes["SET"] = "set"; /** * Emitted after a new value is set for the characteristic. * The new value can be set via a request by a HomeKit controller or via an API call. */ CharacteristicEventTypes["CHANGE"] = "change"; /** * @private */ CharacteristicEventTypes["SUBSCRIBE"] = "subscribe"; /** * @private */ CharacteristicEventTypes["UNSUBSCRIBE"] = "unsubscribe"; /** * @private */ CharacteristicEventTypes["CHARACTERISTIC_WARNING"] = "characteristic-warning"; })(CharacteristicEventTypes || (exports.CharacteristicEventTypes = CharacteristicEventTypes = {})); /** * @group Characteristic */ class ValidValuesIterable { props; constructor(props) { (0, assert_1.default)((0, request_util_1.isNumericFormat)(props.format), "Cannot instantiate valid values iterable when format is not numeric. Found " + props.format); this.props = props; } *[Symbol.iterator]() { if (this.props.validValues) { for (const value of this.props.validValues) { yield value; } } else { let min = 0; // default is zero for all the uint types let max; let stepValue = 1; if (this.props.validValueRanges) { min = this.props.validValueRanges[0]; max = this.props.validValueRanges[1]; } else if (this.props.minValue != null && this.props.maxValue != null) { min = this.props.minValue; max = this.props.maxValue; if (this.props.minStep != null) { stepValue = this.props.minStep; } } else if ((0, request_util_1.isUnsignedNumericFormat)(this.props.format)) { max = (0, request_util_1.numericUpperBound)(this.props.format); } else { throw new Error("Could not find valid iterator strategy for props: " + JSON.stringify(this.props)); } for (let i = min; i <= max; i += stepValue) { yield i; } } } } const numberPattern = /^-?\d+$/; function extractHAPStatusFromError(error) { let errorValue = -70402 /* HAPStatus.SERVICE_COMMUNICATION_FAILURE */; if (numberPattern.test(error.message)) { const value = parseInt(error.message, 10); if ((0, HAPServer_1.IsKnownHAPStatusError)(value)) { errorValue = value; } } return errorValue; } function maxWithUndefined(a, b) { if (a == null) { return b; } else if (b == null) { return a; } else { return Math.max(a, b); } } function minWithUndefined(a, b) { if (a == null) { return b; } else if (b == null) { return a; } else { return Math.min(a, b); } } /** * Characteristic represents a particular typed variable that can be assigned to a Service. For instance, a * "Hue" Characteristic might store a 'float' value of type 'arcdegrees'. You could add the Hue Characteristic * to a {@link Service} in order to store that value. A particular Characteristic is distinguished from others by its * UUID. HomeKit provides a set of known Characteristic UUIDs defined in HomeKit.ts along with a * corresponding concrete subclass. * * You can also define custom Characteristics by providing your own UUID. Custom Characteristics can be added * to any native or custom Services, but Siri will likely not be able to work with these. * * @group Characteristic */ // eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging class Characteristic extends events_1.EventEmitter { // Pattern below is for automatic detection of the section of defined characteristics. Used by the generator // -=-=-=-=-=-=-=-=-=-=-=-=-=-=- /** * @group Characteristic Definitions */ static AccessCodeControlPoint; /** * @group Characteristic Definitions */ static AccessCodeSupportedConfiguration; /** * @group Characteristic Definitions */ static AccessControlLevel; /** * @group Characteristic Definitions */ static AccessoryFlags; /** * @group Characteristic Definitions */ static AccessoryIdentifier; /** * @group Characteristic Definitions */ static Active; /** * @group Characteristic Definitions */ static ActiveIdentifier; /** * @group Characteristic Definitions */ static ActivityInterval; /** * @group Characteristic Definitions */ static AdministratorOnlyAccess; /** * @group Characteristic Definitions */ static AirParticulateDensity; /** * @group Characteristic Definitions */ static AirParticulateSize; /** * @group Characteristic Definitions */ static AirPlayEnable; /** * @group Characteristic Definitions */ static AirQuality; /** * @group Characteristic Definitions */ static AppMatchingIdentifier; /** * @group Characteristic Definitions */ static AssetUpdateReadiness; /** * @group Characteristic Definitions */ static AudioFeedback; /** * @group Characteristic Definitions */ static BatteryLevel; /** * @group Characteristic Definitions */ static Brightness; /** * @group Characteristic Definitions */ static ButtonEvent; /** * @group Characteristic Definitions */ static CameraOperatingModeIndicator; /** * @group Characteristic Definitions */ static CarbonDioxideDetected; /** * @group Characteristic Definitions */ static CarbonDioxideLevel; /** * @group Characteristic Definitions */ static CarbonDioxidePeakLevel; /** * @group Characteristic Definitions */ static CarbonMonoxideDetected; /** * @group Characteristic Definitions */ static CarbonMonoxideLevel; /** * @group Characteristic Definitions */ static CarbonMonoxidePeakLevel; /** * @group Characteristic Definitions */ static CCAEnergyDetectThreshold; /** * @group Characteristic Definitions */ static CCASignalDetectThreshold; /** * @group Characteristic Definitions */ static CharacteristicValueActiveTransitionCount; /** * @group Characteristic Definitions */ static CharacteristicValueTransitionControl; /** * @group Characteristic Definitions */ static ChargingState; /** * @group Characteristic Definitions */ static ClosedCaptions; /** * @group Characteristic Definitions */ static ColorTemperature; /** * @group Characteristic Definitions */ static ConfigurationState; /** * @group Characteristic Definitions */ static ConfiguredName; /** * @group Characteristic Definitions */ static ContactSensorState; /** * @group Characteristic Definitions */ static CoolingThresholdTemperature; /** * @group Characteristic Definitions */ static CryptoHash; /** * @group Characteristic Definitions */ static CurrentAirPurifierState; /** * @group Characteristic Definitions */ static CurrentAmbientLightLevel; /** * @group Characteristic Definitions */ static CurrentDoorState; /** * @group Characteristic Definitions */ static CurrentFanState; /** * @group Characteristic Definitions */ static CurrentHeaterCoolerState; /** * @group Characteristic Definitions */ static CurrentHeatingCoolingState; /** * @group Characteristic Definitions */ static CurrentHorizontalTiltAngle; /** * @group Characteristic Definitions */ static CurrentHumidifierDehumidifierState; /** * @group Characteristic Definitions */ static CurrentMediaState; /** * @group Characteristic Definitions */ static CurrentPosition; /** * @group Characteristic Definitions */ static CurrentRelativeHumidity; /** * @group Characteristic Definitions */ static CurrentSlatState; /** * @group Characteristic Definitions */ static CurrentTemperature; /** * @group Characteristic Definitions */ static CurrentTiltAngle; /** * @group Characteristic Definitions */ static CurrentTransport; /** * @group Characteristic Definitions */ static CurrentVerticalTiltAngle; /** * @group Characteristic Definitions */ static CurrentVisibilityState; /** * @group Characteristic Definitions */ static DataStreamHAPTransport; /** * @group Characteristic Definitions */ static DataStreamHAPTransportInterrupt; /** * @group Characteristic Definitions */ static DiagonalFieldOfView; /** * @group Characteristic Definitions */ static DigitalZoom; /** * @group Characteristic Definitions */ static DisplayOrder; /** * @group Characteristic Definitions */ static EventRetransmissionMaximum; /** * @group Characteristic Definitions */ static EventSnapshotsActive; /** * @group Characteristic Definitions */ static EventTransmissionCounters; /** * @group Characteristic Definitions */ static FilterChangeIndication; /** * @group Characteristic Definitions */ static FilterLifeLevel; /** * @group Characteristic Definitions */ static FirmwareRevision; /** * @group Characteristic Definitions */ static FirmwareUpdateReadiness; /** * @group Characteristic Definitions */ static FirmwareUpdateStatus; /** * @group Characteristic Definitions */ static HardwareFinish; /** * @group Characteristic Definitions */ static HardwareRevision; /** * @group Characteristic Definitions */ static HeartBeat; /** * @group Characteristic Definitions */ static HeatingThresholdTemperature; /** * @group Characteristic Definitions */ static HoldPosition; /** * @group Characteristic Definitions */ static HomeKitCameraActive; /** * @group Characteristic Definitions */ static Hue; /** * @group Characteristic Definitions */ static Identifier; /** * @group Characteristic Definitions */ static Identify; /** * @group Characteristic Definitions */ static ImageMirroring; /** * @group Characteristic Definitions */ static ImageRotation; /** * @group Characteristic Definitions */ static InputDeviceType; /** * @group Characteristic Definitions */ static InputSourceType; /** * @group Characteristic Definitions */ static InUse; /** * @group Characteristic Definitions */ static IsConfigured; /** * @group Characteristic Definitions */ static LeakDetected; /** * @group Characteristic Definitions */ static ListPairings; /** * @group Characteristic Definitions */ static LockControlPoint; /** * @group Characteristic Definitions */ static LockCurrentState; /** * @group Characteristic Definitions */ static LockLastKnownAction; /** * @group Characteristic Definitions */ static LockManagementAutoSecurityTimeout; /** * @group Characteristic Definitions */ static LockPhysicalControls; /** * @group Characteristic Definitions */ static LockTargetState; /** * @group Characteristic Definitions */ static Logs; /** * @group Characteristic Definitions */ static MACRetransmissionMaximum; /** * @group Characteristic Definitions */ static MACTransmissionCounters; /** * @group Characteristic Definitions */ static ManagedNetworkEnable; /** * @group Characteristic Definitions */ static ManuallyDisabled; /** * @group Characteristic Definitions */ static Manufacturer; /** * @group Characteristic Definitions */ static MaximumTransmitPower; /** * @group Characteristic Definitions */ static MetricsBufferFullState; /** * @group Characteristic Definitions */ static Model; /** * @group Characteristic Definitions */ static MotionDetected; /** * @group Characteristic Definitions */ static MultifunctionButton; /** * @group Characteristic Definitions */ static Mute; /** * @group Characteristic Definitions */ static Name; /** * @group Characteristic Definitions */ static NetworkAccessViolationControl; /** * @group Characteristic Definitions */ static NetworkClientProfileControl; /** * @group Characteristic Definitions */ static NetworkClientStatusControl; /** * @group Characteristic Definitions */ static NFCAccessControlPoint; /** * @group Characteristic Definitions */ static NFCAccessSupportedConfiguration; /** * @group Characteristic Definitions */ static NightVision; /** * @group Characteristic Definitions */ static NitrogenDioxideDensity; /** * @group Characteristic Definitions */ static ObstructionDetected; /** * @group Characteristic Definitions */ static OccupancyDetected; /** * @group Characteristic Definitions */ static On; /** * @group Characteristic Definitions */ static OperatingStateResponse; /** * @group Characteristic Definitions */ static OpticalZoom; /** * @group Characteristic Definitions */ static OutletInUse; /** * @group Characteristic Definitions */ static OzoneDensity; /** * @group Characteristic Definitions */ static PairingFeatures; /** * @group Characteristic Definitions */ static PairSetup; /** * @group Characteristic Definitions */ static PairVerify; /** * @group Characteristic Definitions */ static PasswordSetting; /** * @group Characteristic Definitions */ static PeriodicSnapshotsActive; /** * @group Characteristic Definitions */ static PictureMode; /** * @group Characteristic Definitions */ static Ping; /** * @group Characteristic Definitions */ static PM10Density; /** * @group Characteristic Definitions */ static PM2_5Density; /** * @group Characteristic Definitions */ static PositionState; /** * @group Characteristic Definitions */ static PowerModeSelection; /** * @group Characteristic Definitions */ static ProductData; /** * @group Characteristic Definitions */ static ProgrammableSwitchEvent; /** * @group Characteristic Definitions */ static ProgrammableSwitchOutputState; /** * @group Characteristic Definitions */ static ProgramMode; /** * @group Characteristic Definitions */ static ReceivedSignalStrengthIndication; /** * @group Characteristic Definitions */ static ReceiverSensitivity; /** * @group Characteristic Definitions */ static RecordingAudioActive; /** * @group Characteristic Definitions */ static RelativeHumidityDehumidifierThreshold; /** * @group Characteristic Definitions */ static RelativeHumidityHumidifierThreshold; /** * @group Characteristic Definitions */ static RelayControlPoint; /** * @group Characteristic Definitions */ static RelayEnabled; /** * @group Characteristic Definitions */ static RelayState; /** * @group Characteristic Definitions */ static RemainingDuration; /** * @group Characteristic Definitions */ static RemoteKey; /** * @group Characteristic Definitions */ static ResetFilterIndication; /** * @group Characteristic Definitions */ static RotationDirection; /** * @group Characteristic Definitions */ static RotationSpeed; /** * @group Characteristic Definitions */ static RouterStatus; /** * @group Characteristic Definitions */ static Saturation; /** * @group Characteristic Definitions */ static SecuritySystemAlarmType; /** * @group Characteristic Definitions */ static SecuritySystemCurrentState; /** * @group Characteristic Definitions */ static SecuritySystemTargetState; /** * @group Characteristic Definitions */ static SelectedAudioStreamConfiguration; /** * @group Characteristic Definitions */ static SelectedCameraRecordingConfiguration; /** * @group Characteristic Definitions */ static SelectedDiagnosticsModes; /** * @group Characteristic Definitions */ static SelectedRTPStreamConfiguration; /** * @group Characteristic Definitions */ static SelectedSleepConfiguration; /** * @group Characteristic Definitions */ static SerialNumber; /** * @group Characteristic Definitions */ static ServiceLabelIndex; /** * @group Characteristic Definitions */ static ServiceLabelNamespace; /** * @group Characteristic Definitions */ static SetDuration; /** * @group Characteristic Definitions */ static SetupDataStreamTransport; /** * @group Characteristic Definitions */ static SetupEndpoints; /** * @group Characteristic Definitions */ static SetupTransferTransport; /** * @group Characteristic Definitions */ static SignalToNoiseRatio; /** * @group Characteristic Definitions */ static SiriEnable; /** * @group Characteristic Definitions */ static SiriEndpointSessionStatus; /** * @group Characteristic Definitions */ static SiriEngineVersion; /** * @group Characteristic Definitions */ static SiriInputType; /** * @group Characteristic Definitions */ static SiriLightOnUse; /** * @group Characteristic Definitions */ static SiriListening; /** * @group Characteristic Definitions */ static SiriTouchToUse; /** * @group Characteristic Definitions */ static SlatType; /** * @group Characteristic Definitions */ static SleepDiscoveryMode; /** * @group Characteristic Definitions */ static SleepInterval; /** * @group Characteristic Definitions */ static SmokeDetected; /** * @group Characteristic Definitions */ static SoftwareRevision; /** * @group Characteristic Definitions */ static StagedFirmwareVersion; /** * @group Characteristic Definitions */ static StatusActive; /** * @group Characteristic Definitions */ static StatusFault; /** * @group Characteristic Definitions */ static StatusJammed; /** * @group Characteristic Definitions */ static StatusLowBattery; /** * @group Characteristic Definitions */ static StatusTampered; /** * @group Characteristic Definitions */ static StreamingStatus; /** * @group Characteristic Definitions */ static SulphurDioxideDensity; /** * @group Characteristic Definitions */ static SupportedAssetTypes; /** * @group Characteristic Definitions */ static SupportedAudioRecordingConfiguration; /** * @group Characteristic Definitions */ static SupportedAudioStreamConfiguration; /** * @group Characteristic Definitions */ static SupportedCameraRecordingConfiguration; /** * @group Characteristic Definitions */ static SupportedCharacteristicValueTransitionConfiguration; /** * @group Characteristic Definitions */ static SupportedDataStreamTransportConfiguration; /** * @group Characteristic Definitions */ static SupportedDiagnosticsModes; /** * @group Characteristic Definitions */ static SupportedDiagnosticsSnapshot; /** * @group Characteristic Definitions */ static SupportedFirmwareUpdateConfiguration; /** * @group Characteristic Definitions */ static SupportedMetrics; /** * @group Characteristic Definitions */ static SupportedRouterConfiguration; /** * @group Characteristic Definitions */ static SupportedRTPConfiguration; /** * @group Characteristic Definitions */ static SupportedSleepConfiguration; /** * @group Characteristic Definitions */ static SupportedTransferTransportConfiguration; /** * @group Characteristic Definitions */ static SupportedVideoRecordingConfiguration; /** * @group Characteristic Definitions */ static SupportedVideoStreamConfiguration; /** * @group Characteristic Definitions */ static SwingMode; /** * @group Characteristic Definitions */ static TapType; /** * @group Characteristic Definitions */ static TargetAirPurifierState; /** * @group Characteristic Definitions */ static TargetControlList; /** * @group Characteristic Definitions */ static TargetControlSupportedConfiguration; /** * @group Characteristic Definitions */ static TargetDoorState; /** * @group Characteristic Definitions */ static TargetFanState; /** * @group Characteristic Definitions */ static TargetHeaterCoolerState; /** * @group Characteristic Definitions */ static TargetHeatingCoolingState; /** * @group Characteristic Definitions */ static TargetHorizontalTiltAngle; /** * @group Characteristic Definitions */ static TargetHumidifierDehumidifierState; /** * @group Characteristic Definitions */ static TargetMediaState; /** * @group Characteristic Definitions */ static TargetPosition; /** * @group Characteristic Definitions */ static TargetRelativeHumidity; /** * @group Characteristic Definitions */ static TargetTemperature; /** * @group Characteristic Definitions */ static TargetTiltAngle; /** * @group Characteristic Definitions */ static TargetVerticalTiltAngle; /** * @group Characteristic Definitions */ static TargetVisibilityState; /** * @group Characteristic Definitions */ static TemperatureDisplayUnits; /** * @group Characteristic Definitions */ static ThirdPartyCameraActive; /** * @group Characteristic Definitions */ static ThreadControlPoint; /** * @group Characteristic Definitions */ static ThreadNodeCapabilities; /** * @group Characteristic Definitions */ static ThreadOpenThreadVersion; /** * @group Characteristic Definitions */ static ThreadStatus; /** * @group Characteristic Definitions */ static Token; /** * @group Characteristic Definitions */ static TransmitPower; /** * @group Characteristic Definitions */ static TunnelConnectionTimeout; /** * @group Characteristic Definitions */ static TunneledAccessoryAdvertising; /** * @group Characteristic Definitions */ static TunneledAccessoryConnected; /** * @group Characteristic Definitions */ static TunneledAccessoryStateNumber; /** * @group Characteristic Definitions */ static ValveType; /** * @group Characteristic Definitions */ static Version; /** * @group Characteristic Definitions */ static VideoAnalysisActive; /** * @group Characteristic Definitions */ static VOCDensity; /** * @group Characteristic Definitions */ static Volume; /** * @group Characteristic Definitions */ static VolumeControlType; /** * @group Characteristic Definitions */ static VolumeSelector; /** * @group Characteristic Definitions */ static WakeConfiguration; /** * @group Characteristic Definitions */ static WANConfigurationList; /** * @group Characteristic Definitions */ static WANStatusList; /** * @group Characteristic Definitions */ static WaterLevel; /** * @group Characteristic Definitions */ static WiFiCapabilities; /** * @group Characteristic Definitions */ static WiFiConfigurationControl; /** * @group Characteristic Definitions */ static WiFiSatelliteStatus; // =-=-=-=-=-=-=-=-=-=-=-=-=-=-= // NOTICE: when adding/changing properties, remember to possibly adjust the serialize/deserialize functions displayName; UUID; iid = null; value = null; /** * @private */ statusCode = 0 /* HAPStatus.SUCCESS */; props; /** * The {@link Characteristic.onGet} handler */ getHandler; /** * The {@link Characteristic.onSet} handler */ setHandler; subscriptions = 0; /** * @private */ additionalAuthorizationHandler; constructor(displayName, UUID, props) { super(); this.displayName = displayName; this.UUID = UUID; this.props = { format: "int" /* Formats.INT */, perms: ["ev" /* Perms.NOTIFY */], }; this.setProps(props || {}); // ensure sanity checks are called } /** * Accepts a function that will be called to retrieve the current value of a Characteristic. * The function must return a valid Characteristic value for the Characteristic type. * May optionally return a promise. * * @example * ```ts * Characteristic.onGet(async () => { * return true; * }); * ``` * @param handler */ onGet(handler) { if (typeof handler !== "function") { this.characteristicWarning(".onGet handler must be a function"); return this; } this.getHandler = handler; return this; } /** * Removes the {@link CharacteristicGetHandler} handler which was configured using {@link onGet}. */ removeOnGet() { this.getHandler = undefined; return this; } /** * Accepts a function that will be called when setting the value of a Characteristic. * If the characteristic supports {@link Perms.WRITE_RESPONSE} and the request requests a write-response value, * the returned value will be used. * May optionally return a promise. * * @example * ```ts * Characteristic.onSet(async (value: CharacteristicValue) => { * console.log(value); * }); * ``` * @param handler */ onSet(handler) { if (typeof handler !== "function") { this.characteristicWarning(".onSet handler must be a function"); return this; } this.setHandler = handler; return this; } /** * Removes the {@link CharacteristicSetHandler} which was configured using {@link onSet}. */ removeOnSet() { this.setHandler = undefined; return this; } /** * Updates the properties of this characteristic. * Properties passed via the parameter will be set. Any parameter set to null will be deleted. * See {@link CharacteristicProps}. * * @param props - Partial properties object with the desired updates. */ setProps(props) { (0, assert_1.default)(props, "props cannot be undefined when setting props"); // TODO calling setProps after publish doesn't lead to a increment in the current configuration number let formatDidChange = false; // for every value "null" can be used to reset props, except for required props if (props.format) { formatDidChange = this.props.format !== props.format; this.props.format = props.format; } if (props.perms) { (0, assert_1.default)(props.perms.length > 0, "characteristic prop perms cannot be empty array"); this.props.perms = props.perms; } if (props.unit !== undefined) { this.props.unit = props.unit != null ? props.unit : undefined; } if (props.description !== undefined) { this.props.description = props.description != null ? props.description : undefined; } // check minValue is valid for the format type if (props.minValue !== undefined) { if (props.minValue === null) { props.minValue = undefined; } else if (!(0, request_util_1.isNumericFormat)(this.props.format)) { this.characteristicWarning("Characteristic Property 'minValue' can only be set for characteristics with numeric format, but not for " + this.props.format, "error-message" /* CharacteristicWarningType.ERROR_MESSAGE */); props.minValue = undefined; } else if (typeof props.minValue !== "number" || !Number.isFinite(props.minValue)) { this.characteristicWarning(`Characteristic Property 'minValue' must be a finite number, received "${props.minValue}" (${typeof props.minValue})`, "error-message" /* CharacteristicWarningType.ERROR_MESSAGE */); props.minValue = undefined; } else { if (props.minValue < (0, request_util_1.numericLowerBound)(this.props.format)) { this.characteristicWarning("Characteristic Property 'minValue' was set to " + props.minValue + ", but for numeric format " + this.props.format + " minimum possible is " + (0, request_util_1.numericLowerBound)(this.props.format), "error-message" /* CharacteristicWarningType.ERROR_MESSAGE */); props.minValue = (0, request_util_1.numericLowerBound)(this.props.format); } else if (props.minValue > (0, request_util_1.numericUpperBound)(this.props.format)) { this.characteristicWarning("Characteristic Property 'minValue' was set to " + props.minValue + ", but for numeric format " + this.props.format + " maximum possible is " + (0, request_util_1.numericUpperBound)(this.props.format), "error-message" /* CharacteristicWarningType.ERROR_MESSAGE */); props.minValue = (0, request_util_1.numericLowerBound)(this.props.format); } } this.props.minValue = props.minValue; } // check maxValue is valid for the format type if (props.maxValue !== undefined) { if (props.maxValue === null) { props.maxValue = undefined; } else if (!(0, request_util_1.isNumericFormat)(this.props.format)) { this.characteristicWarning("Characteristic Property 'maxValue' can only be set for characteristics with numeric format, but not for " + this.props.format, "error-message" /* CharacteristicWarningType.ERROR_MESSAGE */); props.maxValue = undefined; } else if (typeof props.maxValue !== "number" || !Number.isFinite(props.maxValue)) { this.characteristicWarning(`Characteristic Property 'maxValue' must be a finite number, received "${props.maxValue}" (${typeof props.maxValue})`, "error-message" /* CharacteristicWarningType.ERROR_MESSAGE */); props.maxValue = undefined; } else { if (props.maxValue > (0, request_util_1.numericUpperBound)(this.props.format)) { this.characteristicWarning("Characteristic Property 'maxValue' was set to " + props.maxValue + ", but for numeric format " + this.props.format + " maximum possible is " + (0, request_util_1.numericUpperBound)(this.props.format), "error-message" /* CharacteristicWarningType.ERROR_MESSAGE */); props.maxValue = (0, request_util_1.numericUpperBound)(this.props.format); } else if (props.maxValue < (0, request_util_1.numericLowerBound)(this.props.format)) { this.characteristicWarning("Characteristic Property 'maxValue' was set to " + props.maxValue + ", but for numeric format " + this.props.format + " minimum possible is " + (0, request_util_1.numericLowerBound)(this.props.format), "error-message" /* CharacteristicWarningType.ERROR_MESSAGE */); props.maxValue = (0, request_util_1.numericUpperBound)(this.props.format); } } this.props.maxValue = props.maxValue; } if (props.minStep !== undefined) { if (props.minStep === null) { this.props.minStep = undefined; } else if (!(0, request_util_1.isNumericFormat)(this.props.format)) { this.characteristicWarning("Characteristic Property `minStep` can only be set for characteristics with numeric format, but not for " + this.props.format, "error-message" /* CharacteristicWarningType.ERROR_MESSAGE */); } else { if (props.minStep < 1 && (0, request_util_1.isIntegerNumericFormat)(this.props.format)) { this.characteristicWarning("Characteristic Property `minStep` was set to a value lower than 1, " + "this will have no effect on format `" + this.props.format); } this.props.minStep = props.minStep; } } if (props.maxLen !== undefined) { if (props.maxLen === null) { this.props.maxLen = undefined; } else if (this.props.format !== "string" /* Formats.STRING */) { this.characteristicWarning("Characteristic Property `maxLen` can only be set for characteristics with format `STRING`, but not for " + this.props.format, "error-message" /* CharacteristicWarningType.ERROR_MESSAGE */); } else { if (props.maxLen > 256) { this.characteristicWarning("Characteristic Property string `maxLen` cannot be bigger than 256"); props.maxLen = 256; } this.props.maxLen = props.maxLen; } } if (props.maxDataLen !== undefined) { if (props.maxDataLen === null) { this.props.maxDataLen = undefined; } else if (this.props.format !== "data" /* Formats.DATA */) { this.characteristicWarning("Characteristic Property `maxDataLen` can only be set for characteristics with format `DATA`, but not for " + this.props.format, "error-message" /* CharacteristicWarningType.ERROR_MESSAGE */); } else { this.props.maxDataLen = props.maxDataLen; } } if (props.validValues !== undefined) { if (props.validValues === null) { this.props.validValues = undefined; } else if (!(0, request_util_1.isNumericFormat)(this.props.format)) { this.characteristicWarning("Characteristic Property `validValues` was supplied for non numeric format " + this.props.format); } else { (0, assert_1.default)(props.validValues.length, "characteristic prop validValues cannot be empty array"); this.props.validValues = props.validValues; } } if (props.validValueRanges !== undefined) { if (props.validValueRanges === null) { this.props.validValueRanges = undefined; } else if (!(0, request_util_1.isNumericFormat)(this.props.format)) { this.characteristicWarning("Characteristic Property `validValueRanges` was supplied for non numeric format " + this.props.format); } else { (0, assert_1.default)(props.validValueRanges.length === 2, "characteristic prop validValueRanges must have a length of 2"); this.props.validValueRanges = props.validValueRanges; } } if (props.adminOnlyAccess !== undefined) { this.props.adminOnlyAccess = props.adminOnlyAccess != null ? props.adminOnlyAccess : undefined; } if (this.props.minValue != null && this.props.maxValue != null) { // the eqeq instead of eqeqeq is important here if (this.props.minValue > this.props.maxValue) { // see https://github.com/homebridge/HAP-NodeJS/issues/690 this.props.minValue = undefined; this.props.maxValue = undefined; throw new Error("Error setting CharacteristicsProps for '" + this.displayName + "': 'minValue' cannot be greater or equal the 'maxValue'!"); } } if (((0, request_util_1.isNumericFormat)(this.props.format) || this.props.format === "string" /* Formats.STRING */) && this.value != null && !formatDidChange && this.statusCode === 0 /* HAPStatus.SUCCESS */ && this.UUID !== Characteristic.ProgrammableSwitchEvent.UUID) { // explaining the if statement above: // - We only do a check for numeric and string formats as they are the only ones affected by characteristic property restrictions. // - There must be a value to begin with. Otherwise, it should just stay not having a value at all (anything else is guess work). // - If the format is changed through `setProps` we rely on the user to supply a valid value after the `setProps` call! // - If the characteristic is marked as erroneous the value is not considered valid anyway, and we must not remove the `statusCode`. // - Special case for `ProgrammableSwitchEvent` where every change in value is considered an event which would result in ghost button presses // validateUserInput when called from setProps is intended to clamp value withing allowed range. It is why warnings should not be displayed. const correctedValue = this.validateUserInput(this.value, "debug-message" /* CharacteristicWarningType.DEBUG_MESSAGE */); if (correctedValue !== this.value) { // we don't want to emit a CHANGE event if the value didn't change at all! this.updateValue(correctedValue); } } return this; } /** * This method can be used to gain an Iterator to loop over all valid values defined for this characteristic. * * The range of valid values can be defined using three different ways via the {@link CharacteristicProps} object * (set via the {@link setProps} method): * * First method is to specifically list every valid value inside {@link CharacteristicProps.validValues} * * Second you can specify a range via {@link CharacteristicProps.minValue} and {@link CharacteristicProps.maxValue} (with optionally defining * {@link CharacteristicProps.minStep}) * * And lastly you can specify a range via {@link CharacteristicProps.validValueRanges} * * Implicitly a valid value range is predefined for characteristics with Format {@link Formats.UINT8}, {@link Formats.UINT16}, * {@link Formats.UINT32} and {@link Formats.UINT64}: starting by zero to their respective maximum number * * The method will automatically detect which type of valid values definition is used and provide * the correct Iterator for that case. * * Note: This method is (obviously) only valid for numeric characteristics. * * @example * ```ts * // use the iterator to loop over every valid value... * for (const value of characteristic.validValuesIterator()) { * // Insert logic to run for every * } * * // ... or collect them in an array for storage or manipulation * const validValues = Array.from(characteristic.validValuesIterator()); * ``` */ validValuesIterator() { return new ValidValuesIterable(this.props); } // noinspection JSUnusedGlobalSymbols /** * This method can be used to set up additional authorization for a characteristic. * For one, it adds the {@link Perms.ADDITIONAL_AUTHORIZATION} permission to the characteristic * (if it wasn't already) to signal support for additional authorization to HomeKit. * Additionally, an {@link AdditionalAuthorizationHandler} is set up which is called * before a write request is performed. * * Additional Authorization Data can be added to SET request via a custom iOS App. * Before hap-nodejs executes a write request it will call the {@link AdditionalAuthorizationHandler} * with 'authData' supplied in the write request. The 'authData' is a base64 encoded string * (or undefined if no authData was supplied). * The {@link AdditionalAuthorizationHandler} must then return true or false to indicate if the write request * is authorized and should be accepted. * * @param handler - Handler called to check additional authorization data. */ setupAdditionalAuthorization(handler) { if (!this.props.perms.includes("aa" /* Perms.ADDITIONAL_AUTHORIZATION */)) { this.props.perms.push("aa" /* Perms.ADDITIONAL_AUTHORIZATION */); } this.additionalAuthorizationHandler = handler; } setValue(value, callback, context) { if (value instanceof Error) { this.statusCode = value instanceof hapStatusError_1.HapStatusError ? value.hapStatus : extractHAPStatusFromError(value); if (callback) { callback(); } return this; } if (callback && !context && typeof callback !== "function") { context = callback; callback = undefined; } try { value = this.validateUserInput(value); } catch (error) { this.characteristicWarning(error?.message + "", "error-message" /* CharacteristicWarningType.ERROR_MESSAGE */, error?.stack); if (callback) { callback(error); } return this; } this.handleSetRequest(value, undefined, context).then(value => { if (callback) { if (value) { // possible write response callback(null, value); } else { callback(null); } } }, reason => { if (callback) { callback(reason); } }); return this; } updateValue(value, callback, context) { if (value instanceof Error) { this.statusCode = value instanceof hapStatusError_1.HapStatusError ? value.hapStatus : extractHAPStatusFromError(value); if (callback) { callback(); } return this; } if (callback && !context && typeof callback !== "function") { context = callback; callback = undefined; } try { value = this.validateUserInput(value); } catch (error) { this.characteristicWarning(error?.message + "", "error-message" /* CharacteristicWarningType.ERROR_MESSAGE */, error?.stack); if (callback) { callback(); } return this; } this.statusCode = 0 /* HAPStatus.SUCCESS */; const oldValue = this.value; this.value = value; if (callback) { callback(); } this.emit("change" /* CharacteristicEventTypes.CHANGE */, { originator: undefined, oldValue: oldValue, newValue: value, reason: "update" /* ChangeReason.UPDATE */, context: context }); return this; // for chaining } /** * This method acts similarly to {@link updateValue} by setting the current value of the characteristic