import type { UnifiController } from './classes.unifi-controller.js'; import type { INetworkDevice, IPortConfig } from './interfaces/index.js'; /** * Represents a UniFi network device (AP, switch, gateway, etc.) */ export class UnifiDevice implements INetworkDevice { /** Reference to parent controller */ private controller?: UnifiController; /** Site ID for API calls */ private siteId?: string; // INetworkDevice properties public _id: string; public mac: string; public model: string; public type: string; public name?: string; public site_id: string; public adopted: boolean; public ip: string; public state: number; public serial?: string; public version?: string; public uptime?: number; public last_seen?: number; public upgradable?: boolean; public upgrade_to_firmware?: string; public config_network?: { type?: string; ip?: string; }; public ethernet_table?: Array<{ name: string; mac: string; num_port?: number; }>; public port_overrides?: Array<{ port_idx: number; name?: string; poe_mode?: string; }>; public sys_stats?: { loadavg_1?: number; loadavg_5?: number; loadavg_15?: number; mem_total?: number; mem_used?: number; }; public led_override?: string; public led_override_color?: string; public led_override_color_brightness?: number; constructor() { this._id = ''; this.mac = ''; this.model = ''; this.type = ''; this.site_id = ''; this.adopted = false; this.ip = ''; this.state = 0; } /** * Create a device instance from API response object */ public static createFromApiObject( apiObject: INetworkDevice, controller?: UnifiController, siteId?: string ): UnifiDevice { const device = new UnifiDevice(); Object.assign(device, apiObject); device.controller = controller; device.siteId = siteId || apiObject.site_id; return device; } /** * Get the raw API object representation */ public toApiObject(): INetworkDevice { return { _id: this._id, mac: this.mac, model: this.model, type: this.type, name: this.name, site_id: this.site_id, adopted: this.adopted, ip: this.ip, state: this.state, serial: this.serial, version: this.version, uptime: this.uptime, last_seen: this.last_seen, upgradable: this.upgradable, upgrade_to_firmware: this.upgrade_to_firmware, config_network: this.config_network, ethernet_table: this.ethernet_table, port_overrides: this.port_overrides, sys_stats: this.sys_stats, led_override: this.led_override, led_override_color: this.led_override_color, led_override_color_brightness: this.led_override_color_brightness, }; } /** * Check if device is online (state 1 = connected) */ public isOnline(): boolean { return this.state === 1; } /** * Check if device is an access point */ public isAccessPoint(): boolean { return this.type === 'uap'; } /** * Check if device is a switch */ public isSwitch(): boolean { return this.type === 'usw'; } /** * Check if device is a gateway/router */ public isGateway(): boolean { return this.type === 'ugw' || this.type === 'udm'; } /** * Check if device has available firmware upgrade */ public hasUpgrade(): boolean { return this.upgradable === true && !!this.upgrade_to_firmware; } /** * Get device display name (name or MAC if no name) */ public getDisplayName(): string { return this.name || this.mac; } /** * Restart the device */ public async restart(): Promise { if (!this.controller || !this.siteId) { throw new Error('Cannot restart device: no controller reference'); } await this.controller.request( 'POST', `/api/s/${this.siteId}/cmd/devmgr`, { cmd: 'restart', mac: this.mac, } ); } /** * Upgrade the device firmware */ public async upgrade(): Promise { if (!this.controller || !this.siteId) { throw new Error('Cannot upgrade device: no controller reference'); } await this.controller.request( 'POST', `/api/s/${this.siteId}/cmd/devmgr`, { cmd: 'upgrade', mac: this.mac, } ); } /** * Set LED override */ public async setLedOverride(mode: 'default' | 'on' | 'off'): Promise { if (!this.controller || !this.siteId) { throw new Error('Cannot set LED: no controller reference'); } await this.controller.request( 'PUT', `/api/s/${this.siteId}/rest/device/${this._id}`, { led_override: mode, } ); } /** * Rename the device */ public async rename(newName: string): Promise { if (!this.controller || !this.siteId) { throw new Error('Cannot rename device: no controller reference'); } await this.controller.request( 'PUT', `/api/s/${this.siteId}/rest/device/${this._id}`, { name: newName, } ); this.name = newName; } /** * Set port configuration */ public async setPortConfig(portIdx: number, config: Partial): Promise { if (!this.controller || !this.siteId) { throw new Error('Cannot set port config: no controller reference'); } const portOverride = { port_idx: portIdx, ...config, }; // Get existing port overrides and update const existingOverrides = this.port_overrides || []; const overrideIndex = existingOverrides.findIndex((p) => p.port_idx === portIdx); if (overrideIndex >= 0) { existingOverrides[overrideIndex] = { ...existingOverrides[overrideIndex], ...portOverride }; } else { existingOverrides.push(portOverride); } await this.controller.request( 'PUT', `/api/s/${this.siteId}/rest/device/${this._id}`, { port_overrides: existingOverrides, } ); } }