feat(snmp): Enhance SNMP metrics with output load, power, voltage, and current readings

This commit is contained in:
2025-10-23 12:25:59 +00:00
parent 9ba50da73c
commit fbe1cd64cb
5 changed files with 166 additions and 2 deletions

View File

@@ -2,6 +2,7 @@
"name": "@serve.zone/nupst", "name": "@serve.zone/nupst",
"version": "5.0.5", "version": "5.0.5",
"exports": "./mod.ts", "exports": "./mod.ts",
"nodeModulesDir": "auto",
"tasks": { "tasks": {
"dev": "deno run --allow-all mod.ts", "dev": "deno run --allow-all mod.ts",
"compile": "deno task compile:all", "compile": "deno task compile:all",

View File

@@ -58,5 +58,6 @@
"publishConfig": { "publishConfig": {
"access": "public", "access": "public",
"registry": "https://registry.npmjs.org/" "registry": "https://registry.npmjs.org/"
} },
"packageManager": "pnpm@10.18.1+sha512.77a884a165cbba2d8d1c19e3b4880eee6d2fcabd0d879121e282196b80042351d5eb3ca0935fa599da1dc51265cc68816ad2bddd2a2de5ea9fdf92adbec7cd34"
} }

View File

@@ -1,4 +1,4 @@
import * as snmp from 'npm:net-snmp@3.20.0'; import * as snmp from 'npm:net-snmp@3.26.0';
import { Buffer } from 'node:buffer'; import { Buffer } from 'node:buffer';
import type { IOidSet, ISnmpConfig, IUpsStatus, TUpsModel } from './types.ts'; import type { IOidSet, ISnmpConfig, IUpsStatus, TUpsModel } from './types.ts';
import { UpsOidSets } from './oid-sets.ts'; import { UpsOidSets } from './oid-sets.ts';
@@ -304,6 +304,10 @@ export class NupstSnmp {
console.log(' Power Status:', this.activeOIDs.POWER_STATUS); console.log(' Power Status:', this.activeOIDs.POWER_STATUS);
console.log(' Battery Capacity:', this.activeOIDs.BATTERY_CAPACITY); console.log(' Battery Capacity:', this.activeOIDs.BATTERY_CAPACITY);
console.log(' Battery Runtime:', this.activeOIDs.BATTERY_RUNTIME); console.log(' Battery Runtime:', this.activeOIDs.BATTERY_RUNTIME);
console.log(' Output Load:', this.activeOIDs.OUTPUT_LOAD);
console.log(' Output Power:', this.activeOIDs.OUTPUT_POWER);
console.log(' Output Voltage:', this.activeOIDs.OUTPUT_VOLTAGE);
console.log(' Output Current:', this.activeOIDs.OUTPUT_CURRENT);
console.log('---------------------------------------'); console.log('---------------------------------------');
} }
@@ -324,20 +328,65 @@ export class NupstSnmp {
config, config,
) || 0; ) || 0;
// Get power draw metrics
const outputLoad = await this.getSNMPValueWithRetry(
this.activeOIDs.OUTPUT_LOAD,
'output load',
config,
) || 0;
const outputPower = await this.getSNMPValueWithRetry(
this.activeOIDs.OUTPUT_POWER,
'output power',
config,
) || 0;
const outputVoltage = await this.getSNMPValueWithRetry(
this.activeOIDs.OUTPUT_VOLTAGE,
'output voltage',
config,
) || 0;
const outputCurrent = await this.getSNMPValueWithRetry(
this.activeOIDs.OUTPUT_CURRENT,
'output current',
config,
) || 0;
// Determine power status - handle different values for different UPS models // Determine power status - handle different values for different UPS models
const powerStatus = this.determinePowerStatus(config.upsModel, powerStatusValue); const powerStatus = this.determinePowerStatus(config.upsModel, powerStatusValue);
// Convert to minutes for UPS models with different time units // Convert to minutes for UPS models with different time units
const processedRuntime = this.processRuntimeValue(config.upsModel, batteryRuntime); const processedRuntime = this.processRuntimeValue(config.upsModel, batteryRuntime);
// Process power metrics with vendor-specific scaling
const processedVoltage = this.processVoltageValue(config.upsModel, outputVoltage);
const processedCurrent = this.processCurrentValue(config.upsModel, outputCurrent);
// Calculate power from voltage × current if not provided by UPS
let processedPower = outputPower;
if (outputPower === 0 && processedVoltage > 0 && processedCurrent > 0) {
processedPower = Math.round(processedVoltage * processedCurrent);
if (this.debug) {
console.log(
`Calculated power from V×I: ${processedVoltage}V × ${processedCurrent}A = ${processedPower}W`,
);
}
}
const result = { const result = {
powerStatus, powerStatus,
batteryCapacity, batteryCapacity,
batteryRuntime: processedRuntime, batteryRuntime: processedRuntime,
outputLoad,
outputPower: processedPower,
outputVoltage: processedVoltage,
outputCurrent: processedCurrent,
raw: { raw: {
powerStatus: powerStatusValue, powerStatus: powerStatusValue,
batteryCapacity, batteryCapacity,
batteryRuntime, batteryRuntime,
outputLoad,
outputPower,
outputVoltage,
outputCurrent,
}, },
}; };
@@ -347,6 +396,10 @@ export class NupstSnmp {
console.log(' Power Status:', result.powerStatus); console.log(' Power Status:', result.powerStatus);
console.log(' Battery Capacity:', result.batteryCapacity + '%'); console.log(' Battery Capacity:', result.batteryCapacity + '%');
console.log(' Battery Runtime:', result.batteryRuntime, 'minutes'); console.log(' Battery Runtime:', result.batteryRuntime, 'minutes');
console.log(' Output Load:', result.outputLoad + '%');
console.log(' Output Power:', result.outputPower, 'watts');
console.log(' Output Voltage:', result.outputVoltage, 'volts');
console.log(' Output Current:', result.outputCurrent, 'amps');
console.log('---------------------------------------'); console.log('---------------------------------------');
} }
@@ -602,4 +655,69 @@ export class NupstSnmp {
return batteryRuntime; return batteryRuntime;
} }
/**
* Process voltage value based on UPS model
* @param upsModel UPS model
* @param outputVoltage Raw output voltage value
* @returns Processed voltage in volts
*/
private processVoltageValue(
upsModel: TUpsModel | undefined,
outputVoltage: number,
): number {
if (this.debug) {
console.log('Raw voltage value:', outputVoltage);
}
if (upsModel === 'cyberpower' && outputVoltage > 0) {
// CyberPower: Voltage is in 0.1V, convert to volts
const volts = outputVoltage / 10;
if (this.debug) {
console.log(
`Converting CyberPower voltage from ${outputVoltage} (0.1V) to ${volts} volts`,
);
}
return volts;
}
return outputVoltage;
}
/**
* Process current value based on UPS model
* @param upsModel UPS model
* @param outputCurrent Raw output current value
* @returns Processed current in amps
*/
private processCurrentValue(
upsModel: TUpsModel | undefined,
outputCurrent: number,
): number {
if (this.debug) {
console.log('Raw current value:', outputCurrent);
}
if (upsModel === 'cyberpower' && outputCurrent > 0) {
// CyberPower: Current is in 0.1A, convert to amps
const amps = outputCurrent / 10;
if (this.debug) {
console.log(
`Converting CyberPower current from ${outputCurrent} (0.1A) to ${amps} amps`,
);
}
return amps;
} else if ((upsModel === 'eaton' || upsModel === 'tripplite' || upsModel === 'liebert') && outputCurrent > 0) {
// RFC 1628 standard: Current is in 0.1A, convert to amps
const amps = outputCurrent / 10;
if (this.debug) {
console.log(
`Converting RFC 1628 current from ${outputCurrent} (0.1A) to ${amps} amps`,
);
}
return amps;
}
return outputCurrent;
}
} }

View File

@@ -14,6 +14,10 @@ export class UpsOidSets {
POWER_STATUS: '1.3.6.1.4.1.3808.1.1.1.4.1.1.0', // upsBaseOutputStatus POWER_STATUS: '1.3.6.1.4.1.3808.1.1.1.4.1.1.0', // upsBaseOutputStatus
BATTERY_CAPACITY: '1.3.6.1.4.1.3808.1.1.1.2.2.1.0', // upsAdvanceBatteryCapacity (percentage) BATTERY_CAPACITY: '1.3.6.1.4.1.3808.1.1.1.2.2.1.0', // upsAdvanceBatteryCapacity (percentage)
BATTERY_RUNTIME: '1.3.6.1.4.1.3808.1.1.1.2.2.4.0', // upsAdvanceBatteryRunTimeRemaining (TimeTicks) BATTERY_RUNTIME: '1.3.6.1.4.1.3808.1.1.1.2.2.4.0', // upsAdvanceBatteryRunTimeRemaining (TimeTicks)
OUTPUT_LOAD: '1.3.6.1.4.1.3808.1.1.1.4.2.3.0', // upsAdvanceOutputLoad (percentage)
OUTPUT_POWER: '1.3.6.1.4.1.3808.1.1.1.4.2.5.0', // upsAdvanceOutputPower (watts)
OUTPUT_VOLTAGE: '1.3.6.1.4.1.3808.1.1.1.4.2.1.0', // upsAdvanceOutputVoltage (0.1V scale)
OUTPUT_CURRENT: '1.3.6.1.4.1.3808.1.1.1.4.2.4.0', // upsAdvanceOutputCurrent (0.1A scale)
POWER_STATUS_VALUES: { POWER_STATUS_VALUES: {
online: 2, // upsBaseOutputStatus: 2=onLine online: 2, // upsBaseOutputStatus: 2=onLine
onBattery: 3, // upsBaseOutputStatus: 3=onBattery onBattery: 3, // upsBaseOutputStatus: 3=onBattery
@@ -25,6 +29,10 @@ export class UpsOidSets {
POWER_STATUS: '1.3.6.1.4.1.318.1.1.1.4.1.1.0', // upsBasicOutputStatus POWER_STATUS: '1.3.6.1.4.1.318.1.1.1.4.1.1.0', // upsBasicOutputStatus
BATTERY_CAPACITY: '1.3.6.1.4.1.318.1.1.1.2.2.1.0', // Battery capacity in percentage BATTERY_CAPACITY: '1.3.6.1.4.1.318.1.1.1.2.2.1.0', // Battery capacity in percentage
BATTERY_RUNTIME: '1.3.6.1.4.1.318.1.1.1.2.2.3.0', // Remaining runtime in minutes BATTERY_RUNTIME: '1.3.6.1.4.1.318.1.1.1.2.2.3.0', // Remaining runtime in minutes
OUTPUT_LOAD: '1.3.6.1.4.1.318.1.1.1.4.2.3.0', // upsAdvOutputLoad (percentage)
OUTPUT_POWER: '', // Not readily available, load returns VA on some models
OUTPUT_VOLTAGE: '1.3.6.1.4.1.318.1.1.1.4.2.1.0', // upsAdvOutputVoltage
OUTPUT_CURRENT: '1.3.6.1.4.1.318.1.1.1.4.2.4.0', // upsAdvOutputCurrent
POWER_STATUS_VALUES: { POWER_STATUS_VALUES: {
online: 2, // upsBasicOutputStatus: 2=onLine online: 2, // upsBasicOutputStatus: 2=onLine
onBattery: 3, // upsBasicOutputStatus: 3=onBattery onBattery: 3, // upsBasicOutputStatus: 3=onBattery
@@ -36,6 +44,10 @@ export class UpsOidSets {
POWER_STATUS: '1.3.6.1.4.1.534.1.4.4.0', // xupsOutputSource POWER_STATUS: '1.3.6.1.4.1.534.1.4.4.0', // xupsOutputSource
BATTERY_CAPACITY: '1.3.6.1.4.1.534.1.2.4.0', // xupsBatCapacity (percentage) BATTERY_CAPACITY: '1.3.6.1.4.1.534.1.2.4.0', // xupsBatCapacity (percentage)
BATTERY_RUNTIME: '1.3.6.1.4.1.534.1.2.1.0', // xupsBatTimeRemaining (seconds) BATTERY_RUNTIME: '1.3.6.1.4.1.534.1.2.1.0', // xupsBatTimeRemaining (seconds)
OUTPUT_LOAD: '1.3.6.1.2.1.33.1.4.4.1.5.1', // RFC 1628: upsOutputPercentLoad
OUTPUT_POWER: '1.3.6.1.2.1.33.1.4.4.1.4.1', // RFC 1628: upsOutputPower (watts)
OUTPUT_VOLTAGE: '1.3.6.1.2.1.33.1.4.4.1.2.1', // RFC 1628: upsOutputVoltage
OUTPUT_CURRENT: '1.3.6.1.2.1.33.1.4.4.1.3.1', // RFC 1628: upsOutputCurrent (0.1A scale)
POWER_STATUS_VALUES: { POWER_STATUS_VALUES: {
online: 3, // xupsOutputSource: 3=normal (mains power) online: 3, // xupsOutputSource: 3=normal (mains power)
onBattery: 5, // xupsOutputSource: 5=battery onBattery: 5, // xupsOutputSource: 5=battery
@@ -47,6 +59,10 @@ export class UpsOidSets {
POWER_STATUS: '1.3.6.1.4.1.850.1.1.3.1.1.1.0', // tlUpsOutputSource POWER_STATUS: '1.3.6.1.4.1.850.1.1.3.1.1.1.0', // tlUpsOutputSource
BATTERY_CAPACITY: '1.3.6.1.4.1.850.1.1.3.2.4.1.0', // Battery capacity in percentage BATTERY_CAPACITY: '1.3.6.1.4.1.850.1.1.3.2.4.1.0', // Battery capacity in percentage
BATTERY_RUNTIME: '1.3.6.1.4.1.850.1.1.3.2.2.1.0', // Remaining runtime in minutes BATTERY_RUNTIME: '1.3.6.1.4.1.850.1.1.3.2.2.1.0', // Remaining runtime in minutes
OUTPUT_LOAD: '1.3.6.1.2.1.33.1.4.4.1.5.1', // RFC 1628: upsOutputPercentLoad
OUTPUT_POWER: '1.3.6.1.2.1.33.1.4.4.1.4.1', // RFC 1628: upsOutputPower (watts)
OUTPUT_VOLTAGE: '1.3.6.1.2.1.33.1.4.4.1.2.1', // RFC 1628: upsOutputVoltage
OUTPUT_CURRENT: '1.3.6.1.2.1.33.1.4.4.1.3.1', // RFC 1628: upsOutputCurrent (0.1A scale)
POWER_STATUS_VALUES: { POWER_STATUS_VALUES: {
online: 2, // tlUpsOutputSource: 2=normal (mains power) online: 2, // tlUpsOutputSource: 2=normal (mains power)
onBattery: 3, // tlUpsOutputSource: 3=onBattery onBattery: 3, // tlUpsOutputSource: 3=onBattery
@@ -58,6 +74,10 @@ export class UpsOidSets {
POWER_STATUS: '1.3.6.1.4.1.476.1.42.3.9.20.1.20.1.2.1.2.1', // lgpPwrOutputSource POWER_STATUS: '1.3.6.1.4.1.476.1.42.3.9.20.1.20.1.2.1.2.1', // lgpPwrOutputSource
BATTERY_CAPACITY: '1.3.6.1.4.1.476.1.42.3.9.20.1.20.1.2.1.4.1', // Battery capacity in percentage BATTERY_CAPACITY: '1.3.6.1.4.1.476.1.42.3.9.20.1.20.1.2.1.4.1', // Battery capacity in percentage
BATTERY_RUNTIME: '1.3.6.1.4.1.476.1.42.3.9.20.1.20.1.2.1.5.1', // Remaining runtime in minutes BATTERY_RUNTIME: '1.3.6.1.4.1.476.1.42.3.9.20.1.20.1.2.1.5.1', // Remaining runtime in minutes
OUTPUT_LOAD: '1.3.6.1.2.1.33.1.4.4.1.5.1', // RFC 1628: upsOutputPercentLoad
OUTPUT_POWER: '1.3.6.1.2.1.33.1.4.4.1.4.1', // RFC 1628: upsOutputPower (watts)
OUTPUT_VOLTAGE: '1.3.6.1.2.1.33.1.4.4.1.2.1', // RFC 1628: upsOutputVoltage
OUTPUT_CURRENT: '1.3.6.1.2.1.33.1.4.4.1.3.1', // RFC 1628: upsOutputCurrent (0.1A scale)
POWER_STATUS_VALUES: { POWER_STATUS_VALUES: {
online: 2, // lgpPwrOutputSource: 2=normal (mains power) online: 2, // lgpPwrOutputSource: 2=normal (mains power)
onBattery: 3, // lgpPwrOutputSource: 3=onBattery onBattery: 3, // lgpPwrOutputSource: 3=onBattery
@@ -69,6 +89,10 @@ export class UpsOidSets {
POWER_STATUS: '', POWER_STATUS: '',
BATTERY_CAPACITY: '', BATTERY_CAPACITY: '',
BATTERY_RUNTIME: '', BATTERY_RUNTIME: '',
OUTPUT_LOAD: '',
OUTPUT_POWER: '',
OUTPUT_VOLTAGE: '',
OUTPUT_CURRENT: '',
}, },
}; };
@@ -90,6 +114,10 @@ export class UpsOidSets {
'power status': '1.3.6.1.2.1.33.1.4.1.0', // upsOutputSource 'power status': '1.3.6.1.2.1.33.1.4.1.0', // upsOutputSource
'battery capacity': '1.3.6.1.2.1.33.1.2.4.0', // upsEstimatedChargeRemaining 'battery capacity': '1.3.6.1.2.1.33.1.2.4.0', // upsEstimatedChargeRemaining
'battery runtime': '1.3.6.1.2.1.33.1.2.3.0', // upsEstimatedMinutesRemaining 'battery runtime': '1.3.6.1.2.1.33.1.2.3.0', // upsEstimatedMinutesRemaining
'output load': '1.3.6.1.2.1.33.1.4.4.1.5.1', // upsOutputPercentLoad (indexed by line)
'output power': '1.3.6.1.2.1.33.1.4.4.1.4.1', // upsOutputPower in watts (indexed by line)
'output voltage': '1.3.6.1.2.1.33.1.4.4.1.2.1', // upsOutputVoltage (indexed by line)
'output current': '1.3.6.1.2.1.33.1.4.4.1.3.1', // upsOutputCurrent in 0.1A (indexed by line)
}; };
} }
} }

View File

@@ -14,6 +14,14 @@ export interface IUpsStatus {
batteryCapacity: number; batteryCapacity: number;
/** Remaining runtime in minutes */ /** Remaining runtime in minutes */
batteryRuntime: number; batteryRuntime: number;
/** Output load percentage (0-100) */
outputLoad: number;
/** Output power in watts */
outputPower: number;
/** Output voltage in volts */
outputVoltage: number;
/** Output current in amps */
outputCurrent: number;
/** Raw values from SNMP responses */ /** Raw values from SNMP responses */
raw: Record<string, any>; raw: Record<string, any>;
} }
@@ -28,6 +36,14 @@ export interface IOidSet {
BATTERY_CAPACITY: string; BATTERY_CAPACITY: string;
/** OID for battery runtime */ /** OID for battery runtime */
BATTERY_RUNTIME: string; BATTERY_RUNTIME: string;
/** OID for output load percentage */
OUTPUT_LOAD: string;
/** OID for output power in watts */
OUTPUT_POWER: string;
/** OID for output voltage */
OUTPUT_VOLTAGE: string;
/** OID for output current */
OUTPUT_CURRENT: string;
/** Power status value mappings */ /** Power status value mappings */
POWER_STATUS_VALUES?: { POWER_STATUS_VALUES?: {
/** SNMP value that indicates UPS is online (on AC power) */ /** SNMP value that indicates UPS is online (on AC power) */