How to read SNMP OID Output (bits) (hrPrinterDetectedErrorState)

8.3k views Asked by At

I have a quick question. Its most likely user error so I apologize before I begin.

I’m trying to setup threshold for a device so that it will alert us when one of our printers is in a certain state. (Jammed, out of toner, no paper etc) I’ve found the specific oid that handles this. (1.3.6.1.2.1.25.3.5.1.2.1) The specific oid is called hrPrinterDetectedErrorState under the HOST-RESOURCE-MIB. I’ve verified that I can see the oid via SNMPWALK. My problem is interpreting the data its spitting out. What i'm reading in the MIB and what i'm seeing via SNMPWALK are different.

Here is the description of oid from the MIB:

     "This object represents any error conditions detected
      by the printer.  The error conditions are encoded as
      bits in an octet string, with the following
      definitions:

            Condition        Bit #

            lowPaper              0

            noPaper              1
            lowToner              2
            noToner              3
            doorOpen              4
            jammed                5
            offline              6
            serviceRequested      7
            inputTrayMissing      8
            outputTrayMissing    9
            markerSupplyMissing  10
            outputNearFull      11
            outputFull          12
            inputTrayEmpty      13
            overduePreventMaint  14

      Bits are numbered starting with the most significant
      bit of the first byte being bit 0, the least
      significant bit of the first byte being bit 7, the
      most significant bit of the second byte being bit 8,
      and so on.  A one bit encodes that the condition was
      detected, while a zero bit encodes that the condition
      was not detected.

      This object is useful for alerting an operator to
      specific warning or error conditions that may occur,
      especially those requiring human intervention."

The odd part is that SNMPWALK says the oid is a Hex-String while the MIB specifies that it should be a Octet-String. Are the two different? Do I need to convert the data that is output by SNMPWALK somehow to get it to match up with what the MIB is saying?

To test everything, I put the printer into several different “States.” I then ran an SNMPWALK on the device to see what the oid output. Here are the results. As you will see, these results don’t match up to what the MIB specifies.

Case 1: Opened the toner door

Expected Output based on MIB: 4
SNMP Output: 08

Case 2: Removed Toner & Closed the door

Expected Output based on MIB:  1
SNMP Output:  10

Case 3: Placed 1 sheet of paper and printed a 2 page document. The printer ran out of paper.

Expected Output based on MIB: 0 or 1
SNMP Output: @

I’m confused at the output. I just need to know how to read the oid so I can setup thresholds so that when it sees, for example, a 08 it performs a certain action.

Thanks for your help!

2

There are 2 answers

3
Vajura On BEST ANSWER

You are reading this wrong. The data you receive back should actually be interpreted as a bit array and every bit is its own value for the specific alarm in your case

Expected Output based on MIB: 4
SNMP Output: 08

You actually get back the output:

00001000 00000000

The first byte here covers those values

lowPaper             0
noPaper              1
lowToner             2
noToner              3
doorOpen             4
jammed               5
offline              6
serviceRequested     7

So lowPaper is bit 0, noPaper is bit 1, lowToner is bit 2, etc. And doorOpen is bit 4 and as you can see that bit is set, indicating that the door is open.

EDIT:

This is very dependent on the device and implementation. To know how to parse it right involves a lot of trial and error (at least from my experience). As an example if you get back the message 9104, this could be either be

91 and 04 are separate so you first translate 91 to binary from hex and then the 
same thing with 04
91: 10010001
04: 00000100

Which would mean low paper, noToner, service requested and inputTrayEmpty. This looks like the most likely way this works.

If you only get one byte back this then means you should only look for alarms in the first 8 bits. As a example of things you need to look out for: If the only alarm present is doorOpen you could be getting back only 08 but it would actually be 0008 where the first 2 hex chars are actually the second part of the alarms but aren't shown because they are none present. So in your case you actually first have to switch the bytes (if there are 4) parse the first two and the second two on their own and then you get the actual result.

As I said there is no real standard here from what i have seen and you have to just work with it until you are sure you know how the data is sent and how to parse it.

0
js2010 On

Powershell function to interpret the hrPrinterDetectedErrorState octetstring. (I feel like there's some more often used way to do this?) I've been using this module, but it doesn't even resolve hostnames to ip addresses. The data property returned is just a string (.tostring()) not an octetstring type. None of the printers are snmp v3. https://www.powershellgallery.com/packages/SNMP/1.0.0.1 (note this doesn't handle bytes outside the ascii range well, -gt 0x7e, replaces with a '?')

A single byte would have to be padded with a zero. Most of the time only one byte is sent. The bytes are in the, I think confusing, order that it's documented in. Converting two bytes to an integer results in a different order (depending on big endian or little endian order).

function snmpmessage {

  param($data)

  [flags()] Enum hrPrinterDetectedErrorState
  {
    # more common group
    LowPaper            = 0x0080
    NoPaper             = 0x0040
    LowToner            = 0x0020
    NoToner             = 0x0010
    DoorOpen            = 0x0008
    Jammed              = 0x0004
    Offline             = 0x0002
    ServiceRequested    = 0x0001

    InputTrayMissing    = 0x8000
    OutputTrayMissing   = 0x4000
    MarkerSupplyMissing = 0x2000
    OutputNearFull      = 0x1000
    OutputFull          = 0x0800
    InputTrayEmpty      = 0x0400
    OverduePreventMaint = 0x0200
  }

  $bytes = [byte[]][char[]]$data

  if ($bytes.count -eq 1) { $bytes = $bytes[0],0 } # pad 0
  $code = [bitconverter]::ToUInt16($bytes, ($startIndex=0))

  [hrPrinterDetectedErrorState]$code

}

snmpmessage -join [char[]](1,4)

ServiceRequested, InputTrayEmpty


snmpmessage '@' # 0x40

NoPaper

Or:

$hrPrinterDetectedErrorState = '1.3.6.1.2.1.25.3.5.1.2.1'
$hostname = 'myprinter01'
$ip = (Resolve-DnsName $hostname).ipaddress
$result = Get-SnmpData -ip $ip -oid $hrPrinterDetectedErrorState -v v1
snmpmessage $result.data

LowToner


# ?
# $octetstring = [Lextm.SharpSnmpLib.OctetString]::new($result.data)