Files
devicemanager/ts/features/feature.power.ts

232 lines
6.3 KiB
TypeScript
Raw Normal View History

/**
* Power Feature
* Provides UPS/power monitoring and control capability
*/
import { Feature, type TDeviceReference } from './feature.abstract.js';
import type {
TPowerProtocol,
TPowerStatus,
IBatteryInfo,
IPowerInfo,
IPowerFeatureInfo,
IFeatureOptions,
} from '../interfaces/feature.interfaces.js';
/**
* Options for creating a PowerFeature
*/
export interface IPowerFeatureOptions extends IFeatureOptions {
protocol: TPowerProtocol;
hasBattery?: boolean;
supportsShutdown?: boolean;
supportsTest?: boolean;
/** For NUT protocol: UPS name */
upsName?: string;
/** For SNMP: community string */
community?: string;
}
/**
* Power Feature - provides UPS/power monitoring and control
*
* Supports NUT (Network UPS Tools) and SNMP protocols for monitoring
* UPS devices and smart power equipment.
*
* @example
* ```typescript
* const power = device.getFeature<PowerFeature>('power');
* if (power) {
* const status = await power.getStatus();
* const battery = await power.getBatteryInfo();
* console.log(`Status: ${status}, Battery: ${battery.charge}%`);
* }
* ```
*/
export class PowerFeature extends Feature {
public readonly type = 'power' as const;
public readonly protocol: TPowerProtocol;
// Configuration
public readonly upsName: string;
public readonly community: string;
// Capabilities
public readonly hasBattery: boolean;
public readonly supportsShutdown: boolean;
public readonly supportsTest: boolean;
// Current state
protected _status: TPowerStatus = 'unknown';
protected _batteryCharge: number = 0;
protected _batteryRuntime: number = 0;
protected _load: number = 0;
constructor(
device: TDeviceReference,
port: number,
options: IPowerFeatureOptions
) {
super(device, port, options);
this.protocol = options.protocol;
this.upsName = options.upsName ?? 'ups';
this.community = options.community ?? 'public';
this.hasBattery = options.hasBattery ?? true;
this.supportsShutdown = options.supportsShutdown ?? false;
this.supportsTest = options.supportsTest ?? false;
}
// ============================================================================
// Properties
// ============================================================================
public get powerStatus(): TPowerStatus {
return this._status;
}
public get batteryCharge(): number {
return this._batteryCharge;
}
public get batteryRuntime(): number {
return this._batteryRuntime;
}
public get load(): number {
return this._load;
}
// ============================================================================
// Connection
// ============================================================================
protected async doConnect(): Promise<void> {
// Protocol-specific connection would be implemented here
// For now, just verify the port is reachable
}
protected async doDisconnect(): Promise<void> {
// Protocol-specific disconnection
}
// ============================================================================
// Status Monitoring
// ============================================================================
/**
* Get current power status
*/
public async getStatus(): Promise<TPowerStatus> {
// Protocol-specific implementation would fetch status
return this._status;
}
/**
* Get battery information
*/
public async getBatteryInfo(): Promise<IBatteryInfo> {
return {
charge: this._batteryCharge,
runtime: this._batteryRuntime,
};
}
/**
* Get power information
*/
public async getPowerInfo(): Promise<IPowerInfo> {
return {
load: this._load,
};
}
// ============================================================================
// Control Commands
// ============================================================================
/**
* Initiate shutdown
*/
public async shutdown(delay?: number): Promise<void> {
if (!this.supportsShutdown) {
throw new Error('Shutdown not supported');
}
this.emit('power:shutdown', { delay });
}
/**
* Start battery test
*/
public async testBattery(): Promise<void> {
if (!this.supportsTest) {
throw new Error('Battery test not supported');
}
this.emit('power:test:started');
}
// ============================================================================
// State Updates
// ============================================================================
protected updateStatus(status: TPowerStatus): void {
const oldStatus = this._status;
this._status = status;
if (oldStatus !== status) {
this.emit('power:status:changed', { oldStatus, newStatus: status });
// Emit specific events
if (status === 'onbattery') {
this.emit('power:onbattery');
} else if (status === 'online' && oldStatus === 'onbattery') {
this.emit('power:restored');
} else if (status === 'lowbattery') {
this.emit('power:lowbattery');
}
}
}
protected updateBattery(charge: number, runtime: number): void {
const oldCharge = this._batteryCharge;
this._batteryCharge = charge;
this._batteryRuntime = runtime;
if (oldCharge !== charge) {
this.emit('battery:changed', { charge, runtime });
}
}
// ============================================================================
// Serialization
// ============================================================================
public getFeatureInfo(): IPowerFeatureInfo {
return {
...this.getBaseFeatureInfo(),
type: 'power',
protocol: this.protocol,
hasBattery: this.hasBattery,
supportsShutdown: this.supportsShutdown,
supportsTest: this.supportsTest,
};
}
// ============================================================================
// Static Factory
// ============================================================================
public static fromDiscovery(
device: TDeviceReference,
port: number,
protocol: TPowerProtocol,
metadata: Record<string, unknown>
): PowerFeature {
return new PowerFeature(device, port, {
protocol,
upsName: metadata.upsName as string,
hasBattery: metadata.hasBattery as boolean ?? true,
supportsShutdown: metadata.supportsShutdown as boolean ?? false,
supportsTest: metadata.supportsTest as boolean ?? false,
});
}
}