Monitoring Brother network printer with SNMP and alert when low on toner

Written by - 0 comments

Published on - Listed in Hardware Monitoring Coding Perl Network Icinga


Most (network) printers have SNMP capabilities. By querying specific SNMP OID's the printer status (and more) can be obtained and checked. The Printer MIB definition is a standard for all kinds of printers, this should be the common ground on printer monitoring. And there are additional vendor MIBs which may contain additional information about the printer's usage and status.

In the open source monitoring world, there are a couple of monitoring plugins available, which do exactly such SNMP checks on printers. But do they work? Depending on your printer, a proper monitoring is unfortunately not guaranteed. At least that's what I had to find out with my Brother MFC-9330CDW multi function printer. But let's start at the beginning.

Black toner is low

Obviously the first hint that a toner is low came from the printer itself. The display nicely showed me that the black (BK) toner cartridge will soon be empty and that it's time to replace the toner:

Accessing the printer's IP address in the browser also shows the toner status, which shows a warning on the black toner:

Recent printed pages already showed a clear decrease in black density, making it hard(er) to read the printed letters. Being a monitoring guy I decided to add this printer into my (Icinga2 based) monitoring.

Testing multiple monitoring plugins

As mentioned at the beginning, there are a couple of open source monitoring/nagios plugins available. However after testing some of them I was less than enthusiastic. You'll see...

check_snmp_printer (Shell script)

The first promising plugin on my research seemed to be check_snmp_printer, a Shell/Bash script written by Yoann Lamy. It seemed to have everything I expect in a monitoring plugin: An understandable code, a help output and it's not 15 years old.

I needed to modify the grep, awk and expr paths within the script to be compatible with my monitoring server (running on Debian Bullseye):

CMD_GREP="/usr/bin/env grep"
CMD_AWK="/usr/bin/env awk"
CMD_EXPR="/usr/bin/env expr"

But as soon as I tried to check the toner (consumables), the script failed:

$ ./check_snmp_printer.sh -H MyBrotherPrinter -t consumable -o black
.1.3.6.1.2.1.43.10.2.1.10.1.: Unknown Object Identifier ()
Printer is waiting

Maybe my Brother printer requires a check on Brother specific OID's?

check_snmp_brother (Shell script)

Another Shell script, check_snmp_brother, looked promising in this regard. It seems to focus on a specific Brother SNMP OID (and is therefore not working for any other printer brand). The plugin is however very limited and only checks the black toner cartridge:

 $ ./check_snmp_brother.sh public MyBrotherPrinter 80 90
OK - Toner Cartridge 85%

The plugin doesn't mention whether the thresholds are understood as "warn when over 80% usage" or "warn when below 80% available". The output shows the (black) toner cartridge level is at 85%. Does that mean 85% used? As I know the toner is almost empty, this would make more sense. However 85% is probably also a wrong value as the printer clearly shows the black toner nearly finished in both the display and in the HTML UI.

A hint for a real toner usage/available value could be in the HTML output:

<td><img src="../common/images/black.gif" alt="Black" class="tonerremain" height="5px" /></td>
<td><img src="../common/images/cyan.gif" alt="Cyan" class="tonerremain" height="33px" /></td>
<td><img src="../common/images/magenta.gif" alt="Magenta" class="tonerremain" height="28px" /></td>
<td><img src="../common/images/yellow.gif" alt="Yellow" class="tonerremain" height="28px" /></td>

The img class "tonerremain" hints this is the current value of remaining toner. As the black toner gif has a height set to 5px this indicates the black toner has a remaining capacity of 5%.

This also means: The check_snmp_brother plugin is wrong. Let's move on.

check_hpjd (C Binary)

Why not try one of the original Nagios plugins to check the printer status? check_hpjd is one of the earliest plugins and has been around since 1999. It was created for HP printers with the JetDirect (network) card - something that almost any network printer has embedded these days.

The output looks promising indeed:

$ /usr/lib/nagios/plugins/check_hpjd -H MyBrotherPrinter
Intervention Required ("Toner Low: BK

The exit code is 1, which is interpreted as WARNING in Nagios, Icinga and co. So this one should work, although I would have preferred to get some nice performance data with it. 

The check_hpjd plugin is also part of the Icinga Integrated Template Library (ITL). This means the check command is already prepared for it:

root@icinga2:~# cat /etc/icinga2/zones.d/master/td-brother-printer.conf
###############################################################################
# HOST DEFINITION
###############################################################################
object Host "td-brother-printer" {
  import "host-printer"
  address = "xxx.xxx.xxx.xxx"
  vars.sys.type = "Printer"
}

###############################################################################
# SERVICE DEFINITIONS
###############################################################################
# Printer check using hpjd
object Service "Printer Status" {
  import "generic-service"
  host_name = "td-brother-printer"
  check_command = "hpjd"
}

In Icinga's UI the printer and the status can now be seen:

So far so good. I can live with that...

check_printer_health (Perl script)

And then I stumbled on check_printer_health! This is a monitoring plugin written in Perl by Gerhard Lausser. And from personal experience I know that Gerhard's plugins are great and well thought of (check_nwc_health for example is another known plugin from Gerhard).

However there is one problem: The plugin does not detect the low toner status:

$ ./check_printer_health --hostname MyBrotherPrinter --mode supplies-status
OK - supplies status is fine | 'Yellow_Drum_Unit_remaining'=72.13%;20:;5:;0;100 'Belt_Unit_remaining'=68.49%;20:;5:;0;100 'Black_Drum_Unit_remaining'=72.13%;20:;5:;0;100 'Cyan_Drum_Unit_remaining'=39.69%;20:;5:;0;100 'Magenta_Drum_Unit_remaining'=39.69%;20:;5:;0;100

Strangely only the Drum and Belt units are detected as supplies, but the toner cartridges don't show up. The reason for this can be seen in a very verbose output:

$ ./check_printer_health --hostname MyBrotherPrinter --mode supplies-status -vvvvvvvvvvvvvvvvvvvvvvv
Thu Jun 13 06:47:48 2024: AUTOLOAD Classes::Device::check_messages
[...]
[MARKERSUPPLY_1.1]
prtMarkerSuppliesClass: supplyThatIsConsumed
prtMarkerSuppliesColorantIndex: 1
prtMarkerSuppliesDescription: Black Toner Cartridge
prtMarkerSuppliesLevel: -3
prtMarkerSuppliesMarkerIndex: 1
prtMarkerSuppliesMaxCapacity: -2
prtMarkerSuppliesSupplyUnit: tenthsOfGrams
prtMarkerSuppliesType: toner
usage: 150
info: Black Toner Cartridge is sufficiently large
[...]

According to Gerhard, the usage (150) is calculated with MaxCapcacity and SuppliesLevel. According to this output, the printer's only information is "everything's fine".

The second check mode (--mode hardware-health) does not show any alert either:

$ ./check_printer_health --hostname MyBrotherPrinter --mode hardware-health
OK - hardware working fine

The prtAlert OID

Looking deeper in a way to get check_printer_health show some kind of alert, I stumbled on the prtAlert (SNMP OID 1.3.6.1.2.1.43.18) table. Within this OID printer alerts are shown, which interestingly is also the case for my low toner situation:

ck@linux:~$ snmpwalk -v 1 -c public MyBrotherPrinter 1.3.6.1.2.1.43.18
iso.3.6.1.2.1.43.18.1.1.2.1.1 = INTEGER: 4
iso.3.6.1.2.1.43.18.1.1.2.1.2 = INTEGER: 0
iso.3.6.1.2.1.43.18.1.1.3.1.1 = INTEGER: 4
iso.3.6.1.2.1.43.18.1.1.3.1.2 = INTEGER: 0
iso.3.6.1.2.1.43.18.1.1.4.1.1 = INTEGER: 11
iso.3.6.1.2.1.43.18.1.1.4.1.2 = INTEGER: 0
iso.3.6.1.2.1.43.18.1.1.5.1.1 = INTEGER: 1
iso.3.6.1.2.1.43.18.1.1.5.1.2 = INTEGER: 0
iso.3.6.1.2.1.43.18.1.1.6.1.1 = INTEGER: 10209
iso.3.6.1.2.1.43.18.1.1.6.1.2 = INTEGER: 40000
iso.3.6.1.2.1.43.18.1.1.7.1.1 = INTEGER: 1104
iso.3.6.1.2.1.43.18.1.1.7.1.2 = INTEGER: 0
iso.3.6.1.2.1.43.18.1.1.8.1.1 = STRING: "Toner Low: BK"
iso.3.6.1.2.1.43.18.1.1.8.1.2 = STRING: "Sleep"
iso.3.6.1.2.1.43.18.1.1.9.1.1 = Timeticks: (0) 0:00:00.00
iso.3.6.1.2.1.43.18.1.1.9.1.2 = Timeticks: (0) 0:00:00.00

The OID 1.3.6.1.2.1.43.18.1.1.8.1.1 clearly shows the same string ("Toner Low: BK") as seen on the printer display.

What if I simply add this OID into the check_printer_health hardware-health check?

Patching check_printer_health

Luckily I've already worked on Gerhard's plugins in the past, so I (kind of) understand how the components and classes are built up. 

Within the PrinterSubsystem check, a new class Classes::PRINTERMIB::Component::PrinterSubsystem::Alert was added, which checks for an alert string. If any string is found (which is not Sleep), the plugin should alert with a warning:

ck@mint ~/Git/check_printer_health $ git diff
diff --git a/plugins-scripts/Classes/PRINTERMIB/Component/PrinterSubsystem.pm b/plugins-scripts/Classes/PRINTERMIB/Component/PrinterSubsystem.pm
index 4b062fb..4170f1f 100644
--- a/plugins-scripts/Classes/PRINTERMIB/Component/PrinterSubsystem.pm
+++ b/plugins-scripts/Classes/PRINTERMIB/Component/PrinterSubsystem.pm
@@ -9,6 +9,7 @@ sub init {
         ['displays', 'prtConsoleDisplayBufferTable', 'Classes::PRINTERMIB::Component::PrinterSubsystem::Display'],
         ['covers', 'prtCoverTable', 'Classes::PRINTERMIB::Component::PrinterSubsystem::Cover'],
         ['channels', 'prtChannelTable', 'Classes::PRINTERMIB::Component::PrinterSubsystem::Channel'],
+        ['alerts', 'prtAlertTable', 'Classes::PRINTERMIB::Component::PrinterSubsystem::Alert'],
     ]);
   } elsif ($self->mode =~ /device::printer::consumables/) {
     $self->get_snmp_tables('PRINTER-MIB', [
@@ -48,6 +49,20 @@ sub check {
   }
 }

+package Classes::PRINTERMIB::Component::PrinterSubsystem::Alert;
+our @ISA = qw(Monitoring::GLPlugin::SNMP::TableItem);
+use strict;
+
+sub check {
+  my ($self) = @_;
+  $self->add_info(sprintf 'Alert: %s',
+      $self->accentfree($self->{prtAlertDescription})
+  );
+  if ($self->{prtAlertDescription} !~ /Sleep/) {
+    $self->add_warning();
+  }
+}
+
 package Classes::PRINTERMIB::Component::PrinterSubsystem::Display;
 our @ISA = qw(Monitoring::GLPlugin::SNMP::TableItem);
 use strict;

The corresponding PR in the upstream project was already merged as I am writing this article.

This results in the plugin now alerting when an alert message is found:

$ ./check_printer_health --hostname MyBrotherPrinter --mode hardware-health
WARNING - Alert: Toner Low: BK

A new release of check_printer_health will contain this addition.

check_printer_health v1.2 integration into Icinga2

Meanwhile a minor code modification has happened inside the plugin. The prtAlertDescription check still happens, however when the string contains "toner", the message (and alert) will be added under the supplies-status check:

$ ./check_printer_health --hostname MyBrotherPrinter --mode supplies-status
WARNING - Alert: Toner Low: BK | 'Yellow_Drum_Unit_remaining'=72.13%;20:;5:;0;100 'Belt_Unit_remaining'=68.47%;20:;5:;0;100 'Black_Drum_Unit_remaining'=72.13%;20:;5:;0;100 'Cyan_Drum_Unit_remaining'=39.69%;20:;5:;0;100 'Magenta_Drum_Unit_remaining'=39.69%;20:;5:;0;100

This means that starting with check_printer_health v1.2, Brother printers can now also be properly monitored. Unfortunately without performance data on the toner supplies, as the SNMP output does not (seem to) contain relevant toner cartridge usage data.

Adding this into Icinga2 as service checks (after having created the check_printer_health CheckCommand):

# Printer check using check_printer_health
object Service "Printer Supplies Status" {
  import "service-2h-normal"
  host_name = "td-brother-printer"
  check_command = "check_printer_health"
  vars.printer_mode = "supplies-status"
}

# Printer check using check_printer_health
object Service "Printer Hardware Health" {
  import "service-2h-normal"
  host_name = "td-brother-printer"
  check_command = "check_printer_health"
  vars.printer_mode = "hardware-health"
}

And finally, the result in Icinga's UI:

Brother MFC network printer supplies monitored in Icinga2


More recent articles:

RSS feed

Blog Tags:

  AWS   Android   Ansible   Apache   Apple   Atlassian   BSD   Backup   Bash   Bluecoat   CMS   Chef   Cloud   Coding   Consul   Containers   CouchDB   DB   DNS   Database   Databases   Docker   ELK   Elasticsearch   Filebeat   FreeBSD   Galera   Git   GlusterFS   Grafana   Graphics   HAProxy   HTML   Hacks   Hardware   Icinga   Influx   Internet   Java   KVM   Kibana   Kodi   Kubernetes   LVM   LXC   Linux   Logstash   Mac   Macintosh   Mail   MariaDB   Minio   MongoDB   Monitoring   Multimedia   MySQL   NFS   Nagios   Network   Nginx   OSSEC   OTRS   Office   PGSQL   PHP   Perl   Personal   PostgreSQL   Postgres   PowerDNS   Proxmox   Proxy   Python   Rancher   Rant   Redis   Roundcube   SSL   Samba   Seafile   Security   Shell   SmartOS   Solaris   Surveillance   Systemd   TLS   Tomcat   Ubuntu   Unix   VMWare   VMware   Varnish   Virtualization   Windows   Wireless   Wordpress   Wyse   ZFS   Zoneminder