@jw988/unifi-access
Version:
A soon-to-be-almost-complete implementation of the UniFi Access API.
323 lines (322 loc) • 14.1 kB
TypeScript
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;
}