Files
unifi/ts/classes.device.ts

256 lines
5.9 KiB
TypeScript

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<void> {
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<void> {
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<void> {
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<void> {
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<IPortConfig>): Promise<void> {
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,
}
);
}
}