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.

Storage

banshee/storage-collection/storage/synology/snmp/

disks

The status, health, temperature, bad sectors and remaining life of each disk of a Synology NAS by SNMP.

  • storage
  • synology
  • dsm
  • nas
  • disk
  • snmp
  • temperature

by banshee1 installation1 version

v1Latest

Published on October 27, 2026. First version.

Keen 1.0.0 · 62 lines
// The disks of a Synology NAS, by SNMP (SYNOLOGY-DISK-MIB): the state and the temperature of each, and, from
// DSM 7.0, its bad sectors and remaining life, from DSM 7.1 its health. A column the agent does not serve
// (an older DSM) is left out of its row: what it would say is not returned, the rest is.
need('protocol:snmp');

per('disk', 'Disks');
output('status', 'text', array('label' => 'Status', 'per' => 'disk'));
output('health', 'text', array('label' => 'Health', 'per' => 'disk'));
output('temperature', 'number', array('label' => 'Temperature', 'unit' => '°C', 'per' => 'disk'));
output('bad-sectors', 'number', array('label' => 'Bad sectors', 'per' => 'disk'));
output('remaining-life', 'number', array('label' => 'Remaining life', 'unit' => '%', 'per' => 'disk'));

watch.state('failed', 'Disk failed', 'status', array('critical' => array('crashed', 'system-partition-failed', 'disconnected')));
watch.state('unhealthy', 'Disk health degraded', 'health', array('warning' => array('warning'), 'critical' => array('critical', 'failing')));
watch.above('hot', 'High temperature', 'temperature', array('warning' => 55, 'critical' => 60, 'for' => '3 runs'));
watch.above('bad-sectors', 'Bad sectors', 'bad-sectors', array('warning' => 0));
watch.below('worn', 'Disk worn out', 'remaining-life', array('warning' => 10, 'critical' => 3));
watch.missing('missing', 'Disk missing', 'status', array('enabled' => false));

// SYNOLOGY-DISK-MIB, diskTable (1.3.6.1.4.1.6574.2.1), by diskIndex: diskID (deprecated, the name before
// DSM 7.0), diskStatus, diskTemperature, diskBadSector, diskRemainLife, diskName and diskHealthStatus.
$disks = snmp.table(array(
    'id'          => '1.3.6.1.4.1.6574.2.1.1.2',
    'status'      => '1.3.6.1.4.1.6574.2.1.1.5',
    'temperature' => '1.3.6.1.4.1.6574.2.1.1.6',
    'bad-sectors' => '1.3.6.1.4.1.6574.2.1.1.9',
    'life'        => '1.3.6.1.4.1.6574.2.1.1.11',
    'name'        => '1.3.6.1.4.1.6574.2.1.1.12',
    'health'      => '1.3.6.1.4.1.6574.2.1.1.13',
));

$statuses = array(1 => 'normal', 2 => 'initialized', 3 => 'not-initialized', 4 => 'system-partition-failed',
    5 => 'crashed', 6 => 'disconnected');
$healths = array(1 => 'normal', 2 => 'warning', 3 => 'critical', 4 => 'failing');

$read = 0;
foreach ($disks as $row) {
    // The name in the OS ("sata1") from DSM 7.0; before, the deprecated diskID ("Disk 1").
    $name = list.get($row, 'name', list.get($row, 'id', ''));
    if ($name == '' || !list.has($row, 'status')) {
        continue;
    }
    $read = $read + 1;
    value('status', list.get($statuses, $row['status'], 'unknown'), $name);
    if (list.has($row, 'health')) {
        value('health', list.get($healths, $row['health'], 'unknown'), $name);
    }
    if (list.has($row, 'temperature')) {
        value('temperature', $row['temperature'], $name);
    }
    if (list.has($row, 'bad-sectors')) {
        value('bad-sectors', $row['bad-sectors'], $name);
    }
    // A disk that does not estimate its life (most hard disks) answers a negative number.
    if (list.has($row, 'life') && $row['life'] >= 0) {
        value('remaining-life', $row['life'], $name);
    }
}
if ($read == 0) {
    fail('misconfigured', 'The agent serves no disk (diskTable, SYNOLOGY-DISK-MIB)',
        'Not a Synology, or a view that does not include 1.3.6.1.4.1.6574.');
}