banshee is under active development: collectors will keep changing, and a version you publish will likely need adjustments. For stable use, wait for version 1.0.0.

Hardware

banshee/hardware-collection/hardware/ups/snmp/

status

The power source, battery, runtime, load, self-test and alarms of a UPS of any brand by SNMP (UPS-MIB).

  • hardware
  • ups
  • battery
  • power
  • rfc1628
  • ups-mib
  • snmp

by banshee1 installation2 versions

v2Latest

Published on October 28, 2026. One naming convention across collections; documentation completed.

Keen 1.0.0 · 98 lines
// An uninterruptible power supply, by SNMP (UPS-MIB, RFC 1628), whatever its brand: what feeds its output
// (mains, battery, bypass), the state of its battery, the runtime and charge left, its temperature, the load
// of its most loaded output line, the result of its last self-test and the alarms it raises. It is the MIB
// a UPS network card serves whatever its brand, often beside a MIB of its own.
need('protocol:snmp');

output('source', 'text', array('label' => 'Output source'));
output('battery', 'text', array('label' => 'Battery state'));
output('on-battery', 'number', array('label' => 'Time on battery', 'unit' => 's'));
output('runtime', 'number', array('label' => 'Runtime left', 'unit' => 'min'));
output('charge', 'number', array('label' => 'Battery charge', 'unit' => '%'));
output('temperature', 'number', array('label' => 'Battery temperature', 'unit' => '°C'));
output('load', 'number', array('label' => 'Load', 'unit' => '%'));
output('self-test', 'text', array('label' => 'Last self-test'));
output('alarms', 'number', array('label' => 'Alarms'));
output('alarm-list', 'text', array('label' => 'Alarms raised'));

watch.state('on-battery', 'On battery, bypass or off', 'source', array('warning' => array('battery', 'bypass'), 'critical' => array('none')));
watch.state('battery', 'Battery low or depleted', 'battery', array('warning' => array('low'), 'critical' => array('depleted')));
watch.below('runtime', 'Little runtime left', 'runtime', array('warning' => 15, 'critical' => 5));
watch.below('charge', 'Battery not charged', 'charge', array('warning' => 50, 'critical' => 20, 'for' => '2 runs'));
watch.above('temperature', 'Battery too hot', 'temperature', array('warning' => 40, 'critical' => 50, 'for' => '3 runs'));
watch.above('load', 'Overloaded', 'load', array('warning' => 80, 'critical' => 95, 'for' => '3 runs'));
watch.state('self-test', 'Self-test failed', 'self-test', array('warning' => array('warning'), 'critical' => array('error')));
watch.above('alarms', 'Alarms raised', 'alarms', array('warning' => 0));

// The whole of upsObjects (1.3.6.1.2.1.33.1), a small branch, in one walk; each key is the rest of the OID:
// '2.1.0' is upsBatteryStatus.0.
$ups = snmp.walk('1.3.6.1.2.1.33.1');
if (!list.has($ups, '4.1.0') || !list.has($ups, '2.1.0')) {
    fail('misconfigured', 'The agent serves no UPS-MIB (upsOutputSource, upsBatteryStatus)',
        'Not a UPS, a card where the RFC 1628 MIB is turned off, or a view that does not include 1.3.6.1.2.1.33.');
}

// upsOutputSource: other (1), none (2), normal (3), bypass (4), battery (5), booster (6), reducer (7).
$sources = array(1 => 'other', 2 => 'none', 3 => 'normal', 4 => 'bypass', 5 => 'battery', 6 => 'booster', 7 => 'reducer');
value('source', list.get($sources, $ups['4.1.0'], 'unknown'));

// upsBatteryStatus: unknown (1), batteryNormal (2), batteryLow (3), batteryDepleted (4).
$batteries = array(1 => 'unknown', 2 => 'normal', 3 => 'low', 4 => 'depleted');
value('battery', list.get($batteries, $ups['2.1.0'], 'unknown'));

// upsSecondsOnBattery, 0 on mains; upsEstimatedMinutesRemaining; upsEstimatedChargeRemaining, in %;
// upsBatteryTemperature, in degrees Celsius, which not every UPS serves.
if (list.has($ups, '2.2.0')) {
    value('on-battery', $ups['2.2.0']);
}
if (list.has($ups, '2.3.0')) {
    value('runtime', $ups['2.3.0']);
}
if (list.has($ups, '2.4.0')) {
    value('charge', $ups['2.4.0']);
}
if (list.has($ups, '2.7.0')) {
    value('temperature', $ups['2.7.0']);
}

// upsOutputPercentLoad (4.4.1.5.<line>), the load of each output line in % of its capacity: the most loaded
// line is returned, the one that trips first.
$load = -1;
foreach ($ups as $key => $percent) {
    if (list.count(text.match($key, '^4\.4\.1\.5\.[0-9]+$')) > 0 && $percent > $load) {
        $load = $percent;
    }
}
if ($load >= 0) {
    value('load', $load);
}

// upsTestResultsSummary: donePass (1), doneWarning (2), doneError (3), aborted (4), inProgress (5),
// noTestsInitiated (6).
$tests = array(1 => 'pass', 2 => 'warning', 3 => 'error', 4 => 'aborted', 5 => 'in-progress', 6 => 'none');
if (list.has($ups, '7.3.0')) {
    value('self-test', list.get($tests, $ups['7.3.0'], 'unknown'));
}

// upsAlarmsPresent, and in upsAlarmTable each alarm's upsAlarmDescr (6.2.1.2.<id>), the OID of one of the
// well-known alarms of the MIB (1.3.6.1.2.1.33.1.6.3.<n>), or a brand's own.
$names = array(1 => 'battery bad', 2 => 'on battery', 3 => 'low battery', 4 => 'depleted battery',
    5 => 'temperature bad', 6 => 'input bad', 7 => 'output bad', 8 => 'output overload', 9 => 'on bypass',
    10 => 'bypass bad', 11 => 'output off as requested', 12 => 'UPS off as requested', 13 => 'charger failed',
    14 => 'UPS output off', 15 => 'UPS system off', 16 => 'fan failure', 17 => 'fuse failure',
    18 => 'general fault', 19 => 'diagnostic test failed', 20 => 'communications lost', 21 => 'awaiting power',
    22 => 'shutdown pending', 23 => 'shutdown imminent', 24 => 'test in progress');
$raised = array();
foreach ($ups as $key => $description) {
    if (list.count(text.match($key, '^6\.2\.1\.2\.[0-9]+$')) == 0) {
        continue;
    }
    $known = text.match($description, '33\.1\.6\.3\.([0-9]+)$');
    if (list.count($known) > 0 && list.has($names, $known[1])) {
        $raised = list.add($raised, $names[$known[1]]);
    } else {
        $raised = list.add($raised, $description);
    }
}
value('alarms', list.get($ups, '6.1.0', list.count($raised)));
value('alarm-list', text.join($raised, ', '));