PRTG HP Drucker Sensor

Diese Seite beschreibt einen Custom Sensor für PRTG zur Überwachung eines HP Office Jet Pro 8600 AIO-Geräts. ich bin aber ziemlich sicher, dass damit auch andere HP-Drucker überwacht werden können.

Ich nutze im Home-Office schon länger einen HP Office Jet Pro 8600. Er tut unauffällig seinen Dienst und wird immer brav mit original Tine versorgt. Aber mich hat neugierig gemacht, dass der Drucker auch SNMP unterstützt. Da muss doch was mit PRTG möglich sein. Aus der Überlegung "mal eben schnell" einen HP-Drucker per SNMP zu überwachen ist dann doch ein eigenes Skript geworden. SNMP ist nicht SNMP und wenn der Hersteller keine MIB mitliefert, muss man "vermuten". Wenn dann wichtige Werte wie Seitenzahlen nicht geliefert werden und die Abfrage des Füllstandes einer Patrone (Magenta) nur mit einem Fehler quittiert wird, muss man wieder selbst ran.

PRTG Bordmittel reichen nicht ?

Drucker im Netzwerk können per PRTG überwacht werden. Das geht per ICMP (PING), LPD-Portcheck oder SNMP (wenn vorhanden). PRTG bringt schon einige Sensoren für die Druckerüberwachung mit:

Der "SNMP HP LaserJet Hardware"-Sensor überwacht einen Status für Toner, Papier und "Jam" und zudem kann PRTG per SNMP auch direkt die gedruckten Seiten erfassen.

Für meinen Tintenstrahldrucker hätte ich aber schon gern den Füllstand der verschiedenen Farben und für einen Farblaserdrucker wäre das auch interessant. ein "All in One"- Gerät (AIO) kann sicher noch Daten zur Nutzung der Scanner-Einheit, Faxeinheit und Kopien liefern.

SNMP - Partiell

Der HP Office Jet Pro 8600 kann laut Dokumentation sogar SNMP. Ich habe einige Zeit für die Suche nach einer MIB oder Beschreibung verbracht. Gefunden habe ich letztlich einen wenig hilfreichen Eintrag im Forum und einen Hinweis auf das Handbuch. Wie ich schnell erkennen sollte, ist die SNMP-Implementierung zumindest auf dem HP Office Jet Pro 8600 fehlerhaft.

Es finden sich aber auch Hinweise in Foren wie:

SNMP is broken in the 8600 firmware - has been for a long time - some OID's work, some dont - some only respond to walk requests, not single get requests. Some counters don't even exist (page counts). .1.3.6.1.2.1.43.10.2.1.4.0.1 is the closest # to page counts, and doesn't work with a GET request.
Quele: http://h30434.www3.hp.com/t5/Inkjet-Printing/SNMP-MIB-for-HP-Officejet-Pro-8600/td-p/3665098

Auf den ersten Blick erscheint das alles nicht gerade positiv. ich habe mir dann die OID etwas genauer anschaut und zwei Dinge festgestellt. Zuerst habe ich mich auf die Suche nach der OID 1.3.6.1.2.1.43.11.1.1 gemacht und wurde auf http://cric.grenoble.cnrs.fr/Administrateurs/Outils/MIBS/?module=Printer-MIB fündig.

Wenn ich dann mit dem Paesslers SNMP Tester die OID anspreche, dann muss ich mit SNMPV1 arbeiten und bekommt folgende drei interessante Gruppen:

Unter " 1.3.6.1.2.1.43.11.1.1.6.0" sind die Namen enthalten unter unter " 1.3.6.1.2.1.43.11.1.1.8.0" sieht man eine variable Maximalfüllmenge. Die schwarze Patrone ist größer. Abhängig davon muss man auch die unter " 1.3.6.1.2.1.43.11.1.1.9.0" wiedergegebenen Werte sehen. Der Versuch den Füllstand direkt zu lesen, war natürlich aus zweierlei Gründen nicht von Erfolg gekrönt:

Die Werte unter 1.3.6.1.2.1.43.11.1.1.9.0 sind ohne Bezug auf die maximale Füllmenge von 1.3.6.1.2.1.43.11.1.1.8.0 unbrauchbar und zudem scheint es einen Bug im HP zu geben, dass der letzte Eintrag einer OID-Serie nicht gelesen werden kann. Auch ein direkter Versuch per Abfrage mit dem PRTG SNMP Tester ergibt ein Ergebnis für die ".3" aber "null" für die ".4"

Damit kann ich also nicht mal eine "Custom SNMP-Abfrage" mal schnell bauen, sondern muss einen "SNMPWALK" über die darüber liegende OID machen und die Werte aufsammeln. Eine einfache SNMP-Walk-Klasse in .NET gibt es aber leider nicht. Also bleibt nur die Wahl per UDP-Klasse sich in dem Fall einen eigenen SNMP-Client zu bauen oder eine Kommandozeile oder andere API zu nutzen und deren Ergebnisse zu parsen. Eine kurze Recherche im Internet liefert u.a. folgende Seiten:

Füllstand mit OlePRN.OLESNMP auslesen

Interessant fand ich den ersten Link, der die COM-Klasse "OlePRN.OLESNMP" instanziert.

Eigentlich ist diese Klasse für die Abfrage von Druckern optimiert aber kann anscheinend für andere Zwecke ebenfalls genutzt werden. 

# Klasse instanziere
$SNMP = new-object -ComObject olePrn.OleSNMP

# SNMP Host mit IP-Adresse, Community, Retry und Timeout hinterlegen
$snmp.open("192.168.178.4","public",2,3000)

# Einen einzelnen Wert abfragen. Hier Druckertyp
$snmp.get(".1.3.6.1.2.1.25.3.2.1.3.1")



# einen Teilbaum abfragen
$snmp.gettree(".1.3.6.1.2.1.43.11.1.1") | select -last 16

 

# Versuch die einzelnen Wert abzufragen.
# Hier ist gut zu sehen, dass der HP8600 den letzten Wert nicht liefert.

Damit kann ich mit dann doch sehr schnell ein Powershell-Skript für PRTG-bauen, um den Tonerstand und andere Werte zu ermitteln.

Zählerstände per HTTP

Ich habe natürlich noch weiter nach anderen OIDs gesucht aber anscheinend gibt es keine Entsprechung zu den Statistiken bezüglich gedruckter Seiten.

Es ist von Herstellern schon ein Stück weit unverschämt mit SNMP in den Datenblättern zu werben aber nicht die entsprechenden MIBs zu veröffentlichen. Für den Fehler in der Implementierung des SNMP-Stacks, dass der letzte Eintrag einer Liste mit mit einem WALK statt einem GET zu lesen ist, sollte sich HP schämen.

Die Statistik der gedruckten Seiten kann ich mir immer noch über die HTML-Seite "http://<printerIP>/#hId-pgUsageReport" besorgen.

 

Allerdings sieht das hier nur auf den ersten Blick so aus, dass hier eine HTML-Tabelle mit eindeutigen IDs kommt-. Ein Abruf mit Get-Webrequest liefert nur eine Miniseite und ein Mitschnitt mit Fiddler offenbart auch hier, dass auf dem Client "JavaScript" zur Aufbereitung genutzt wird:

Aber so wird auch schnell offenbar, dass die Informationen sogar in einer XML-Datei über den Pfad "/DevMgmt/ProductUsageDyn.xml" ausgeliefert werden. Allerdings sind nicht alle Knoten direkt eine Nummer, sondern unterschiedlich codiert: Hier am Beispiel von Druckern.

Einige Werte wie "MonochromeImpressions", "ColorImpressions" oder "SimplexSheets" sind direkt erkennbar. Andere wie "TotalImpressions" oder "WirelessNetworkImpressions" etc. sind noch Unterknoten mit einem Text. Auch bei den Werten für die Kopiererfunktion kann ich mir nicht erklären, warum HP die Werte so unterschiedlich ausgibt:

Aber all das ist kein Problem für ein PowerShell-Skript und PRTG. Diese Zahlen müssen ja nicht alle paar Minuten im HomeOffice-Bereich erfasst werden. Selbst die Tonerstände können ja "entspannt" angegangen werden. Insofern ist die Laufzeit des PowerShell-Skripts nicht so kritisch, wenn es z.B. nur einmal die Stunde aufgerufen wird.

Tintentank per HTTP

Durch den "einfachen Abruf" per HTTP für die Seitenstände war ich natürlich neugierig, wie das dann mit den Tintenständen auf der Webseite aussieht. Diese können über die URL "http://<druckerip>/#hId-consumablePage abgerufen werden und sind dann aber als Bilder im HTML-Dokument enthalten. Aber auch hier ist clientseitiges JavaScript für den Seitenaufbau erforderlich und ein Mitschnitt per Fiddler zeigt schnell, wo die Daten herkommen:

Die XML-Datei " "/DevMgmt/ProductUsageDyn.xml" habe ich ja schon für die Seitenzahlen ausgewertet. Die XML-Datei "/DevMgmt/ConsumableConfigDyn.xml" enthält umfangreiche Informationen über die Tinentanks inklusive Tankkapazität, Füllstand aber auch Seriennummern, Garantiezeiten, Refill-Status etc. Hier mal einen Auszug aus der XML

<?xml version="1.0" encoding="UTF-8"?>
<!-- THIS DATA SUBJECT TO DISCLAIMER(S) INCLUDED WITH THE PRODUCT OF ORIGIN. -->
<ccdyn:ConsumableConfigDyn >
	<dd:Version>
		<dd:Revision>SVN-IPG-LEDM.38</dd:Revision>
		<dd:Date>2010-06-02</dd:Date>
	</dd:Version>
	<ccdyn:ProductConsumableInfo>.....</ccdyn:ProductConsumableInfo>
	<ccdyn:ConsumableInfo>...</ccdyn:ConsumableInfo>
	<ccdyn:ConsumableInfo>
		<dd:Capacity>
			<dd:MaxCapacity>241</dd:MaxCapacity>
			<dd:Unit>tenthsOfMilliliters</dd:Unit>
		</dd:Capacity>
		<dd:ConsumableAcceptibilitySubBrand>officejet</dd:ConsumableAcceptibilitySubBrand>
		<dd:ConsumableAcceptibilitySegmentClass>allDevices</dd:ConsumableAcceptibilitySegmentClass>
		<dd:ConsumableAcceptibilityUpgradability>notSupported</dd:ConsumableAcceptibilityUpgradability>
		<dd:ConsumableContentType>markingAgent</dd:ConsumableContentType>
		<dd:ConsumableFamilyName>NESTA</dd:ConsumableFamilyName>
		<dd:ConsumableKeyingDescriptor>large1</dd:ConsumableKeyingDescriptor>
		<dd:ConsumableLabelCode>M</dd:ConsumableLabelCode>
		<dd:ConsumableLifeState>
			<dd:ConsumableState>ok</dd:ConsumableState>
			<dd:MeasuredQuantityState>ok</dd:MeasuredQuantityState>
			<dd:Brand>HP</dd:Brand>
			<dd:ConsumableStateAction>none</dd:ConsumableStateAction>
			<dd:IsRefilled>false</dd:IsRefilled>
		</dd:ConsumableLifeState>
		<dd:ConsumableLevelMessagingStyle>dropCount</dd:ConsumableLevelMessagingStyle>
		<dd:ConsumableLowUseAlgorithm>standard</dd:ConsumableLowUseAlgorithm>
		<dd:ConsumablePercentageLevelRemaining>60</dd:ConsumablePercentageLevelRemaining>
		<dd:ConsumableReplaceabilityType>UserReplaceable</dd:ConsumableReplaceabilityType>
		<dd:ConsumableSelectibilityNumber>951XL</dd:ConsumableSelectibilityNumber>
		<dd:ConsumableStation>0</dd:ConsumableStation>
		<dd:ConsumableTypeEnum>ink</dd:ConsumableTypeEnum>
		<dd:Installation>
			<dd:Date>2015-11-19</dd:Date>
		</dd:Installation>
		<dd:ProductNumber> CN047A</dd:ProductNumber>
		<dd:SerialNumber>1147685736</dd:SerialNumber>
		<dd:RegionalCartridge>
			<dd:RegionIdentifier>1</dd:RegionIdentifier>
		</dd:RegionalCartridge>
		<dd:ConsumableIcon>...</dd:ConsumableIcon>
		<dd:Warranty><dd:ExpirationDate>2016-04-29</dd:ExpirationDate></dd:Warranty>
	</ccdyn:ConsumableInfo>
	<ccdyn:ConsumableInfo>...</ccdyn:ConsumableInfo>
	<ccdyn:ConsumableInfo>...</ccdyn:ConsumableInfo>
	<ccdyn:ConsumableInfo>...</ccdyn:ConsumableInfo>
</ccdyn:ConsumableConfigDyn>

Wer mag kann so also seine Drucker im Netzwerk auch bezüglich der Patronen inventarisieren und Missbrauch oder vorschnelle Wechsel überwachen. Das ganze hat dann aber nicht mehr viel mit einem "Verfügbarkeitsmonitoring" zu tun sondern geht mehr in das Thema "Inventory". Wobei es durchaus interessant sein kann, auch das "Alter" einer Tinenpatrone anhand des Installationsdatums zu ermitteln. Für die Lagerhaltung könnte es interessant sein, die Differenz von Installationsdatum und Garantie-Endedatum zu ermitteln. Wer also viele HP-Drucker betreibt, könnte als Inventory-Skript diese und andere Daten sammeln.

Ich belasse das Auslesen des Füllstandes aktuell einmal bei SNMP und stelle das vielleicht in einer späteren Version einmal um.

Irrweg: IPP Internet Printing Protocol

Die meisten Drucker unterstützen aber mittlerweile auch das IPP-Protokoll zum Drucken und zur Statusabfrage. Diese Schnittstelle haben fast alle modernen Drucker, da Clients per UPNP und IPP ziemlich alleine Drucker im LAN (und insbesondere im Haus-LAN) finden. Technisch ist IPP einfach nur ein HTTP-Service auf dem Port 631/TCP, der alle Funktionen des HTTP-Stacks mitbringt. Vereinfacht lässt sich sagen, dass IPP auf der Seite des Druckers ein Webserver ist, der auf dem Port 631 wartet. Er kann die komplette Funktionen eines Webservers bezüglich Authentifizierung, Verschlüsselung, Chunking, Streaming etc. Unterstützen. CUPS nutzt meines Wissens 631/UDP. Der Client sendet einen HTTP-POST-Request mit dem MIME-Type "application/ipp" an den Drucker samt der erforderlichen Daten. Ohne SSL können diese Pakete einfach per Wireshark oder NetMon 3 mitgelesen werden.

Zuerst musste ich den Drucker aber unter Windows 7 per IPP einrichten. Das geht relativ einfach mit einem HP OfficeJet 8600 über den Assistenten. Der Anwender muss nur den Namen oder die IP-Adresse als HTTP-URL angeben aber dabei natürlich den Port 631 und eine Start-URL mitgeben.

Andere Drucker haben eventuell andere "Adressen". Ein Blick ins Handbuch oder Suche im Internet liefert die erforderlichen Daten meist sehr schnell.

Ich habe die Links und URLs mitgeschnitten, die bei mir alle "unverschlüsselt" waren und in den Stream verschiedene Texte und Hinweise gesehen aber keine Informationen, die für ein Monitoring interessant wären. Es waren keine Seitenzahlen, Tonerstände, Betriebszeiten o.ä. zu erkennen. IPP scheint wirklich nur für die Einrichtung am Anfang, die Übergabe von Jobs und die Rückmeldung über das Druckende mit Status geeignet zu sein.

Dann kam aber doch noch ein Lichtblick durch einen Artikel in der c't 10/2015 Seite 164ff, der mehr Details zu IPP beschreibt und vor allem    

Die kostenfreien IPPTools für Windows erlauben u.a. die Abfrage von Druckern über IPP durch eine Kommandozeile. Damit erspare ich mir die Mühe das Protokoll quasi in PowerShell zu codieren. Allerdings habe ich nur Beispiele für den Abruf der Tonerstände gefunden aber die ganzen Informationen über Seitenzahlen etc. konnte ich noch nicht ermitteln. Auch die Abhängigkeit und Installation von einer Zusatzsoftware finde ich eher lästig. Daher habe ich einen alternativen Weg eingeschlagen

Daten aus Webseite extrahieren

Ehe ich den Weg über die XML-Dateien und SNMP entdeckt habe, hatte ich versucht den Status direkt von der Webseite zu parsen. Es gibt leider immer noch Geräte, die einfach nur eine Webseite anbieten oder ein anderer Weg zumindest nicht "bekannt" ist.

Auf den ersten Blick sieht das auch noch ganz nett aus. Die Seitenzahlen sind numerisch in einer HTML-Tabelle zu sehen.

Die einzelne Tabelle ist mit einer "ID" versehen, was die Selektion vereinfacht und im Body sind sowohl die Beschreibung als auch der Wert dazu recht einfach zu parsen. Das sollte nicht so schwer werden, diese Daten wieder zu extrahieren und an PRTG zu übergeben. Kniffliger ist es die Daten für den Tonerfüllstand zu ermitteln. Diese sind leider nirgends als "Zahl" zu finden, sondern nur schöne Bilder:

 

Diese werden interessanterweise aus 10 "DIV"-Blöcken aufgebaut, die als Klasse dann die Formatierung der dahinter liegenden Grafik vorgeben. Sehr interessante Lösung für diese Anzeige. So muss der Drucker nichts "Rendern". Aber auch dies sollte man recht einfach parsen können, indem man die HTML-Datei an den "<div class="ink-inkLevel_div">" String aufteilt und dann von "10" die Anzahl der "<div class="ink-gauge-empty-top"></div>" Einträge abzieht.

Als ich damals mit Fiddler kontrolliert habe, was der Browser vom Drucker lädt, konnte ich den Teil im HTML-Dokument aber nicht finden. Und so habe ich dann zwangsläufig entdeckt, das die Webseite erst auf dem Client mit javaScript "schick" gemacht wird.

PRTG-Skript

Auf der Seite PRTG Kostal  habe ich schon vorgemacht, wie ich von einem Webserver meines Solar-Wechselrichters die Daten abgreife und in PRTG einspeise. Basierend auf dem Skript habe ich einen Custom Sensor für den HP-Drucker erstellt, der einmal pro Stunde die Tonerstände per SNMP abruft und die Seitenzahlen per HTTP. Da sich alles im Hauslan befindet, habe ich auf eine Authentifizierung per HTTP verzichtet. Bei SNMPv1 ist es sowieso nicht möglich.

prtg-hpdrucker.1.0.ps1.txt
Nach dem Download bitte die Erweiterung .TXT entfernen.

Wie üblich und auf PRTG:Custom Sensor schon beschrieben, kopieren Sie das Skript einfach nach EXEXML ihrer PRTG-Installation oder der Probe und binden es als neuen Sensor vom Typ "EXE Custom" ein. In der Auswahlliste der Skripte sollte dann PRTG-HP8600.PS1 erscheinen.

Wenn die die IP-Adresse des Druckers nicht direkt im Skript anpassen, dann müssen Sie diese als Parameter angeben. Auch sollten Sie der Vererbung des Aufrufinterfalls abschalten und z.B. das Skript nicht alle 60Sek starten. Nach dem ersten Lauf können Sie dann bestimmen, welcher "Channel" als primärer Kanal erscheint. Ich habe extra einen errechneten Kanal "Ink Lowest" addiert, der das Minimum aller Füllstände enthält. Das bietet sich natürlich dann als primärer Kanal an. Und so kann das Ganze dann aussehen:

Wenn es ihnen zu viele Kanäle sind, können Sie diese natürlich ausblenden oder gleich im Skript die Generierung der Daten unterbinden. Einfach hier die entsprechenden Ausgaben auskommentieren.

Andere Drucker

Mein kleiner OfifceJetPro 8600 ist sicher nicht der einzige HP-Drucker im Feld und es liegt nahe, dass HP die Firmware auch in anderen Druckern verwendet. Also bin ich einfach mal auf einen HP Laserdrucker gegangen und fündig geworden.

HP Drucker URL Inhalte

HP LaserJet 300 color MFP

/DevMgmt/ProductUsageDyn.xml

  • Seitenzahlen SWQ/Color
  • Verteilung nach PCL5/PCL6/PS
  • Aktueller Tonerdaten wie Seriennummer, Füllstand und Restlaufzeit, Installationsdatum
  • Grauwertverteilung der  Seiten
  • Anzahl der Scanvorgänge
  • Anzahl der Faxvorgänge

HP LaserJet 300 color MFP

/DevMgmt/ProductStatusDyn.xml

  • Eine kurze Tabelle mit Alert

HP Laserjet 3015

/DevMgmt/ProductStatusDyn.xml

Wie beim LJ300

HP Laserjet 3015

/DevMgmt/ProductUsageDyn.xml

Wie beim LJ300

Wenn ich mir das so anschauen und daran denke, dass diese Daten in den meisten Fällen ohne Authentifizierung erreichbar sein werden, dann könnte der PRTG-Sensor, den ich gerade mal für den HP8600 gebaut habe, auch für viele andere HP-Drucker funktionieren. Mit einem etwas ausgereifteren Skript könnten die XML-Antworten für vermutlich sehr viele HP-Drucker für PRTG aufbereitet werden.

Offen

Es gibt schon erste Überlegungen, wie ich den Sensor "verbessern" kann:

  • Connectivity Check
    Ich betrachte einige Zeit lang die Ausgaben der Sensoren auf meinen HP Druckern. Zuerst würde ich wohl einen PING addieren, um die Erreichbarkeit des Druckers sicher zu stellen und so die Zeit für eine SNMP-Anfrage per UDP oder eine HTTP-Anfragen zu reduzieren, wenn der Drucker eh offline ist.
  • Ergebnisse aufteilen
    Aktuell sind alle Ergebnisse in einem Sensor mit unterschiedlichen Kanälen zusammen gefasst. Es könnte sinnvoll sein, per Parameter vielleicht nur eine Teilmenge zurück zu liefern

Danke der Flexibilität der PRT Custom Sensoren sollte aber vieles lösbar sein.

Weitere Links