initial
This commit is contained in:
377
ts/ups/ups.classes.upssnmp.ts
Normal file
377
ts/ups/ups.classes.upssnmp.ts
Normal file
@@ -0,0 +1,377 @@
|
||||
import { SnmpProtocol, SNMP_OIDS, type ISnmpOptions } from '../snmp/snmp.classes.snmpprotocol.js';
|
||||
|
||||
/**
|
||||
* Extended UPS-MIB OIDs (RFC 1628)
|
||||
*/
|
||||
export const UPS_SNMP_OIDS = {
|
||||
// Identity
|
||||
upsIdentManufacturer: '1.3.6.1.2.1.33.1.1.1.0',
|
||||
upsIdentModel: '1.3.6.1.2.1.33.1.1.2.0',
|
||||
upsIdentUPSSoftwareVersion: '1.3.6.1.2.1.33.1.1.3.0',
|
||||
upsIdentAgentSoftwareVersion: '1.3.6.1.2.1.33.1.1.4.0',
|
||||
upsIdentName: '1.3.6.1.2.1.33.1.1.5.0',
|
||||
upsIdentAttachedDevices: '1.3.6.1.2.1.33.1.1.6.0',
|
||||
|
||||
// Battery group
|
||||
upsBatteryStatus: '1.3.6.1.2.1.33.1.2.1.0',
|
||||
upsSecondsOnBattery: '1.3.6.1.2.1.33.1.2.2.0',
|
||||
upsEstimatedMinutesRemaining: '1.3.6.1.2.1.33.1.2.3.0',
|
||||
upsEstimatedChargeRemaining: '1.3.6.1.2.1.33.1.2.4.0',
|
||||
upsBatteryVoltage: '1.3.6.1.2.1.33.1.2.5.0',
|
||||
upsBatteryCurrent: '1.3.6.1.2.1.33.1.2.6.0',
|
||||
upsBatteryTemperature: '1.3.6.1.2.1.33.1.2.7.0',
|
||||
|
||||
// Input group
|
||||
upsInputLineBads: '1.3.6.1.2.1.33.1.3.1.0',
|
||||
upsInputNumLines: '1.3.6.1.2.1.33.1.3.2.0',
|
||||
upsInputLineIndex: '1.3.6.1.2.1.33.1.3.3.1.1',
|
||||
upsInputFrequency: '1.3.6.1.2.1.33.1.3.3.1.2',
|
||||
upsInputVoltage: '1.3.6.1.2.1.33.1.3.3.1.3',
|
||||
upsInputCurrent: '1.3.6.1.2.1.33.1.3.3.1.4',
|
||||
upsInputTruePower: '1.3.6.1.2.1.33.1.3.3.1.5',
|
||||
|
||||
// Output group
|
||||
upsOutputSource: '1.3.6.1.2.1.33.1.4.1.0',
|
||||
upsOutputFrequency: '1.3.6.1.2.1.33.1.4.2.0',
|
||||
upsOutputNumLines: '1.3.6.1.2.1.33.1.4.3.0',
|
||||
upsOutputLineIndex: '1.3.6.1.2.1.33.1.4.4.1.1',
|
||||
upsOutputVoltage: '1.3.6.1.2.1.33.1.4.4.1.2',
|
||||
upsOutputCurrent: '1.3.6.1.2.1.33.1.4.4.1.3',
|
||||
upsOutputPower: '1.3.6.1.2.1.33.1.4.4.1.4',
|
||||
upsOutputPercentLoad: '1.3.6.1.2.1.33.1.4.4.1.5',
|
||||
|
||||
// Bypass group
|
||||
upsBypassFrequency: '1.3.6.1.2.1.33.1.5.1.0',
|
||||
upsBypassNumLines: '1.3.6.1.2.1.33.1.5.2.0',
|
||||
|
||||
// Alarm group
|
||||
upsAlarmsPresent: '1.3.6.1.2.1.33.1.6.1.0',
|
||||
|
||||
// Test group
|
||||
upsTestId: '1.3.6.1.2.1.33.1.7.1.0',
|
||||
upsTestSpinLock: '1.3.6.1.2.1.33.1.7.2.0',
|
||||
upsTestResultsSummary: '1.3.6.1.2.1.33.1.7.3.0',
|
||||
upsTestResultsDetail: '1.3.6.1.2.1.33.1.7.4.0',
|
||||
upsTestStartTime: '1.3.6.1.2.1.33.1.7.5.0',
|
||||
upsTestElapsedTime: '1.3.6.1.2.1.33.1.7.6.0',
|
||||
|
||||
// Control group
|
||||
upsShutdownType: '1.3.6.1.2.1.33.1.8.1.0',
|
||||
upsShutdownAfterDelay: '1.3.6.1.2.1.33.1.8.2.0',
|
||||
upsStartupAfterDelay: '1.3.6.1.2.1.33.1.8.3.0',
|
||||
upsRebootWithDuration: '1.3.6.1.2.1.33.1.8.4.0',
|
||||
upsAutoRestart: '1.3.6.1.2.1.33.1.8.5.0',
|
||||
|
||||
// Config group
|
||||
upsConfigInputVoltage: '1.3.6.1.2.1.33.1.9.1.0',
|
||||
upsConfigInputFreq: '1.3.6.1.2.1.33.1.9.2.0',
|
||||
upsConfigOutputVoltage: '1.3.6.1.2.1.33.1.9.3.0',
|
||||
upsConfigOutputFreq: '1.3.6.1.2.1.33.1.9.4.0',
|
||||
upsConfigOutputVA: '1.3.6.1.2.1.33.1.9.5.0',
|
||||
upsConfigOutputPower: '1.3.6.1.2.1.33.1.9.6.0',
|
||||
upsConfigLowBattTime: '1.3.6.1.2.1.33.1.9.7.0',
|
||||
upsConfigAudibleStatus: '1.3.6.1.2.1.33.1.9.8.0',
|
||||
upsConfigLowVoltageTransferPoint: '1.3.6.1.2.1.33.1.9.9.0',
|
||||
upsConfigHighVoltageTransferPoint: '1.3.6.1.2.1.33.1.9.10.0',
|
||||
};
|
||||
|
||||
/**
|
||||
* Battery status values from UPS-MIB
|
||||
*/
|
||||
export type TUpsBatteryStatus =
|
||||
| 'unknown'
|
||||
| 'batteryNormal'
|
||||
| 'batteryLow'
|
||||
| 'batteryDepleted';
|
||||
|
||||
/**
|
||||
* Output source values from UPS-MIB
|
||||
*/
|
||||
export type TUpsOutputSource =
|
||||
| 'other'
|
||||
| 'none'
|
||||
| 'normal'
|
||||
| 'bypass'
|
||||
| 'battery'
|
||||
| 'booster'
|
||||
| 'reducer';
|
||||
|
||||
/**
|
||||
* Test results summary from UPS-MIB
|
||||
*/
|
||||
export type TUpsTestResult =
|
||||
| 'donePass'
|
||||
| 'doneWarning'
|
||||
| 'doneError'
|
||||
| 'aborted'
|
||||
| 'inProgress'
|
||||
| 'noTestsInitiated';
|
||||
|
||||
/**
|
||||
* SNMP-based UPS status interface
|
||||
*/
|
||||
export interface IUpsSnmpStatus {
|
||||
batteryStatus: TUpsBatteryStatus;
|
||||
secondsOnBattery: number;
|
||||
estimatedMinutesRemaining: number;
|
||||
estimatedChargeRemaining: number;
|
||||
batteryVoltage: number;
|
||||
batteryTemperature: number;
|
||||
outputSource: TUpsOutputSource;
|
||||
outputFrequency: number;
|
||||
outputVoltage: number;
|
||||
outputCurrent: number;
|
||||
outputPower: number;
|
||||
outputPercentLoad: number;
|
||||
inputFrequency: number;
|
||||
inputVoltage: number;
|
||||
alarmsPresent: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* UPS SNMP handler for querying UPS devices via SNMP
|
||||
*/
|
||||
export class UpsSnmpHandler {
|
||||
private protocol: SnmpProtocol;
|
||||
|
||||
constructor(address: string, options?: ISnmpOptions) {
|
||||
this.protocol = new SnmpProtocol(address, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close SNMP session
|
||||
*/
|
||||
public close(): void {
|
||||
this.protocol.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get UPS identity information
|
||||
*/
|
||||
public async getIdentity(): Promise<{
|
||||
manufacturer: string;
|
||||
model: string;
|
||||
softwareVersion: string;
|
||||
name: string;
|
||||
}> {
|
||||
const varbinds = await this.protocol.getMultiple([
|
||||
UPS_SNMP_OIDS.upsIdentManufacturer,
|
||||
UPS_SNMP_OIDS.upsIdentModel,
|
||||
UPS_SNMP_OIDS.upsIdentUPSSoftwareVersion,
|
||||
UPS_SNMP_OIDS.upsIdentName,
|
||||
]);
|
||||
|
||||
const getValue = (oid: string): string => {
|
||||
const vb = varbinds.find((v) => v.oid === oid);
|
||||
return String(vb?.value || '');
|
||||
};
|
||||
|
||||
return {
|
||||
manufacturer: getValue(UPS_SNMP_OIDS.upsIdentManufacturer),
|
||||
model: getValue(UPS_SNMP_OIDS.upsIdentModel),
|
||||
softwareVersion: getValue(UPS_SNMP_OIDS.upsIdentUPSSoftwareVersion),
|
||||
name: getValue(UPS_SNMP_OIDS.upsIdentName),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get battery status
|
||||
*/
|
||||
public async getBatteryStatus(): Promise<{
|
||||
status: TUpsBatteryStatus;
|
||||
secondsOnBattery: number;
|
||||
estimatedMinutesRemaining: number;
|
||||
estimatedChargeRemaining: number;
|
||||
voltage: number;
|
||||
temperature: number;
|
||||
}> {
|
||||
const varbinds = await this.protocol.getMultiple([
|
||||
UPS_SNMP_OIDS.upsBatteryStatus,
|
||||
UPS_SNMP_OIDS.upsSecondsOnBattery,
|
||||
UPS_SNMP_OIDS.upsEstimatedMinutesRemaining,
|
||||
UPS_SNMP_OIDS.upsEstimatedChargeRemaining,
|
||||
UPS_SNMP_OIDS.upsBatteryVoltage,
|
||||
UPS_SNMP_OIDS.upsBatteryTemperature,
|
||||
]);
|
||||
|
||||
const getValue = (oid: string): number => {
|
||||
const vb = varbinds.find((v) => v.oid === oid);
|
||||
return Number(vb?.value || 0);
|
||||
};
|
||||
|
||||
const statusMap: Record<number, TUpsBatteryStatus> = {
|
||||
1: 'unknown',
|
||||
2: 'batteryNormal',
|
||||
3: 'batteryLow',
|
||||
4: 'batteryDepleted',
|
||||
};
|
||||
|
||||
return {
|
||||
status: statusMap[getValue(UPS_SNMP_OIDS.upsBatteryStatus)] || 'unknown',
|
||||
secondsOnBattery: getValue(UPS_SNMP_OIDS.upsSecondsOnBattery),
|
||||
estimatedMinutesRemaining: getValue(UPS_SNMP_OIDS.upsEstimatedMinutesRemaining),
|
||||
estimatedChargeRemaining: getValue(UPS_SNMP_OIDS.upsEstimatedChargeRemaining),
|
||||
voltage: getValue(UPS_SNMP_OIDS.upsBatteryVoltage) / 10, // Typically in 0.1V units
|
||||
temperature: getValue(UPS_SNMP_OIDS.upsBatteryTemperature),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get input status
|
||||
*/
|
||||
public async getInputStatus(): Promise<{
|
||||
frequency: number;
|
||||
voltage: number;
|
||||
lineBads: number;
|
||||
}> {
|
||||
const varbinds = await this.protocol.getMultiple([
|
||||
UPS_SNMP_OIDS.upsInputFrequency + '.1', // Line 1
|
||||
UPS_SNMP_OIDS.upsInputVoltage + '.1', // Line 1
|
||||
UPS_SNMP_OIDS.upsInputLineBads,
|
||||
]);
|
||||
|
||||
const getValue = (oid: string): number => {
|
||||
const vb = varbinds.find((v) => v.oid === oid);
|
||||
return Number(vb?.value || 0);
|
||||
};
|
||||
|
||||
return {
|
||||
frequency: getValue(UPS_SNMP_OIDS.upsInputFrequency + '.1') / 10, // 0.1 Hz units
|
||||
voltage: getValue(UPS_SNMP_OIDS.upsInputVoltage + '.1'),
|
||||
lineBads: getValue(UPS_SNMP_OIDS.upsInputLineBads),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get output status
|
||||
*/
|
||||
public async getOutputStatus(): Promise<{
|
||||
source: TUpsOutputSource;
|
||||
frequency: number;
|
||||
voltage: number;
|
||||
current: number;
|
||||
power: number;
|
||||
percentLoad: number;
|
||||
}> {
|
||||
const varbinds = await this.protocol.getMultiple([
|
||||
UPS_SNMP_OIDS.upsOutputSource,
|
||||
UPS_SNMP_OIDS.upsOutputFrequency,
|
||||
UPS_SNMP_OIDS.upsOutputVoltage + '.1', // Line 1
|
||||
UPS_SNMP_OIDS.upsOutputCurrent + '.1', // Line 1
|
||||
UPS_SNMP_OIDS.upsOutputPower + '.1', // Line 1
|
||||
UPS_SNMP_OIDS.upsOutputPercentLoad + '.1', // Line 1
|
||||
]);
|
||||
|
||||
const getValue = (oid: string): number => {
|
||||
const vb = varbinds.find((v) => v.oid === oid);
|
||||
return Number(vb?.value || 0);
|
||||
};
|
||||
|
||||
const sourceMap: Record<number, TUpsOutputSource> = {
|
||||
1: 'other',
|
||||
2: 'none',
|
||||
3: 'normal',
|
||||
4: 'bypass',
|
||||
5: 'battery',
|
||||
6: 'booster',
|
||||
7: 'reducer',
|
||||
};
|
||||
|
||||
return {
|
||||
source: sourceMap[getValue(UPS_SNMP_OIDS.upsOutputSource)] || 'other',
|
||||
frequency: getValue(UPS_SNMP_OIDS.upsOutputFrequency) / 10, // 0.1 Hz units
|
||||
voltage: getValue(UPS_SNMP_OIDS.upsOutputVoltage + '.1'),
|
||||
current: getValue(UPS_SNMP_OIDS.upsOutputCurrent + '.1') / 10, // 0.1 A units
|
||||
power: getValue(UPS_SNMP_OIDS.upsOutputPower + '.1'),
|
||||
percentLoad: getValue(UPS_SNMP_OIDS.upsOutputPercentLoad + '.1'),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get full UPS status
|
||||
*/
|
||||
public async getFullStatus(): Promise<IUpsSnmpStatus> {
|
||||
const [battery, input, output] = await Promise.all([
|
||||
this.getBatteryStatus(),
|
||||
this.getInputStatus(),
|
||||
this.getOutputStatus(),
|
||||
]);
|
||||
|
||||
// Get alarms separately
|
||||
let alarmsPresent = 0;
|
||||
try {
|
||||
const alarmVb = await this.protocol.get(UPS_SNMP_OIDS.upsAlarmsPresent);
|
||||
alarmsPresent = Number(alarmVb.value || 0);
|
||||
} catch {
|
||||
// Ignore alarm fetch errors
|
||||
}
|
||||
|
||||
return {
|
||||
batteryStatus: battery.status,
|
||||
secondsOnBattery: battery.secondsOnBattery,
|
||||
estimatedMinutesRemaining: battery.estimatedMinutesRemaining,
|
||||
estimatedChargeRemaining: battery.estimatedChargeRemaining,
|
||||
batteryVoltage: battery.voltage,
|
||||
batteryTemperature: battery.temperature,
|
||||
outputSource: output.source,
|
||||
outputFrequency: output.frequency,
|
||||
outputVoltage: output.voltage,
|
||||
outputCurrent: output.current,
|
||||
outputPower: output.power,
|
||||
outputPercentLoad: output.percentLoad,
|
||||
inputFrequency: input.frequency,
|
||||
inputVoltage: input.voltage,
|
||||
alarmsPresent,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if UPS-MIB is supported on device
|
||||
*/
|
||||
public async isUpsDevice(): Promise<boolean> {
|
||||
try {
|
||||
const vb = await this.protocol.get(UPS_SNMP_OIDS.upsBatteryStatus);
|
||||
return vb.value !== null && vb.value !== undefined;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get configuration info
|
||||
*/
|
||||
public async getConfiguration(): Promise<{
|
||||
inputVoltage: number;
|
||||
inputFrequency: number;
|
||||
outputVoltage: number;
|
||||
outputFrequency: number;
|
||||
outputVA: number;
|
||||
outputPower: number;
|
||||
lowBatteryTime: number;
|
||||
}> {
|
||||
const varbinds = await this.protocol.getMultiple([
|
||||
UPS_SNMP_OIDS.upsConfigInputVoltage,
|
||||
UPS_SNMP_OIDS.upsConfigInputFreq,
|
||||
UPS_SNMP_OIDS.upsConfigOutputVoltage,
|
||||
UPS_SNMP_OIDS.upsConfigOutputFreq,
|
||||
UPS_SNMP_OIDS.upsConfigOutputVA,
|
||||
UPS_SNMP_OIDS.upsConfigOutputPower,
|
||||
UPS_SNMP_OIDS.upsConfigLowBattTime,
|
||||
]);
|
||||
|
||||
const getValue = (oid: string): number => {
|
||||
const vb = varbinds.find((v) => v.oid === oid);
|
||||
return Number(vb?.value || 0);
|
||||
};
|
||||
|
||||
return {
|
||||
inputVoltage: getValue(UPS_SNMP_OIDS.upsConfigInputVoltage),
|
||||
inputFrequency: getValue(UPS_SNMP_OIDS.upsConfigInputFreq) / 10,
|
||||
outputVoltage: getValue(UPS_SNMP_OIDS.upsConfigOutputVoltage),
|
||||
outputFrequency: getValue(UPS_SNMP_OIDS.upsConfigOutputFreq) / 10,
|
||||
outputVA: getValue(UPS_SNMP_OIDS.upsConfigOutputVA),
|
||||
outputPower: getValue(UPS_SNMP_OIDS.upsConfigOutputPower),
|
||||
lowBatteryTime: getValue(UPS_SNMP_OIDS.upsConfigLowBattTime),
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user