feat(cli,snmp): fix APC runtime unit defaults and add interactive action editing
This commit is contained in:
+13
-48
@@ -2,6 +2,7 @@ import * as snmp from 'npm:net-snmp@3.26.1';
|
||||
import { Buffer } from 'node:buffer';
|
||||
import type { IOidSet, ISnmpConfig, IUpsStatus, TUpsModel } from './types.ts';
|
||||
import { UpsOidSets } from './oid-sets.ts';
|
||||
import { convertRuntimeValueToMinutes, getDefaultRuntimeUnitForUpsModel } from './runtime-units.ts';
|
||||
import { SNMP } from '../constants.ts';
|
||||
import { logger } from '../logger.ts';
|
||||
import type { INupstAccessor } from '../interfaces/index.ts';
|
||||
@@ -707,56 +708,20 @@ export class NupstSnmp {
|
||||
logger.dim(`Raw runtime value: ${batteryRuntime}`);
|
||||
}
|
||||
|
||||
// Explicit runtimeUnit takes precedence over model-based detection
|
||||
if (config.runtimeUnit) {
|
||||
if (config.runtimeUnit === 'seconds' && batteryRuntime > 0) {
|
||||
const minutes = Math.floor(batteryRuntime / 60);
|
||||
if (this.debug) {
|
||||
logger.dim(
|
||||
`Converting runtime from ${batteryRuntime} seconds to ${minutes} minutes (runtimeUnit: seconds)`,
|
||||
);
|
||||
}
|
||||
return minutes;
|
||||
} else if (config.runtimeUnit === 'ticks' && batteryRuntime > 0) {
|
||||
const minutes = Math.floor(batteryRuntime / 6000);
|
||||
if (this.debug) {
|
||||
logger.dim(
|
||||
`Converting runtime from ${batteryRuntime} ticks to ${minutes} minutes (runtimeUnit: ticks)`,
|
||||
);
|
||||
}
|
||||
return minutes;
|
||||
}
|
||||
// runtimeUnit === 'minutes' — return as-is
|
||||
return batteryRuntime;
|
||||
const runtimeUnit = config.runtimeUnit ||
|
||||
getDefaultRuntimeUnitForUpsModel(config.upsModel, batteryRuntime);
|
||||
const minutes = convertRuntimeValueToMinutes(config, batteryRuntime);
|
||||
|
||||
if (this.debug && minutes !== batteryRuntime) {
|
||||
const source = config.runtimeUnit
|
||||
? `runtimeUnit: ${runtimeUnit}`
|
||||
: `upsModel: ${config.upsModel || 'auto'}`;
|
||||
logger.dim(
|
||||
`Converting runtime from ${batteryRuntime} ${runtimeUnit} to ${minutes} minutes (${source})`,
|
||||
);
|
||||
}
|
||||
|
||||
// Fallback: model-based detection (for configs without runtimeUnit)
|
||||
const upsModel = config.upsModel;
|
||||
if (upsModel === 'cyberpower' && batteryRuntime > 0) {
|
||||
const minutes = Math.floor(batteryRuntime / 6000);
|
||||
if (this.debug) {
|
||||
logger.dim(
|
||||
`Converting CyberPower runtime from ${batteryRuntime} ticks to ${minutes} minutes`,
|
||||
);
|
||||
}
|
||||
return minutes;
|
||||
} else if (upsModel === 'eaton' && batteryRuntime > 0) {
|
||||
const minutes = Math.floor(batteryRuntime / 60);
|
||||
if (this.debug) {
|
||||
logger.dim(
|
||||
`Converting Eaton runtime from ${batteryRuntime} seconds to ${minutes} minutes`,
|
||||
);
|
||||
}
|
||||
return minutes;
|
||||
} else if (batteryRuntime > 10000) {
|
||||
const minutes = Math.floor(batteryRuntime / 6000);
|
||||
if (this.debug) {
|
||||
logger.dim(`Converting ${batteryRuntime} ticks to ${minutes} minutes (heuristic)`);
|
||||
}
|
||||
return minutes;
|
||||
}
|
||||
|
||||
return batteryRuntime;
|
||||
return minutes;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ export class UpsOidSets {
|
||||
apc: {
|
||||
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_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 (TimeTicks)
|
||||
OUTPUT_LOAD: '1.3.6.1.4.1.318.1.1.1.4.2.3.0', // upsAdvOutputLoad (percentage)
|
||||
OUTPUT_POWER: '1.3.6.1.4.1.318.1.1.1.4.2.8.0', // upsAdvOutputActivePower (watts)
|
||||
OUTPUT_VOLTAGE: '1.3.6.1.4.1.318.1.1.1.4.2.1.0', // upsAdvOutputVoltage
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import type { ISnmpConfig, TRuntimeUnit, TUpsModel } from './types.ts';
|
||||
|
||||
/**
|
||||
* Return the runtime unit that matches the bundled OID set for a UPS model.
|
||||
*/
|
||||
export function getDefaultRuntimeUnitForUpsModel(
|
||||
upsModel: TUpsModel | undefined,
|
||||
batteryRuntime?: number,
|
||||
): TRuntimeUnit {
|
||||
switch (upsModel) {
|
||||
case 'cyberpower':
|
||||
case 'apc':
|
||||
return 'ticks';
|
||||
case 'eaton':
|
||||
return 'seconds';
|
||||
case 'custom':
|
||||
case 'tripplite':
|
||||
case 'liebert':
|
||||
case undefined:
|
||||
if (batteryRuntime !== undefined && batteryRuntime > 10000) {
|
||||
return 'ticks';
|
||||
}
|
||||
return 'minutes';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an SNMP runtime value to minutes using explicit config first, then model defaults.
|
||||
*/
|
||||
export function convertRuntimeValueToMinutes(
|
||||
config: Pick<ISnmpConfig, 'runtimeUnit' | 'upsModel'>,
|
||||
batteryRuntime: number,
|
||||
): number {
|
||||
if (batteryRuntime <= 0) {
|
||||
return batteryRuntime;
|
||||
}
|
||||
|
||||
const runtimeUnit = config.runtimeUnit ||
|
||||
getDefaultRuntimeUnitForUpsModel(config.upsModel, batteryRuntime);
|
||||
|
||||
if (runtimeUnit === 'seconds') {
|
||||
return Math.floor(batteryRuntime / 60);
|
||||
}
|
||||
|
||||
if (runtimeUnit === 'ticks') {
|
||||
return Math.floor(batteryRuntime / 6000);
|
||||
}
|
||||
|
||||
return batteryRuntime;
|
||||
}
|
||||
Reference in New Issue
Block a user