Patch for mod_apcupsd.pl

I’ve got 2 APC UPS connected to a Raspi3 and use apcupsd for getting the status data. The Raspi provides the status data via SNMP to my Zabbix installation.

For this to work I got this snmpd mod. Unfortunately this only queries the default APC via apcaccess.

I hacked together (I dunno nothing about perl) a patch to support multiple UPS.
You can find this after the break.

--- backup/mod_apcupsd.pl	2017-02-06 13:18:11.000000000 +0000
+++ mod_apcupsd.pl	2017-02-08 12:50:03.517744933 +0000
@@ -57,11 +57,13 @@
 use NetSNMP::OID (':all');
 use NetSNMP::agent (':all');
 use NetSNMP::ASN (':all');
-
+#use Data::Dumper;
 
 
 #################### SETTINGS ###################
 
+# array of nis hosts - multi-ups support
+my @ups_hosts = ("localhost:3551", "localhost:3552");
 
 # Set to 1 to get extra debugging information.
 $debugging = 0;
@@ -73,35 +75,36 @@
 my $base_oid = '.1.3.6.1.4.1.318.1.1.1';
 
 # OIDs mapping
+# removed trailing 0 - this gets added later
 my $mapping = [
 #   Apcupsd name    OID suffix  Data type           OID name
-    ['APCMODEL',    '1.1.1.0',  ASN_OCTET_STR],     # upsBasicIdentModel
-    ['UPSNAME',     '1.1.2.0',  ASN_OCTET_STR],     # upsBasicIdentName
-    ['FIRMWARE',    '1.2.1.0',  ASN_OCTET_STR],     # upsAdvIdentFirmwareRevision
-    ['SERIALNO',    '1.2.3.0',  ASN_OCTET_STR],     # upsAdvIdentSerialNumber
-    ['TONBATT',     '2.1.2.0',  ASN_TIMETICKS],     # upsBasicBatteryTimeOnBattery
-    ['BATTDATE',    '2.1.3.0',  ASN_OCTET_STR],     # upsBasicBatteryLastReplaceDate
-    ['BCHARGE',     '2.2.1.0',  ASN_GAUGE],         # upsAdvBatteryCapacity
-    ['ITEMP',       '2.2.2.0',  ASN_GAUGE],         # upsAdvBatteryTemperature
-    ['TIMELEFT',    '2.2.3.0',  ASN_TIMETICKS],     # upsAdvBatteryRunTimeRemaining
-    ['NOMBATTV',    '2.2.7.0',  ASN_INTEGER],       # upsAdvBatteryNominalVoltage
-    ['BATTV',       '2.2.8.0',  ASN_INTEGER],       # upsAdvBatteryActualVoltage  //should be ASN_INTEGER according to new ver. of MIB
-    ['LINEV',       '3.2.1.0',  ASN_GAUGE],         # upsAdvInputLineVoltage
-    ['LINEFREQ',    '3.2.4.0',  ASN_GAUGE],         # upsAdvInputFrequency
-    ['LASTXFER',    '3.2.5.0',  ASN_INTEGER],       # upsAdvInputLineFailCause
-    ['OUTPUTV',     '4.2.1.0',  ASN_GAUGE],         # upsAdvOutputVoltage
-    ['LOADPCT',     '4.2.3.0',  ASN_GAUGE],         # upsAdvOutputLoad
-    ['NOMOUTV',     '5.2.1.0',  ASN_INTEGER],       # upsAdvConfigRatedOutputVoltage
-    ['HITRANS',     '5.2.2.0',  ASN_INTEGER],       # upsAdvConfigHighTransferVolt
-    ['LOTRANS',     '5.2.3.0',  ASN_INTEGER],       # upsAdvConfigLowTransferVolt
-    ['ALARMDEL',    '5.2.4.0',  ASN_INTEGER],       # upsAdvConfigAlarm
-    ['RETPCT',      '5.2.6.0',  ASN_INTEGER],       # upsAdvConfigMinReturnCapacity
-    ['SENSE',       '5.2.7.0',  ASN_INTEGER],       # upsAdvConfigSensitivity
-    ['MINTIMEL',    '5.2.8.0',  ASN_TIMETICKS],     #? upsAdvConfigLowBatteryRunTime
-    ['DWAKE',       '5.2.9.0',  ASN_TIMETICKS],     # upsAdvConfigReturnDelay
-    ['DSHUTD',      '5.2.10.0', ASN_TIMETICKS],     # upsAdvConfigShutoffDelay
-    ['STESTI',      '7.2.1.0',  ASN_INTEGER],       # upsAdvTestDiagnosticSchedule
-    ['SELFTEST',    '7.2.3.0',  ASN_INTEGER]        # upsAdvTestDiagnosticsResults //according to apcstatus.c, or date and time of last self test according to manual?!
+    ['APCMODEL',    '1.1.1',  ASN_OCTET_STR],     # upsBasicIdentModel
+    ['UPSNAME',     '1.1.2',  ASN_OCTET_STR],     # upsBasicIdentName
+    ['FIRMWARE',    '1.2.1',  ASN_OCTET_STR],     # upsAdvIdentFirmwareRevision
+    ['SERIALNO',    '1.2.3',  ASN_OCTET_STR],     # upsAdvIdentSerialNumber
+    ['TONBATT',     '2.1.2',  ASN_TIMETICKS],     # upsBasicBatteryTimeOnBattery
+    ['BATTDATE',    '2.1.3',  ASN_OCTET_STR],     # upsBasicBatteryLastReplaceDate
+    ['BCHARGE',     '2.2.1',  ASN_GAUGE],         # upsAdvBatteryCapacity
+    ['ITEMP',       '2.2.2',  ASN_GAUGE],         # upsAdvBatteryTemperature
+    ['TIMELEFT',    '2.2.3',  ASN_TIMETICKS],     # upsAdvBatteryRunTimeRemaining
+    ['NOMBATTV',    '2.2.7',  ASN_INTEGER],       # upsAdvBatteryNominalVoltage
+    ['BATTV',       '2.2.8',  ASN_INTEGER],       # upsAdvBatteryActualVoltage  //should be ASN_INTEGER according to new ver. of MIB
+    ['LINEV',       '3.2.1',  ASN_GAUGE],         # upsAdvInputLineVoltage
+    ['LINEFREQ',    '3.2.4',  ASN_GAUGE],         # upsAdvInputFrequency
+    ['LASTXFER',    '3.2.5',  ASN_INTEGER],       # upsAdvInputLineFailCause
+    ['OUTPUTV',     '4.2.1',  ASN_GAUGE],         # upsAdvOutputVoltage
+    ['LOADPCT',     '4.2.3',  ASN_GAUGE],         # upsAdvOutputLoad
+    ['NOMOUTV',     '5.2.1',  ASN_INTEGER],       # upsAdvConfigRatedOutputVoltage
+    ['HITRANS',     '5.2.2',  ASN_INTEGER],       # upsAdvConfigHighTransferVolt
+    ['LOTRANS',     '5.2.3',  ASN_INTEGER],       # upsAdvConfigLowTransferVolt
+    ['ALARMDEL',    '5.2.4',  ASN_INTEGER],       # upsAdvConfigAlarm
+    ['RETPCT',      '5.2.6',  ASN_INTEGER],       # upsAdvConfigMinReturnCapacity
+    ['SENSE',       '5.2.7',  ASN_INTEGER],       # upsAdvConfigSensitivity
+    ['MINTIMEL',    '5.2.8',  ASN_TIMETICKS],     #? upsAdvConfigLowBatteryRunTime
+    ['DWAKE',       '5.2.9',  ASN_TIMETICKS],     # upsAdvConfigReturnDelay
+    ['DSHUTD',      '5.2.10', ASN_TIMETICKS],     # upsAdvConfigShutoffDelay
+    ['STESTI',      '7.2.1',  ASN_INTEGER],       # upsAdvTestDiagnosticSchedule
+    ['SELFTEST',    '7.2.3',  ASN_INTEGER]        # upsAdvTestDiagnosticsResults //according to apcstatus.c, or date and time of last self test according to manual?!
 ];
 
 # Maps apcupsd values to enum types according to MIB.
@@ -213,7 +216,6 @@
     $prev_oid = $oid;
 }
 
-
 # Base OID to register
 $reg_oid = new NetSNMP::OID($base_oid);
 
@@ -221,7 +223,7 @@
 $agent->register('mod_apcupsd', $reg_oid, \&snmp_handler);
 print STDERR "Registering at $base_oid \n" if ($debugging);
 
-
+#print Dumper(\%data);
 
 
 #################### SUBROUTINES ###################
@@ -232,16 +234,20 @@
 # only when it's called after more than $fetch_interval seconds
 # since last fetch.
 sub fetch_data {
+    my $idx = 0;
     my $elapsed = time() - $last_fetch;
 
+
     if ($elapsed < $fetch_interval) {
         print STDERR "It's $elapsed sec since last update, interval is "
                 . "$fetch_interval\n" if ($debugging);
         return 0;
     }
 
+foreach my $host (@ups_hosts){
+
     print STDERR "Fetching data from /sbin/apcaccess\n" if ($debugging);
-    open AC, '/sbin/apcaccess status localhost |'
+    open AC, "/sbin/apcaccess status -h $host |"
             || die "FATAL: can't run \"/sbin/apcaccess\": $!\n";
 
     my $line;
@@ -251,10 +257,14 @@
 
         my $oid = $name_oid{$1};
         my $value = &convert_value($oid, $2) if $oid;
+
+	my $oid = "$oid.$idx" if $oid;
         $data{$oid} = $value if (defined $value);
     }
 
     close AC;
+	$idx = $idx+1;
+}
     $last_fetch = time();
 
     return 1;
@@ -339,7 +349,9 @@
                 my $value = $data{$oid};
 
                 print STDERR "  Returning: $value\n" if ($debugging);
-                $request->setValue($oid_type{$oid}, $value);
+#strip the last digit ("index") coz our type mapping works index-less
+                $request->setValue($oid_type{substr($oid,0,-2)}, $value);
+#                $request->setValue($oid_type{$oid}, $value);
 
             # Workaround for requests without "index"
             } elsif (exists($data{"$oid.0"})) {
@@ -348,7 +360,7 @@
 
                 print STDERR "  Returning for $new_oid: $value\n" if ($debugging);
                 $request->setOID($new_oid);
-                $request->setValue($oid_type{$new_oid}, $value);
+                $request->setValue($oid_type{substr($new_oid,0,-2)}, $value);
             }
 
         # Mode GETNEXT (for walking)
@@ -359,7 +371,7 @@
 
                 print STDERR "  Returning next OID $next_oid: $value\n" if ($debugging);
                 $request->setOID($next_oid);
-                $request->setValue($oid_type{$next_oid}, $value);
+                $request->setValue($oid_type{substr($next_oid,0,-2)}, $value);
 
 
             } elsif ($request->getOID() <= $reg_oid) {
@@ -367,7 +379,7 @@
 
                 print STDERR "  Returning first OID $first_oid: $value\n" if ($debugging);
                 $request->setOID($first_oid);
-                $request->setValue($oid_type{$first_oid}, $value);
+                $request->setValue($oid_type{substr($first_oid,0,-2)}, $value);
 
 
             } else {