How can I access ink levels of printers programmatically?

后端 未结 4 660
南笙
南笙 2021-02-02 04:44

Okay, this is a Windows specific question.

I need to be able to access the ink levels of a printer connected to a computer. Possibly direct connection, or a network conn

相关标签:
4条回答
  • 2021-02-02 04:51

    Okay, this is a OS agnostic answer... :-)

    If the printer isn't a very cheapo model, it will have built-in support for SNMP (Simple Network Management Protocol). SNMP queries can return current values from the network devices stored in their MIBs (Management Information Bases).

    For printers there's a standard defined called Printer MIB. The Printer MIB defines standard names and tree locations (OIDs == Object Identifiers in ASN.1 notation) for prtMarkerSuppliesLevel which in the case of ink marking printers map to ink levels.

    Be aware that SNMP also allows private extensions to the standard MIBs. Most printer vendors do hide many additional pieces of information in their "private MIBs", though the standard info should always be available through the queries of the Printer MIB OIDs.

    Practically every programming language has standard libraries which can help you to make specific SNMP queries from your own application.

    One such implementation is Open Source, called Net-SNMP, which also comes with a few powerfull commandline tools to run SNMP queries.

    I think the OID to query all levels for all inks is .1.3.6.1.2.1.43.11.1.1.9 (this webpage confirms my believe) but I cannot verify that right now, because I don't have a printer around in my LAN at the moment. So Net-SNMP's snmpget command to query ink levels should be something like:

    snmpget                       \
      -c public                   \
       192.168.222.111            \
       ".1.3.6.1.2.1.43.11.1.1.9"
    

    where public is the standard community string and 192.168.222.111 your printer's IP address.

    0 讨论(0)
  • 2021-02-02 04:56

    I have an SNMP-capable HP 8600 pro N911a around to do some digging, so the following commands may help you a bit. Beware that this particular model has some firmware problems, you can't query "magenta" with snmpget, but you see a value with snmpwalk (which does some kind of recursive drill-down).

    OLD: You can query the names and sequence of values, but I couldn't find the "max value" to calculate a clean percentage so far ;(. I'm guessing so far the values are relative to 255, so dividing by 2.55 yields a percentage.

    Update: Marcelo's hint was great! From Registers .8.* you can read the max level per cartridge, and I was totally wrong assuming the max value can only be an 8-bit value. I have updated the sample script to read the max values and calculate c

    There is also some discussion over there at Cacti forums. One answer confirms that the ink levels are measured as percent (value 15 is "percent" in an enumeration):

    # snmpwalk -v1 -c public 192.168.100.173 1.3.6.1.2.1.43.11.1.1.7                 
    SNMPv2-SMI::mib-2.43.11.1.1.7.0.1 = INTEGER: 15
    SNMPv2-SMI::mib-2.43.11.1.1.7.0.2 = INTEGER: 15
    SNMPv2-SMI::mib-2.43.11.1.1.7.0.3 = INTEGER: 15
    SNMPv2-SMI::mib-2.43.11.1.1.7.0.4 = INTEGER: 15
    

    You need to install the net-snmp package. If you're not on Linux you might need some digging for SNMP command line tools for your preferred OS.

    # snmpwalk -v1 -c public 192.168.100.173 1.3.6.1.2.1.43.11.1.1.6.0
    SNMPv2-SMI::mib-2.43.11.1.1.6.0.1 = STRING: "black ink"
    SNMPv2-SMI::mib-2.43.11.1.1.6.0.2 = STRING: "yellow ink"
    SNMPv2-SMI::mib-2.43.11.1.1.6.0.3 = STRING: "cyan ink"
    SNMPv2-SMI::mib-2.43.11.1.1.6.0.4 = STRING: "magenta ink"
    
    # snmpwalk -v1 -c public 192.168.100.173 1.3.6.1.2.1.43.11.1.1.9.0
    SNMPv2-SMI::mib-2.43.11.1.1.9.0.1 = INTEGER: 231
    SNMPv2-SMI::mib-2.43.11.1.1.9.0.2 = INTEGER: 94
    SNMPv2-SMI::mib-2.43.11.1.1.9.0.3 = INTEGER: 210
    SNMPv2-SMI::mib-2.43.11.1.1.9.0.4 = INTEGER: 174
    
    # snmpwalk -v1 -c praxis 192.168.100.173 1.3.6.1.2.1.43.11.1.1.8.0
    SNMPv2-SMI::mib-2.43.11.1.1.8.0.1 = INTEGER: 674
    SNMPv2-SMI::mib-2.43.11.1.1.8.0.2 = INTEGER: 240
    SNMPv2-SMI::mib-2.43.11.1.1.8.0.3 = INTEGER: 226
    SNMPv2-SMI::mib-2.43.11.1.1.8.0.4 = INTEGER: 241
    

    On my Linux box I use the following script to do some pretty-printing:

    #!/bin/sh
    
    PATH=/opt/bin${PATH:+:$PATH}
    
    # get current ink levels
    eval $(snmpwalk -v1 -c praxis 192.168.100.173 1.3.6.1.2.1.43.11.1.1.6.0 |
    perl -ne 'print "c[$1]=$2\n" if(m!SNMPv2-SMI::mib-2.43.11.1.1.6.0.(\d) = STRING:\s+"(\w+) ink"!i);')
    
    # get max ink level per cartridge
    eval $(snmpwalk -v1 -c praxis 192.168.100.173 1.3.6.1.2.1.43.11.1.1.8.0 |
    perl -ne 'print "max[$1]=$2\n" if(m!SNMPv2-SMI::mib-2.43.11.1.1.8.0.(\d) = INTEGER:\s+(\d+)!i);')
    
    snmpwalk -v1 -c praxis 192.168.100.173 1.3.6.1.2.1.43.11.1.1.9.0 |
    perl -ne '
        my @c=("","'${c[1]}'","'${c[2]}'","'${c[3]}'","'${c[4]}'");
        my @max=("","'${max[1]}'","'${max[2]}'","'${max[3]}'","'${max[4]}'");
        printf"# $c[$1]=$2 (%.0f)\n",$2/$max[$1]*100
            if(m!SNMPv2-SMI::mib-2.43.11.1.1.9.0.(\d) = INTEGER:\s+(\d+)!i);'
    
    0 讨论(0)
  • 2021-02-02 04:56

    An alternative approach could be using ipp. While most of the printers I tried support both, I found one which only worked with ipp and one that only worked for me with snmp.

    Simple approach with ipptool:

    • Create file colors.ipp:
    {
        VERSION 2.0
        OPERATION Get-Printer-Attributes
    
        GROUP operation-attributes-tag
        ATTR charset "attributes-charset" "utf-8"
        ATTR naturalLanguage "attributes-natural-language" "en"
        ATTR uri "printer-uri" $uri
        ATTR name "requesting-user-name" "John Doe"
        ATTR keyword "requested-attributes" "marker-colors","marker-high-levels","marker-levels","marker-low-levels","marker-names","marker-types"
    }
    
    • Run:
    ipptool -v -t ipp://192.168.2.126/ipp/print colors.ipp
    
    • The response:
    "colors.ipp":
        Get-Printer-Attributes:
            attributes-charset (charset) = utf-8
            attributes-natural-language (naturalLanguage) = en
            printer-uri (uri) = ipp://192.168.2.126/ipp/print
            requesting-user-name (nameWithoutLanguage) = John Doe
            requested-attributes (1setOf keyword) = marker-colors,marker-high-levels,marker-levels,marker-low-levels,marker-names,marker-types
        colors                                                               [PASS]
            RECEIVED: 507 bytes in response
            status-code = successful-ok (successful-ok)
            attributes-charset (charset) = utf-8
            attributes-natural-language (naturalLanguage) = en-us
            marker-colors (1setOf nameWithoutLanguage) = #00FFFF,#FF00FF,#FFFF00,#000000,none
            marker-high-levels (1setOf integer) = 100,100,100,100,100
            marker-levels (1setOf integer) = 6,6,6,6,100
            marker-low-levels (1setOf integer) = 5,5,5,5,5
            marker-names (1setOf nameWithoutLanguage) = Cyan Toner,Magenta Toner,Yellow Toner,Black Toner,Waste Toner Box
            marker-types (1setOf keyword) = toner,toner,toner,toner,waste-toner
    

    marker-levels has current toner/ink levels, marker-high-levels are maximus (so far I've only seen 100s here), marker-names describe meaning of each field (tip: for colors you may want to strip everything after first space, many printers include cartridge types in this field).

    Note: the above is with cups 2.3.1. With 2.2.1 I had to specify the keywords as one string instead ("marker-colors,marker-h....). Or it can be left altogether, then all keywords are returned.

    More on available attributes (may differ between printers): https://www.cups.org/doc/spec-ipp.html
    More on executing ipp calls (including python examples): https://www.pwg.org/ipp/ippguide.html

    0 讨论(0)
  • 2021-02-02 05:11

    I really liked tseeling's approach!

    Complementarily, I found out that the max value for the OID ... .9 is not 255 as guessed by him, but it actually varies per individual cartridge. The values can be obtained from OID .1.3.6.1.2.1.43.11.1.1.8 (the results obtained by dividing by these values match the ones obtained by running hp-inklevels command from hplip.

    I wrote my own script that output CSVs like below (suppose printer IP addr is 192.168.1.20):

    # ./hpink 192.168.1.20
    black,73,366,19.9454
    yellow,107,115,93.0435
    cyan,100,108,92.5926
    magenta,106,114,92.9825
    

    values are in this order: <color_name>,<level>,<maxlevel>,<percentage>

    The script source (one will notice I usually prefer awk over perl when the puzzle is simple enough):

    #!/bin/sh
    
    snmpwalk -v1 -c public $1 1.3.6.1.2.1.43.11.1.1 | awk '
    
    /.*\.6\.0\./ {
      sub(/.*\./,"");
      split($0,TT,/[ "]*/);
      color[TT[1]]=TT[4];
    }
    
    /.*\.8\.0\./ {
      sub(/.*\./,"");
      split($0,TT,/[ "]*/);
      maxlevel[TT[1]]=TT[4];
    }
    
    /.*\.9\.0\./ {
      sub(/.*\./,"");
      split($0,TT,/[ "]*/);
      print color[TT[1]] "," TT[4] "," maxlevel[TT[1]] "," TT[4] / maxlevel[TT[1]] * 100;
    }'
    
    0 讨论(0)
提交回复
热议问题