169 lines
4.3 KiB
TypeScript
169 lines
4.3 KiB
TypeScript
|
|
import type { UnifiAccess } from './classes.unifi-access.js';
|
||
|
|
import { UnifiDoor } from './classes.door.js';
|
||
|
|
import type { IAccessDoor, IAccessApiResponse, IAccessEvent } from './interfaces/index.js';
|
||
|
|
import { logger } from './unifi.logger.js';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Manager for UniFi Access doors
|
||
|
|
*/
|
||
|
|
export class DoorManager {
|
||
|
|
private access: UnifiAccess;
|
||
|
|
|
||
|
|
constructor(access: UnifiAccess) {
|
||
|
|
this.access = access;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* List all doors
|
||
|
|
*/
|
||
|
|
public async listDoors(): Promise<UnifiDoor[]> {
|
||
|
|
logger.log('debug', 'Fetching doors from Access');
|
||
|
|
|
||
|
|
const response = await this.access.request<IAccessApiResponse<IAccessDoor[]>>(
|
||
|
|
'GET',
|
||
|
|
'/door'
|
||
|
|
);
|
||
|
|
|
||
|
|
const doors: UnifiDoor[] = [];
|
||
|
|
for (const doorData of response.data || []) {
|
||
|
|
doors.push(UnifiDoor.createFromApiObject(doorData, this.access));
|
||
|
|
}
|
||
|
|
|
||
|
|
logger.log('info', `Found ${doors.length} doors`);
|
||
|
|
return doors;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get a door by ID
|
||
|
|
*/
|
||
|
|
public async getDoorById(doorId: string): Promise<UnifiDoor | null> {
|
||
|
|
logger.log('debug', `Fetching door: ${doorId}`);
|
||
|
|
|
||
|
|
try {
|
||
|
|
const response = await this.access.request<IAccessApiResponse<IAccessDoor>>(
|
||
|
|
'GET',
|
||
|
|
`/door/${doorId}`
|
||
|
|
);
|
||
|
|
|
||
|
|
return UnifiDoor.createFromApiObject(response.data, this.access);
|
||
|
|
} catch (error) {
|
||
|
|
logger.log('warn', `Door not found: ${doorId}`);
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Find a door by name
|
||
|
|
*/
|
||
|
|
public async getDoorByName(name: string): Promise<UnifiDoor | null> {
|
||
|
|
const doors = await this.listDoors();
|
||
|
|
return doors.find(
|
||
|
|
(door) =>
|
||
|
|
door.name.toLowerCase() === name.toLowerCase() ||
|
||
|
|
door.alias?.toLowerCase() === name.toLowerCase()
|
||
|
|
) || null;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get locked doors only
|
||
|
|
*/
|
||
|
|
public async getLockedDoors(): Promise<UnifiDoor[]> {
|
||
|
|
const doors = await this.listDoors();
|
||
|
|
return doors.filter((door) => door.isLocked());
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get unlocked doors only
|
||
|
|
*/
|
||
|
|
public async getUnlockedDoors(): Promise<UnifiDoor[]> {
|
||
|
|
const doors = await this.listDoors();
|
||
|
|
return doors.filter((door) => !door.isLocked());
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get open doors only
|
||
|
|
*/
|
||
|
|
public async getOpenDoors(): Promise<UnifiDoor[]> {
|
||
|
|
const doors = await this.listDoors();
|
||
|
|
return doors.filter((door) => door.isOpen());
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get doors by location
|
||
|
|
*/
|
||
|
|
public async getDoorsByLocation(locationId: string): Promise<UnifiDoor[]> {
|
||
|
|
const doors = await this.listDoors();
|
||
|
|
return doors.filter((door) => door.location_id === locationId);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Unlock a door by ID
|
||
|
|
*/
|
||
|
|
public async unlockDoor(doorId: string): Promise<void> {
|
||
|
|
logger.log('info', `Unlocking door: ${doorId}`);
|
||
|
|
|
||
|
|
await this.access.request('PUT', `/door/${doorId}/unlock`);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Lock a door by ID
|
||
|
|
*/
|
||
|
|
public async lockDoor(doorId: string): Promise<void> {
|
||
|
|
logger.log('info', `Locking door: ${doorId}`);
|
||
|
|
|
||
|
|
await this.access.request('PUT', `/door/${doorId}/lock`);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Unlock all doors
|
||
|
|
*/
|
||
|
|
public async unlockAllDoors(): Promise<void> {
|
||
|
|
logger.log('info', 'Unlocking all doors');
|
||
|
|
|
||
|
|
const doors = await this.listDoors();
|
||
|
|
await Promise.all(doors.map((door) => this.unlockDoor(door.unique_id)));
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Lock all doors
|
||
|
|
*/
|
||
|
|
public async lockAllDoors(): Promise<void> {
|
||
|
|
logger.log('info', 'Locking all doors');
|
||
|
|
|
||
|
|
const doors = await this.listDoors();
|
||
|
|
await Promise.all(doors.map((door) => this.lockDoor(door.unique_id)));
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get access events for a door
|
||
|
|
*/
|
||
|
|
public async getDoorEvents(
|
||
|
|
doorId: string,
|
||
|
|
options: { start?: number; end?: number; limit?: number } = {}
|
||
|
|
): Promise<IAccessEvent[]> {
|
||
|
|
logger.log('debug', `Fetching events for door: ${doorId}`);
|
||
|
|
|
||
|
|
const params = new URLSearchParams();
|
||
|
|
params.append('door_id', doorId);
|
||
|
|
if (options.start) params.append('start', options.start.toString());
|
||
|
|
if (options.end) params.append('end', options.end.toString());
|
||
|
|
if (options.limit) params.append('limit', options.limit.toString());
|
||
|
|
|
||
|
|
const response = await this.access.request<IAccessApiResponse<IAccessEvent[]>>(
|
||
|
|
'GET',
|
||
|
|
`/event?${params.toString()}`
|
||
|
|
);
|
||
|
|
|
||
|
|
return response.data || [];
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Update door settings
|
||
|
|
*/
|
||
|
|
public async updateDoor(doorId: string, settings: Partial<IAccessDoor>): Promise<void> {
|
||
|
|
logger.log('info', `Updating door: ${doorId}`);
|
||
|
|
|
||
|
|
await this.access.request('PUT', `/door/${doorId}`, settings);
|
||
|
|
}
|
||
|
|
}
|