1 | import { EventEmitter } from "events";
|
2 | import { ConstructorArgs, HAPPincode, InterfaceName, IPAddress, MacAddress, Nullable, VoidCallback, WithUUID } from "../types";
|
3 | import { Advertiser } from "./Advertiser";
|
4 | import { Characteristic } from "./Characteristic";
|
5 | import { Controller, ControllerConstructor, ControllerIdentifier, ControllerServiceMap } from "./controller";
|
6 | import { HAPServer } from "./HAPServer";
|
7 | import { AccessoryInfo } from "./model/AccessoryInfo";
|
8 | import { ControllerStorage } from "./model/ControllerStorage";
|
9 | import { IdentifierCache } from "./model/IdentifierCache";
|
10 | import { SerializedService, Service, ServiceCharacteristicChange, ServiceId } from "./Service";
|
11 | /**
|
12 | * Known category values. Category is a hint to iOS clients about what "type" of Accessory this represents, for UI only.
|
13 | *
|
14 | * @group Accessory
|
15 | */
|
16 | export declare const enum Categories {
|
17 | OTHER = 1,
|
18 | BRIDGE = 2,
|
19 | FAN = 3,
|
20 | GARAGE_DOOR_OPENER = 4,
|
21 | LIGHTBULB = 5,
|
22 | DOOR_LOCK = 6,
|
23 | OUTLET = 7,
|
24 | SWITCH = 8,
|
25 | THERMOSTAT = 9,
|
26 | SENSOR = 10,
|
27 | ALARM_SYSTEM = 11,
|
28 | SECURITY_SYSTEM = 11,//Added to conform to HAP naming
|
29 | DOOR = 12,
|
30 | WINDOW = 13,
|
31 | WINDOW_COVERING = 14,
|
32 | PROGRAMMABLE_SWITCH = 15,
|
33 | RANGE_EXTENDER = 16,
|
34 | CAMERA = 17,
|
35 | IP_CAMERA = 17,//Added to conform to HAP naming
|
36 | VIDEO_DOORBELL = 18,
|
37 | AIR_PURIFIER = 19,
|
38 | AIR_HEATER = 20,
|
39 | AIR_CONDITIONER = 21,
|
40 | AIR_HUMIDIFIER = 22,
|
41 | AIR_DEHUMIDIFIER = 23,
|
42 | APPLE_TV = 24,
|
43 | HOMEPOD = 25,
|
44 | SPEAKER = 26,
|
45 | AIRPORT = 27,
|
46 | SPRINKLER = 28,
|
47 | FAUCET = 29,
|
48 | SHOWER_HEAD = 30,
|
49 | TELEVISION = 31,
|
50 | TARGET_CONTROLLER = 32,// Remote Control
|
51 | ROUTER = 33,
|
52 | AUDIO_RECEIVER = 34,
|
53 | TV_SET_TOP_BOX = 35,
|
54 | TV_STREAMING_STICK = 36
|
55 | }
|
56 | /**
|
57 | * @group Accessory
|
58 | */
|
59 | export interface SerializedAccessory {
|
60 | displayName: string;
|
61 | UUID: string;
|
62 | lastKnownUsername?: MacAddress;
|
63 | category: Categories;
|
64 | services: SerializedService[];
|
65 | linkedServices?: Record<ServiceId, ServiceId[]>;
|
66 | controllers?: SerializedControllerContext[];
|
67 | }
|
68 | /**
|
69 | * @group Controller API
|
70 | */
|
71 | export interface SerializedControllerContext {
|
72 | type: ControllerIdentifier;
|
73 | services: SerializedServiceMap;
|
74 | }
|
75 | /**
|
76 | * @group Controller API
|
77 | */
|
78 | export type SerializedServiceMap = Record<string, ServiceId>;
|
79 | /**
|
80 | * @group Controller API
|
81 | */
|
82 | export interface ControllerContext {
|
83 | controller: Controller;
|
84 | serviceMap: ControllerServiceMap;
|
85 | }
|
86 | /**
|
87 | * @group Accessory
|
88 | */
|
89 | export declare const enum CharacteristicWarningType {
|
90 | SLOW_WRITE = "slow-write",
|
91 | TIMEOUT_WRITE = "timeout-write",
|
92 | SLOW_READ = "slow-read",
|
93 | TIMEOUT_READ = "timeout-read",
|
94 | WARN_MESSAGE = "warn-message",
|
95 | ERROR_MESSAGE = "error-message",
|
96 | DEBUG_MESSAGE = "debug-message"
|
97 | }
|
98 | /**
|
99 | * @group Accessory
|
100 | */
|
101 | export interface CharacteristicWarning {
|
102 | characteristic: Characteristic;
|
103 | type: CharacteristicWarningType;
|
104 | message: string;
|
105 | originatorChain: string[];
|
106 | stack?: string;
|
107 | }
|
108 | /**
|
109 | * @group Accessory
|
110 | */
|
111 | export interface PublishInfo {
|
112 | username: MacAddress;
|
113 | pincode: HAPPincode;
|
114 | /**
|
115 | * Specify the category for the HomeKit accessory.
|
116 | * The category is used only in the mdns advertisement and specifies the devices type
|
117 | * for the HomeKit controller.
|
118 | * Currently, this only affects the icon shown in the pairing screen.
|
119 | * For the Television and Smart Speaker service it also affects the icon shown in
|
120 | * the Home app when paired.
|
121 | */
|
122 | category?: Categories;
|
123 | setupID?: string;
|
124 | /**
|
125 | * Defines the host where the HAP server will be bound to.
|
126 | * When undefined the HAP server will bind to all available interfaces
|
127 | * (see https://nodejs.org/api/net.html#net_server_listen_port_host_backlog_callback).
|
128 | *
|
129 | * This property accepts a mixture of IPAddresses and network interface names.
|
130 | * Depending on the mixture of supplied addresses/names hap-nodejs will bind differently.
|
131 | *
|
132 | * It is advised to not just bind to a specific address, but specifying the interface name
|
133 | * in oder to bind on all address records (and ip version) available.
|
134 | *
|
135 | * HAP-NodeJS (or the underlying ciao library) will not report about misspelled interface names,
|
136 | * as it could be that the interface is currently just down and will come up later.
|
137 | *
|
138 | * Here are a few examples:
|
139 | * - bind: "::"
|
140 | * Pretty much identical to not specifying anything, as most systems (with ipv6 support)
|
141 | * will default to the unspecified ipv6 address (with dual stack support).
|
142 | *
|
143 | * - bind: "0.0.0.0"
|
144 | * Binding TCP socket to the unspecified ipv4 address.
|
145 | * The mdns advertisement will exclude any ipv6 address records.
|
146 | *
|
147 | * - bind: ["en0", "lo0"]
|
148 | * The mdns advertising will advertise all records of the en0 and loopback interface (if available) and
|
149 | * will also react to address changes on those interfaces.
|
150 | * In order for the HAP server to accept all those address records (which may contain ipv6 records)
|
151 | * it will bind on the unspecified ipv6 address "::" (assuming dual stack is supported).
|
152 | *
|
153 | * - bind: ["en0", "lo0", "0.0.0.0"]
|
154 | * Same as above, only that the HAP server will bind on the unspecified ipv4 address "0.0.0.0".
|
155 | * The mdns advertisement will not advertise any ipv6 records.
|
156 | *
|
157 | * - bind: "169.254.104.90"
|
158 | * This will bind the HAP server to the address 0.0.0.0.
|
159 | * The mdns advertisement will only advertise the A record 169.254.104.90.
|
160 | * If the given network interface of that address encounters an ip address change (to a different address),
|
161 | * the mdns advertisement will result in not advertising an address at all.
|
162 | * So it is advised to specify an interface name instead of a specific address.
|
163 | * This is identical with ipv6 addresses.
|
164 | *
|
165 | * - bind: ["169.254.104.90", "192.168.1.4"]
|
166 | * As the HAP TCP socket can only bind to a single address, when specifying multiple ip addresses
|
167 | * the HAP server will bind to the unspecified ip address (0.0.0.0 if only ipv4 addresses are supplied,
|
168 | * :: if a mixture or only ipv6 addresses are supplied).
|
169 | * The mdns advertisement will only advertise the specified ip addresses.
|
170 | * If the given network interface of that address encounters an ip address change (to different addresses),
|
171 | * the mdns advertisement will result in not advertising an address at all.
|
172 | * So it is advised to specify an interface name instead of a specific address.
|
173 | *
|
174 | */
|
175 | bind?: (InterfaceName | IPAddress) | (InterfaceName | IPAddress)[];
|
176 | /**
|
177 | * Defines the port where the HAP server will be bound to.
|
178 | * When undefined port 0 will be used resulting in a random port.
|
179 | */
|
180 | port?: number;
|
181 | /**
|
182 | * If this option is set to true, HAP-NodeJS will add identifying material (based on {@link username})
|
183 | * to the end of the accessory display name (and bonjour instance name).
|
184 | * Default: true
|
185 | */
|
186 | addIdentifyingMaterial?: boolean;
|
187 | /**
|
188 | * Defines the advertiser used with the published Accessory.
|
189 | */
|
190 | advertiser?: MDNSAdvertiser;
|
191 | }
|
192 | /**
|
193 | * @group Accessory
|
194 | */
|
195 | export declare const enum MDNSAdvertiser {
|
196 | /**
|
197 | * Use the `@homebridge/ciao` module as advertiser.
|
198 | */
|
199 | CIAO = "ciao",
|
200 | /**
|
201 | * Use the `bonjour-hap` module as advertiser.
|
202 | */
|
203 | BONJOUR = "bonjour-hap",
|
204 | /**
|
205 | * Use Avahi/D-Bus as advertiser.
|
206 | */
|
207 | AVAHI = "avahi",
|
208 | /**
|
209 | * Use systemd-resolved/D-Bus as advertiser.
|
210 | *
|
211 | * Note: The systemd-resolved D-Bus interface doesn't provide means to detect restarts of the service.
|
212 | * Therefore, we can't detect if our advertisement might be lost due to a restart of the systemd-resolved daemon restart.
|
213 | * Consequentially, treat this feature as an experimental feature.
|
214 | */
|
215 | RESOLVED = "resolved"
|
216 | }
|
217 | /**
|
218 | * @group Accessory
|
219 | */
|
220 | export type AccessoryCharacteristicChange = ServiceCharacteristicChange & {
|
221 | service: Service;
|
222 | };
|
223 | /**
|
224 | * @group Service
|
225 | */
|
226 | export interface ServiceConfigurationChange {
|
227 | service: Service;
|
228 | }
|
229 | /**
|
230 | * @group Accessory
|
231 | */
|
232 | export declare const enum AccessoryEventTypes {
|
233 | /**
|
234 | * Emitted when an iOS device wishes for this Accessory to identify itself. If `paired` is false, then
|
235 | * this device is currently browsing for Accessories in the system-provided "Add Accessory" screen. If
|
236 | * `paired` is true, then this is a device that has already paired with us. Note that if `paired` is true,
|
237 | * listening for this event is a shortcut for the underlying mechanism of setting the `Identify` Characteristic:
|
238 | * `getService(Service.AccessoryInformation).getCharacteristic(Characteristic.Identify).on('set', ...)`
|
239 | * You must call the callback for identification to be successful.
|
240 | */
|
241 | IDENTIFY = "identify",
|
242 | /**
|
243 | * This event is emitted once the HAP TCP socket is bound.
|
244 | * At this point the mdns advertisement isn't yet available. Use the {@link ADVERTISED} if you require the accessory to be discoverable.
|
245 | */
|
246 | LISTENING = "listening",
|
247 | /**
|
248 | * This event is emitted once the mDNS suite has fully advertised the presence of the accessory.
|
249 | * This event is guaranteed to be called after {@link LISTENING}.
|
250 | */
|
251 | ADVERTISED = "advertised",
|
252 | SERVICE_CONFIGURATION_CHANGE = "service-configurationChange",
|
253 | /**
|
254 | * Emitted after a change in the value of one of the provided Service's Characteristics.
|
255 | */
|
256 | SERVICE_CHARACTERISTIC_CHANGE = "service-characteristic-change",
|
257 | PAIRED = "paired",
|
258 | UNPAIRED = "unpaired",
|
259 | CHARACTERISTIC_WARNING = "characteristic-warning"
|
260 | }
|
261 | /**
|
262 | * @group Accessory
|
263 | */
|
264 | export declare interface Accessory {
|
265 | on(event: "identify", listener: (paired: boolean, callback: VoidCallback) => void): this;
|
266 | on(event: "listening", listener: (port: number, address: string) => void): this;
|
267 | on(event: "advertised", listener: () => void): this;
|
268 | on(event: "service-configurationChange", listener: (change: ServiceConfigurationChange) => void): this;
|
269 | on(event: "service-characteristic-change", listener: (change: AccessoryCharacteristicChange) => void): this;
|
270 | on(event: "paired", listener: () => void): this;
|
271 | on(event: "unpaired", listener: () => void): this;
|
272 | on(event: "characteristic-warning", listener: (warning: CharacteristicWarning) => void): this;
|
273 | emit(event: "identify", paired: boolean, callback: VoidCallback): boolean;
|
274 | emit(event: "listening", port: number, address: string): boolean;
|
275 | emit(event: "advertised"): boolean;
|
276 | emit(event: "service-configurationChange", change: ServiceConfigurationChange): boolean;
|
277 | emit(event: "service-characteristic-change", change: AccessoryCharacteristicChange): boolean;
|
278 | emit(event: "paired"): boolean;
|
279 | emit(event: "unpaired"): boolean;
|
280 | emit(event: "characteristic-warning", warning: CharacteristicWarning): boolean;
|
281 | }
|
282 | /**
|
283 | * Accessory is a virtual HomeKit device. It can publish an associated HAP server for iOS devices to communicate
|
284 | * with - or it can run behind another "Bridge" Accessory server.
|
285 | *
|
286 | * Bridged Accessories in this implementation must have a UUID that is unique among all other Accessories that
|
287 | * are hosted by the Bridge. This UUID must be "stable" and unchanging, even when the server is restarted. This
|
288 | * is required so that the Bridge can provide consistent "Accessory IDs" (aid) and "Instance IDs" (iid) for all
|
289 | * Accessories, Services, and Characteristics for iOS clients to reference later.
|
290 | *
|
291 | * @group Accessory
|
292 | */
|
293 | export declare class Accessory extends EventEmitter {
|
294 | displayName: string;
|
295 | UUID: string;
|
296 | private static readonly TIMEOUT_WARNING;
|
297 | private static readonly TIMEOUT_AFTER_WARNING;
|
298 | aid: Nullable<number>;
|
299 | _isBridge: boolean;
|
300 | bridged: boolean;
|
301 | bridge?: Accessory;
|
302 | bridgedAccessories: Accessory[];
|
303 | reachable: boolean;
|
304 | lastKnownUsername?: MacAddress;
|
305 | category: Categories;
|
306 | services: Service[];
|
307 | private primaryService?;
|
308 | shouldPurgeUnusedIDs: boolean;
|
309 | /**
|
310 | * Captures if initialization steps inside {@link publish} have been called.
|
311 | * This is important when calling {@link publish} multiple times (e.g. after calling {@link unpublish}).
|
312 | * @private Private API
|
313 | */
|
314 | private initialized;
|
315 | private controllers;
|
316 | private serializedControllers?;
|
317 | private activeCameraController?;
|
318 | /**
|
319 | * @private Private API.
|
320 | */
|
321 | _accessoryInfo?: Nullable<AccessoryInfo>;
|
322 | /**
|
323 | * @private Private API.
|
324 | */
|
325 | _setupID: Nullable<string>;
|
326 | /**
|
327 | * @private Private API.
|
328 | */
|
329 | _identifierCache?: Nullable<IdentifierCache>;
|
330 | /**
|
331 | * @private Private API.
|
332 | */
|
333 | controllerStorage: ControllerStorage;
|
334 | /**
|
335 | * @private Private API.
|
336 | */
|
337 | _advertiser?: Advertiser;
|
338 | /**
|
339 | * @private Private API.
|
340 | */
|
341 | _server?: HAPServer;
|
342 | /**
|
343 | * @private Private API.
|
344 | */
|
345 | _setupURI?: string;
|
346 | private configurationChangeDebounceTimeout?;
|
347 | /**
|
348 | * This property captures the time when we last served a /accessories request.
|
349 | * For multiple bursts of /accessories request we don't want to always contact GET handlers
|
350 | */
|
351 | private lastAccessoriesRequest;
|
352 | constructor(displayName: string, UUID: string);
|
353 | private identificationRequest;
|
354 | /**
|
355 | * Add the given service instance to the Accessory.
|
356 | *
|
357 | * @param service - A { Service} instance.
|
358 | * Returns the service instance passed to the method call.
|
359 | */
|
360 | addService(service: Service): Service;
|
361 | /**
|
362 | * Adds a given service by calling the provided {@link Service} constructor with the provided constructor arguments.
|
363 | * @param serviceConstructor - A {@link Service} service constructor (e.g. {@link Service.Switch}).
|
364 | * @param constructorArgs - The arguments passed to the given constructor.
|
365 | * @returns Returns the constructed service instance.
|
366 | */
|
367 | addService<S extends typeof Service>(serviceConstructor: S, ...constructorArgs: ConstructorArgs<S>): Service;
|
368 | removeService(service: Service): void;
|
369 | private removeLinkedService;
|
370 | getService<T extends WithUUID<typeof Service>>(name: string | T): Service | undefined;
|
371 | getServiceById<T extends WithUUID<typeof Service>>(uuid: string | T, subType: string): Service | undefined;
|
372 | /**
|
373 | * Returns the bridging accessory if this accessory is bridged.
|
374 | * Otherwise, returns itself.
|
375 | *
|
376 | * @returns the primary accessory
|
377 | */
|
378 | getPrimaryAccessory: () => Accessory;
|
379 | addBridgedAccessory(accessory: Accessory, deferUpdate?: boolean): Accessory;
|
380 | addBridgedAccessories(accessories: Accessory[]): void;
|
381 | removeBridgedAccessory(accessory: Accessory, deferUpdate?: boolean): void;
|
382 | removeBridgedAccessories(accessories: Accessory[]): void;
|
383 | removeAllBridgedAccessories(): void;
|
384 | private getCharacteristicByIID;
|
385 | protected getAccessoryByAID(aid: number): Accessory | undefined;
|
386 | protected findCharacteristic(aid: number, iid: number): Characteristic | undefined;
|
387 | /**
|
388 | * This method is used to set up a new Controller for this accessory. See {@link Controller} for a more detailed
|
389 | * explanation what a Controller is and what it is capable of.
|
390 | *
|
391 | * The controller can be passed as an instance of the class or as a constructor (without any necessary parameters)
|
392 | * for a new Controller.
|
393 | * Only one Controller of a given {@link ControllerIdentifier} can be configured for a given Accessory.
|
394 | *
|
395 | * When called, it will be checked if there are any services and persistent data the Controller (for the given
|
396 | * {@link ControllerIdentifier}) can be restored from. Otherwise, the Controller will be created with new services.
|
397 | *
|
398 | *
|
399 | * @param controllerConstructor - The Controller instance or constructor to the Controller with no required arguments.
|
400 | */
|
401 | configureController(controllerConstructor: Controller | ControllerConstructor): void;
|
402 | /**
|
403 | * This method will remove a given Controller from this accessory.
|
404 | * The controller object will be restored to its initial state.
|
405 | * This also means that any event handlers setup for the controller will be removed.
|
406 | *
|
407 | * @param controller - The controller which should be removed from the accessory.
|
408 | */
|
409 | removeController(controller: Controller): void;
|
410 | private handleAccessoryUnpairedForControllers;
|
411 | private handleUpdatedControllerServiceMap;
|
412 | setupURI(): string;
|
413 | /**
|
414 | * This method is called right before the accessory is published. It should be used to check for common
|
415 | * mistakes in Accessory structured, which may lead to HomeKit rejecting the accessory when pairing.
|
416 | * If it is called on a bridge it will call this method for all bridged accessories.
|
417 | */
|
418 | private validateAccessory;
|
419 | /**
|
420 | * Assigns aid/iid to ourselves, any Accessories we are bridging, and all associated Services+Characteristics. Uses
|
421 | * the provided identifierCache to keep IDs stable.
|
422 | * @private Private API
|
423 | */
|
424 | _assignIDs(identifierCache: IdentifierCache): void;
|
425 | disableUnusedIDPurge(): void;
|
426 | enableUnusedIDPurge(): void;
|
427 | /**
|
428 | * Manually purge the unused ids if you like, comes handy
|
429 | * when you have disabled auto purge, so you can do it manually
|
430 | */
|
431 | purgeUnusedIDs(): void;
|
432 | /**
|
433 | * Returns a JSON representation of this accessory suitable for delivering to HAP clients.
|
434 | */
|
435 | private toHAP;
|
436 | /**
|
437 | * Returns a JSON representation of this accessory without characteristic values.
|
438 | */
|
439 | private internalHAPRepresentation;
|
440 | /**
|
441 | * Publishes this accessory on the local network for iOS clients to communicate with.
|
442 | * - `info.username` - formatted as a MAC address, like `CC:22:3D:E3:CE:F6`, of this accessory.
|
443 | * Must be globally unique from all Accessories on your local network.
|
444 | * - `info.pincode` - the 8-digit pin code for clients to use when pairing this Accessory.
|
445 | * Must be formatted as a string like `031-45-154`.
|
446 | * - `info.category` - one of the values of the `Accessory.Category` enum, like `Accessory.Category.SWITCH`.
|
447 | * This is a hint to iOS clients about what "type" of Accessory this represents, so
|
448 | * that for instance an appropriate icon can be drawn for the user while adding a
|
449 | * new Accessory.
|
450 | * @param {{
|
451 | * username: string;
|
452 | * pincode: string;
|
453 | * category: Accessory.Categories;
|
454 | * }} info - Required info for publishing.
|
455 | * @param {boolean} allowInsecureRequest - Will allow unencrypted and unauthenticated access to the http server
|
456 | */
|
457 | publish(info: PublishInfo, allowInsecureRequest?: boolean): Promise<void>;
|
458 | /**
|
459 | * Removes this Accessory from the local network
|
460 | * Accessory object will no longer valid after invoking this method
|
461 | * Trying to invoke publish() on the object will result undefined behavior
|
462 | */
|
463 | destroy(): Promise<void>;
|
464 | unpublish(): Promise<void>;
|
465 | private enqueueConfigurationUpdate;
|
466 | private onListening;
|
467 | private handleInitialPairSetupFinished;
|
468 | private handleAddPairing;
|
469 | private handleRemovePairing;
|
470 | private handleListPairings;
|
471 | private handleAccessories;
|
472 | private handleGetCharacteristics;
|
473 | private handleCharacteristicRead;
|
474 | private handleSetCharacteristics;
|
475 | private handleCharacteristicWrite;
|
476 | private handleResource;
|
477 | private handleHAPConnectionClosed;
|
478 | private handleServiceConfigurationChangeEvent;
|
479 | private handleCharacteristicChangeEvent;
|
480 | private sendCharacteristicWarning;
|
481 | private handleCharacteristicWarning;
|
482 | private setupServiceEventHandlers;
|
483 | private _sideloadServices;
|
484 | private static _generateSetupID;
|
485 | static serialize(accessory: Accessory): SerializedAccessory;
|
486 | static deserialize(json: SerializedAccessory): Accessory;
|
487 | static cleanupAccessoryData(username: MacAddress): void;
|
488 | private static serializeServiceMap;
|
489 | private static deserializeServiceMap;
|
490 | private static parseBindOption;
|
491 | }
|
492 | //# sourceMappingURL=Accessory.d.ts.map |
\ | No newline at end of file |