UNPKG

@jw988/unifi-access

Version:

A soon-to-be-almost-complete implementation of the UniFi Access API.

323 lines (322 loc) 14.1 kB
import { type RequestOptions, type Response } from "@adobe/fetch"; import type { AccessBootstrapConfig, AccessControllerConfig, AccessDeviceConfig, AccessDeviceConfigPayload, AccessDoorConfig, AccessFloorConfig } from "./access-types.js"; import type { AccessLogging } from "./access-logging.js"; import { EventEmitter } from "node:events"; /** * The direct UniFi Access API is partially documented through an officially supported public API that Ubiquiti has released. However, this API also has certain * constraints and limitations such as lacking the ability to change the settings on an Access device. The full native API has been reverse engineered mostly through * trail and error with the Access web interface as well as insight from the public API. * * Here's how the UniFi Access API works: * * 1. {@link login | Login} to the UniFi Access controller and acquire security credentials for further calls to the API. * * 2. Enumerate the list of UniFi Access devices by calling the {@link bootstrap} property. This contains everything you would want to know about the devices attached to * this particular UniFi Access controller. Information about the Access controller can be accessed through the {@link controller} property. * * 3. Listen for `message` events emitted by {@link AccessApi} containing all Access controller events, in realtime. They are delivered as * {@link access-types.AccessEventPacket} packets, containing the event-specific details. * * Those are the basics that gets us up and running. */ export declare class AccessApi extends EventEmitter { private _bootstrap; private _controller; private _devices; private _doors; private _floors; private address; private apiErrorCount; private apiLastSuccess; private events; private eventsTimer; private fetch; private headers; private _isAdminUser; private log; private password; private username; private apikey; /** * Create an instance of the UniFi Access API. * * @param log - Logging functions to use. * * @defaultValue `none` - Logging will be done to stdout and stderr. */ constructor(log?: AccessLogging); /** * Execute a login attempt to the UniFi Access API. * * @param address - Address of the UniFi Access controller, expressed as an FQDN or IP address. * @param username - Username to use when logging into the controller. * @param password - Password to use when logging into the controller. * * @returns Returns a promise that will resolve to `true` if successful and `false` otherwise. * * @remarks A `login` event will be emitted each time this method is called, with the result of the attempt as an argument. * * @example * Login to the Access controller. You can selectively choose to either `await` the promise that is returned by `login`, or subscribe to the `login` event. * * ```ts * import { AccessApi } from "unifi-access"; * * // Create a new Access API instance. * const ufp = new AccessApi(); * * // Set a listener to wait for the login event to occur. * ufp.once("login", (successfulLogin: boolean) => { * * // Indicate if we are successful. * if(successfulLogin) { * * console.log("Logged in successfully."); * process.exit(0); * } * }); * * // Login to the Access controller. * if(!(await ufa.login("access-controller.local", "username", "password"))) { * * console.log("Invalid login credentials."); * process.exit(0); * }; * ``` */ login(address: string, username: string, password: string): Promise<boolean>; private loginController; /** * Execute a login attempt to the UniFi Access API. * * @param address - Address of the UniFi Access controller, expressed as an FQDN or IP address. * @param apikey - Apikey for the controller. * * @returns Returns a promise that will resolve to `true` if successful and `false` otherwise. * * @remarks A `login` event will be emitted each time this method is called, with the result of the attempt as an argument. * * @example * Login to the Access controller. You can selectively choose to either `await` the promise that is returned by `login`, or subscribe to the `login` event. * * ```ts * import { AccessApi } from "unifi-access"; * * // Create a new Access API instance. * const ufp = new AccessApi(); * * // Set a listener to wait for the login event to occur. * ufp.once("login", (successfulLogin: boolean) => { * * // Indicate if we are successful. * if(successfulLogin) { * * console.log("Logged in successfully."); * process.exit(0); * } * }); * * // Login to the Access controller. * if(!(await ufa.login("access-controller.local", "username", "password"))) { * * console.log("Invalid login credentials."); * process.exit(0); * }; * ``` */ loginapi(address: string, apikey: string): Promise<boolean>; private bootstrapController; private launchEventsWs; /** * Retrieve the bootstrap JSON from a UniFi Access controller. * * @returns Returns a promise that will resolve to `true` if successful and `false` otherwise. * * @remarks A `bootstrap` event will be emitted each time this method is successfully called, with the AccessToplogyConfig JSON as an argument. As a * convenience, the {@link devices}, {@link doors}, and {@link floors} properties will be populated as well. * * @example * Retrieve the bootstrap JSON. You can selectively choose to either `await` the promise that is returned by `getBootstrap`, or subscribe to the `bootstrap` event. * * ```ts * import { AccessApi, AccessDeviceConfig } from "unifi-access"; * import util from "node:util"; * * // Create a new Access API instance. * const ufa = new AccessApi(); * * // Set a listener to wait for the bootstrap event to occur. * ufa.once("bootstrap", (bootstrapJSON: AccessDeviceConfig) => { * * // Once we've bootstrapped the Access controller, output the bootstrap JSON and we're done. * process.stdout.write(util.inspect(bootstrapJSON, { colors: true, depth: null, sorted: true }) + "\n", () => process.exit(0)); * }); * * // Login to the Access controller. * if(!(await ufa.login("access-controller.local", "username", "password"))) { * * console.log("Invalid login credentials."); * process.exit(0); * }; * * // Bootstrap the controller. It will emit a message once it's received the bootstrap JSON, or you can alternatively wait for the promise to resolve. * if(!(await ufa.getBootstrap())) { * * console.log("Unable to bootstrap the Access controller."); * process.exit(0); * } * ``` * * Alternatively, you can access the bootstrap JSON directly through the {@link bootstrap} accessor: * * ```ts * import { AccessApi } from "unifi-access"; * import util from "node:util"; * * // Create a new Access API instance. * const ufa = new AccessApi(); * * // Login to the Access controller. * if(!(await ufa.login("access-controller.local", "username", "password"))) { * * console.log("Invalid login credentials."); * process.exit(0); * }; * * // Bootstrap the controller. * if(!(await ufa.getBootstrap())) { * * console.log("Unable to bootstrap the Access controller."); * process.exit(0); * } * * // Once we've bootstrapped the Access controller, access the bootstrap JSON through the bootstrap accessor and we're done. * process.stdout.write(util.inspect(ufa.bootstrap, { colors: true, depth: null, sorted: true }) + "\n", () => process.exit(0)); * ``` * */ getBootstrap(): Promise<boolean>; /** * Send an unlock command to the Access controller. * * @param device - Access device. * @param duration - Unlock interval in minutes. * * @returns Returns `true` if successful, `false` otherwise. * * @remarks If `duration` is not specified, a standard unlock request will be sent to the Access controller which will unlock for 2 seconds. Valid values for duration * are `Infinity` - remain unlocked until reset, `0` - reset lock to secure state, `duration` - number of minutes. */ unlock(device: AccessDeviceConfig, duration?: number): Promise<boolean>; /** * Update an Access device's configuration on the UniFi Access controller. * * @typeParam DeviceType - Generic for any known Access device type. * * @param device - Access device. * @param payload - Device configuration payload to upload, usually a subset of the device-specific configuration JSON. * * @returns Returns a promise that will resolve to the updated device-specific configuration JSON if successful, and `null` otherwise. * * @remarks Use this method to change the configuration of a given Access device or controller. It requires the credentials used to login to the Access API * to have administrative privileges for most settings. */ updateDevice<DeviceType extends AccessDeviceConfig>(device: DeviceType, payload: AccessDeviceConfigPayload): Promise<DeviceType | null>; /** * Utility method that generates a nicely formatted device information string. * * @param device - Access device. * @param name - Optional name for the device. Defaults to the device type (e.g. `UA G2 Pro Black`). * @param deviceInfo - Optionally specify whether or not to include the IP address and MAC address in the returned string. Defaults to `false`. * * @returns Returns the Access device name in the following format: <code>*Access device name* [*Access device type*] (address: *IP address* mac: *MAC address*)</code>. * * @remarks The example above assumed the `deviceInfo` parameter is set to `true`. */ getDeviceName(device: AccessDeviceConfig, name?: string, deviceInfo?: boolean): string; /** * Utility method that generates a combined, nicely formatted device and controller string. * * @param device - Access device. * * @returns Returns the Access device name in the following format: * <code>*Access controller name* [*Access controller type*] *Access device name* [*Access device type*]</code>. */ getFullName(device: AccessDeviceConfig): string; /** * Terminate any open connection to the UniFi Access API. */ reset(): void; /** * Clear the login credentials and terminate any open connection to the UniFi Access API. */ logout(): void; /** * Execute an HTTP fetch request to the Access controller. * * @param url - Requested endpoint type. Valid types are `livestream` and `talkback`. * @param options - Parameters to pass on for the endpoint request. * @param logErrors - Log errors that aren't already accounted for and handled, rather than failing silently. Defaults to `true`. * * @returns Returns a promise that will resolve to a Response object successful, and `null` otherwise. * * @remarks This method should be used when direct access to the Access controller is needed, or when this library doesn't have a needed method to access * controller capabilities. */ retrieve(url: string, options?: RequestOptions, logErrors?: boolean): Promise<Response | null>; private _retrieve; private logRetry; /** * Return an API endpoint for the requested endpoint type. * * @param endpoint - Requested endpoint type. * * @returns Returns a URL to the requested endpoint if successful, and an empty string otherwise. * * @remarks Valid API endpoints are `bootstrap`, `device`, `login`, `self`, and `websocket`. */ getApiEndpoint(endpoint: string): string; /** * Access the Access controller information JSON. * * @returns Returns the controller information JSON if the Access controller has been bootstrapped, `null` otherwise. */ get controller(): AccessControllerConfig | null; /** * Access the Access controller bootstrap JSON. * * @returns Returns the bootstrap JSON if the Access controller has been bootstrapped, `null` otherwise. */ get bootstrap(): AccessBootstrapConfig | null; /** * Access the Access controller list of devices. * * @returns Returns an array of all the devices from all the UniFi Access hubs associated with this controller, `null` otherwise. */ get devices(): AccessDeviceConfig[] | null; /** * Access the Access controller list of doors. * * @returns Returns an array of all the doors from all the UniFi Access hubs associated with this controller, `null` otherwise. */ get doors(): AccessDoorConfig[] | null; /** * Access the Access controller list of floors. * * @returns Returns an array of all the floors from all the UniFi Access hubs associated with this controller, `null` otherwise. */ get floors(): AccessFloorConfig[] | null; /** * Utility method that returns whether the credentials that were used to login to the Access controller have administrative privileges or not. * * @returns Returns `true` if the logged in user has administrative privileges, `false` otherwise. */ get isAdminUser(): boolean; /** * Utility method that returns a nicely formatted version of the Access controller name. * * @returns Returns the Access controller name in the following format: * <code>*Access controller name* [*Access controller type*]</code>. */ get name(): string; }