HP Printer over SNMP

Since very nice HP Printer component available as HACS integration works only with devices exposing their status via shared .xml files (which is case for only selected models), I started investigation on how HP laser printers can be monitored from home assistant. I found quite a bit of relevant information about monitoring printers paramenter via SMNP on Solar Winds web page:
https://documentation.solarwindsmsp.com/N-central/documentation/Content/Services/Printer/Services_PrinterTonerLevel.html
I used this as a starting point to investigate a bit more in depth how can I monitor my HP Color LaserJet CP1515n printer and finally I come to something that satisfied me. Since it looks that my printer configuration page is similar to what other members shared for their printers, I thought it might also work for them, being somehow reusable…

So here is the end result:

To come up with these results I had to create set of SNMP sensors:

##########################################################
## Printer information via SNMP
##########################################################

# Printer status

  - platform: snmp
    name: 'cp1515n_total_pages_printed'
    host: 192.168.52.42
    baseoid: 1.3.6.1.2.1.43.10.2.1.4.1.1
    accept_errors: true
    scan_interval: 60
    unit_of_measurement: 'total pages printed'

  - platform: snmp
    name: 'cp1515n_color_pages_printed'
    host: 192.168.52.42
    baseoid: 1.3.6.1.4.1.11.2.3.9.4.2.1.4.1.2.7.0
    accept_errors: true
    scan_interval: 60
    unit_of_measurement: 'color pages printed'

  - platform: snmp
    name: 'cp1515n_printer_status_code'
    host: 192.168.52.42
    baseoid: 1.3.6.1.2.1.25.3.5.1.1.1
    accept_errors: true
    scan_interval: 5

  - platform: snmp
    name: 'cp1515n_printer_error_code'
    host: 192.168.52.42
    baseoid: 1.3.6.1.4.1.11.2.3.9.4.2.1.4.1.2.22.0
    accept_errors: true
    scan_interval: 5

  - platform: snmp
    name: 'cp1515n_uptime'
    host: 192.168.52.42
    baseoid: 1.3.6.1.2.1.1.3.0
    accept_errors: true
    scan_interval: 1

  - platform: template
    sensors:
      cp1515n_bw_pages_printed:
        friendly_name: "B&W pages printed"
        unit_of_measurement: 'B&W pages printed'
        value_template: "{{ (states('sensor.cp1515n_total_pages_printed')|float - states('sensor.cp1515n_color_pages_printed')|float) | round(0) }}"

      cp1515n_printer_error:
        friendly_name: "Printer Error"
        value_template: >-
          {% if is_state('sensor.cp1515n_printer_error_code', '0') %}
            Low supply of paper
          {% elif is_state('sensor.cp1515n_printer_error_code', '1') %}
            No paper available
          {% elif is_state('sensor.cp1515n_printer_error_code', '2') %}
            Low supply of toner
          {% elif is_state('sensor.cp1515n_printer_error_code', '3') %}
            No toner available
          {% elif is_state('sensor.cp1515n_printer_error_code', '4') %}
            A door on the printer is open
          {% elif is_state('sensor.cp1515n_printer_error_code', '5') %}
            The printer is jammed
          {% elif is_state('sensor.cp1515n_printer_error_code', '6') %}
            The printer is offline
          {% elif is_state('sensor.cp1515n_printer_error_code', '7') %}
            Technical service is requested for the printer
          {% elif is_state('sensor.cp1515n_printer_error_code', '8') %}
            The input tray is missing or not installed properly
          {% elif is_state('sensor.cp1515n_printer_error_code', '9') %}
            The output tray is missing or not installed properly
          {% elif is_state('sensor.cp1515n_printer_error_code', '10') %}
            The marker supply is missing or not installed properly
          {% elif is_state('sensor.cp1515n_printer_error_code', '11') %}
            The output tray is nearly full
          {% elif is_state('sensor.cp1515n_printer_error_code', '12') %}
            The output tray is full
          {% elif is_state('sensor.cp1515n_printer_error_code', '13') %}
            The input tray is empty
          {% elif is_state('sensor.cp1515n_printer_error_code', '14') %}
            The printer is overdue for preventative maintenance
          {% else %}  
            Unknown
          {% endif %}

      cp1515n_printer_status:
        friendly_name: "Printer Status"
        value_template: >-
          {% if is_state('sensor.cp1515n_printer_status_code', '1') %}
            Other
          {% elif is_state('sensor.cp1515n_printer_status_code', '2') %}
            Unknown
          {% elif is_state('sensor.cp1515n_printer_status_code', '3') %}
            Idle
          {% elif is_state('sensor.cp1515n_printer_status_code', '4') %}
            Printing
          {% elif is_state('sensor.cp1515n_printer_status_code', '5') %}
            Warming Up
          {% else %}  
            Unknown
          {% endif %}

      cp1515n_printer_uptime:
        friendly_name: "Printer Uptime"
        value_template: >-
          {% set t = states('sensor.cp1515n_uptime') | int %}
          {% set t = (t/10) | int %}
          {{ '{:d}d {:02d}h {:02d}m {:02d}s'.format(t // 86400, (t // 3600) % 24, (t % 3600) // 60, (t % 3600) % 60) }}

# Black toner
  - platform: snmp
    name: 'cp1515n_black_capacity'
    host: 192.168.52.42
    baseoid: 1.3.6.1.2.1.43.11.1.1.8.1.1
    accept_errors: true
    scan_interval: 3600
    #unit_of_measurement: '%'

  - platform: snmp
    name: 'cp1515n_black_remainig'
    host: 192.168.52.42
    baseoid: 1.3.6.1.2.1.43.11.1.1.9.1.1
    accept_errors: true
    scan_interval: 3600
    #unit_of_measurement: '%'

  - platform: template
    sensors:
      cp1515n_black_level:
        friendly_name: "Black Tomer Level"
        unit_of_measurement: '%'
        value_template: "{{ (states('sensor.cp1515n_black_remainig')|float / states('sensor.cp1515n_black_capacity')|float * 100) | round(0) }}"

# Cyan tomer
  - platform: snmp
    name: 'cp1515n_cyan_capacity'
    host: 192.168.52.42
    baseoid: 1.3.6.1.2.1.43.11.1.1.8.1.2
    accept_errors: true
    scan_interval: 3600
    #unit_of_measurement: '%'

  - platform: snmp
    name: 'cp1515n_cyan_remainig'
    host: 192.168.52.42
    baseoid: 1.3.6.1.2.1.43.11.1.1.9.1.2
    accept_errors: true
    scan_interval: 3600
    #unit_of_measurement: '%'

  - platform: template
    sensors:
      cp1515n_cyan_level:
        friendly_name: "Cyan Tomer Level"
        unit_of_measurement: '%'
        value_template: "{{ (states('sensor.cp1515n_cyan_remainig')|float / states('sensor.cp1515n_cyan_capacity')|float * 100) | round(0) }}"

# Magenta tomer   
  - platform: snmp
    name: 'cp1515n_magenta_capacity'
    host: 192.168.52.42
    baseoid: 1.3.6.1.2.1.43.11.1.1.8.1.3
    accept_errors: true
    scan_interval: 3600
    #unit_of_measurement: '%'

  - platform: snmp
    name: 'cp1515n_magenta_remainig'
    host: 192.168.52.42
    baseoid: 1.3.6.1.2.1.43.11.1.1.9.1.3
    accept_errors: true
    scan_interval: 3600
    #unit_of_measurement: '%'

  - platform: template
    sensors:
      cp1515n_magenta_level:
        friendly_name: "Magenta Tomer Level"
        unit_of_measurement: '%'
        value_template: "{{ (states('sensor.cp1515n_magenta_remainig')|float / states('sensor.cp1515n_magenta_capacity')|float * 100) | round(0) }}"

# Yellow toner
  - platform: snmp
    name: 'cp1515n_yellow_capacity'
    host: 192.168.52.42
    baseoid: 1.3.6.1.2.1.43.11.1.1.8.1.4
    accept_errors: true
    scan_interval: 3600
    #unit_of_measurement: '%'

  - platform: snmp
    name: 'cp1515n_yellow_remainig'
    host: 192.168.52.42
    baseoid: 1.3.6.1.2.1.43.11.1.1.9.1.4
    accept_errors: true
    scan_interval: 3600
    #unit_of_measurement: '%'

  - platform: template
    sensors:
      cp1515n_yellow_level:
        friendly_name: "Yellow Tomer Level"
        unit_of_measurement: '%'
        value_template: "{{ (states('sensor.cp1515n_yellow_remainig')|float / states('sensor.cp1515n_yellow_capacity')|float * 100) | round(0) }}"

To make it usable obviously you need to change IP address in all of the sensors to one of your printer (perhaps I’ll improve this one day to have it parametrized :-)). I’ll also dig bit further, perhaps I’ll find some more usefull information available via SNMP formore sensors.

And here is the code for Lovelace card on screenshot above:

cards:
  - content: |
      ## <ha-icon icon="mdi:printer"></ha-icon> HP Color LaserJet CP1515n
    type: markdown
  - type: divider
  - content: >
      ### <ha-icon icon="mdi:information-variant"></ha-icon> Printer status: {{
      states('sensor.cp1515n_printer_status') }}

      ### <ha-icon icon="mdi:alert-outline"></ha-icon> Printer error: {{
      states('sensor.cp1515n_printer_error') }}

      ### <ha-icon icon="mdi:clock-check-outline"></ha-icon> Printer uptime: {{
      states('sensor.cp1515n_printer_uptime') }}
    type: markdown
  - type: divider
  - content: >
      ### <ha-icon icon="mdi:counter"></ha-icon> Total pages printed: {{
      states('sensor.cp1515n_total_pages_printed') }}

      ### <ha-icon icon="mdi:counter"></ha-icon> Color pages printed: {{
      states('sensor.cp1515n_color_pages_printed') }}

      ### <ha-icon icon="mdi:counter"></ha-icon> B&W pages printed: {{
      states('sensor.cp1515n_bw_pages_printed') }}
    type: markdown
  - type: divider
  - content: |
      ## <ha-icon icon="mdi:invert-colors"></ha-icon> Toner levels:
    type: markdown
  - cards:
      - align: center
        animation: auto
        animiation: 'on'
        attribute: false
        background_style: false
        card_style: false
        charge_entity: false
        color: '#222222'
        decimal: false
        delay: 5000
        direction: up
        entities:
          - entity: sensor.cp1515n_black_level
        entity: sensor.cp1515n_black_level
        height: 150px
        icon: false
        icon_position: 'off'
        icon_style: false
        indicator: auto
        limit_value: false
        max: 100
        min: 0
        minmax_style: false
        padding: 4px
        rounding: 3px
        saturation: 100%
        severity: false
        show_minmax: false
        show_value: true
        speed: 1000
        tap_action: info
        target: 10
        title: Black
        title_position: bottom
        title_style: false
        type: 'custom:bar-card'
        unit_of_measurement: false
        value_style: false
        visibility: false
        width: 75%
      - align: center
        animation: auto
        animiation: 'on'
        attribute: false
        background_style: false
        card_style: false
        charge_entity: false
        color: '#00ffff'
        decimal: false
        delay: 5000
        direction: up
        entities:
          - entity: sensor.cp1515n_cyan_level
        entity: sensor.cp1515n_cyan_level
        height: 150px
        icon: false
        icon_position: 'off'
        icon_style: false
        indicator: auto
        limit_value: false
        max: 100
        min: 0
        minmax_style: false
        padding: 4px
        rounding: 3px
        saturation: 100%
        severity: false
        show_minmax: false
        show_value: true
        speed: 1000
        tap_action: info
        target: 10
        title: Cyan
        title_position: bottom
        title_style: false
        type: 'custom:bar-card'
        unit_of_measurement: false
        value_style: false
        visibility: false
        width: 75%
      - align: center
        animation: auto
        animiation: 'on'
        attribute: false
        background_style: false
        card_style: false
        charge_entity: false
        color: '#ff00ff'
        decimal: false
        delay: 5000
        direction: up
        entities:
          - entity: sensor.cp1515n_magenta_level
        entity: sensor.cp1515n_magenta_level
        height: 150px
        icon: false
        icon_position: 'off'
        icon_style: false
        indicator: auto
        limit_value: false
        max: 100
        min: 0
        minmax_style: false
        padding: 4px
        rounding: 3px
        saturation: 100%
        severity: false
        show_minmax: false
        show_value: true
        speed: 1000
        tap_action: info
        target: 10
        title: Magenta
        title_position: bottom
        title_style: false
        type: 'custom:bar-card'
        unit_of_measurement: false
        value_style: false
        visibility: false
        width: 75%
      - align: center
        animation: auto
        animiation: 'on'
        attribute: false
        background_style: false
        card_style: false
        charge_entity: false
        color: '#ffff00'
        decimal: false
        delay: 5000
        direction: up
        entities:
          - entity: sensor.cp1515n_yellow_level
        entity: sensor.cp1515n_yellow_level
        height: 150px
        icon: false
        icon_position: 'off'
        icon_style: false
        indicator: auto
        limit_value: false
        max: 100
        min: 0
        minmax_style: false
        padding: 4px
        rounding: 3px
        saturation: 100%
        severity: false
        show_minmax: false
        show_value: true
        speed: 1000
        tap_action: info
        target: 10
        title: Yellow
        title_position: bottom
        title_style: false
        type: 'custom:bar-card'
        unit_of_measurement: false
        value_style: false
        visibility: false
        width: 75%
    type: horizontal-stack
type: 'custom:vertical-stack-in-card'

Please note that it uses custome verrtical-stack-in-card and bar-card. Hope at least some of you will enjoy it!

4 Likes

Here is updated card configuration:

  • updated to work with new custom cards in 0.107.x
  • config updated for bar-card v3.0
  • using now stack-in-card instead of vertical-stack-in-card
  • removed markups, as causing some issues in new HA when used within custom cards
type: 'custom:stack-in-card'
mode: vertical
keep:
  background: false
  border_radius: false
  box_shadow: false
  margin: false
  outer_padding: false
cards:
  - type: entities
    entities:
      - type: divider
      - entity: sensor.cp1515n_printer_status
        icon: 'mdi:information-variant'
        name: 'Printer status:'
      - entity: sensor.cp1515n_printer_error
        icon: 'mdi:alert-outline'
        name: 'Printer error:'
      - entity: sensor.cp1515n_printer_uptime
        icon: 'mdi:clock-check-outline'
        name: 'Printer uptime:'
      - type: divider
      - entity: sensor.cp1515n_total_pages_printed
        icon: 'mdi:counter'
        name: 'Total pages printed:'
      - entity: sensor.cp1515n_color_pages_printed
        icon: 'mdi:counter'
        name: 'Color pages printed:'
      - entity: sensor.cp1515n_bw_pages_printed
        icon: 'mdi:counter'
        name: 'B&W pages printed:'
      - type: divider
  - type: 'custom:bar-card'
    entities:
      - entity: sensor.cp1515n_black_level
        color: '#333333'
        name: Black
      - entity: sensor.cp1515n_cyan_level
        entity_config: null
        name: Cyan
        color: '#00FFFF'
      - entity: sensor.cp1515n_magenta_level
        entity_config: null
        name: Magenta
        color: '#FF00FF'
      - entity: sensor.cp1515n_yellow_level
        entity_config: null
        name: Yellow
        color: '#FFFf00'
    animation:
      speed: 1000
      delay: 1000
      state: on
    direction: up
    entity_row: false
    height: 100px
    width: 70%
    limit_value: true
    min: 0
    max: 100
    title: 'Toner levels:'
    stack: horizontal
    target: 15
    positions:
      icon: 'off'
      indicator: 'off'
      title: outside
      minmax: 'off'
      value: outside
title: HP Color LaserJet CP1515n

And new, updated look:

1 Like

Great thanks. I made my HP Photosmart C309A sensors in this way.

Is there a way to use the previous values when the printer is offline ? I currently see NaN as value.

Is there a way to remove the horizontal bar divider inside the 4 vertical ink bars? I saw other bars containing also the “drop” icon in them. How can I add it?

Well, this is how the SNMP sensor works, connecting on-line to source device. So this would be possible only by adding some automation that would periodically read SNMP OIDs and write them to some input_number variables, but only if source is available.

I’ve seen somewhere a template with with you can use an if Nan then use the previous value…

I think this is possible

To remove the divider bar ( I use it to indicate ‘critical’ level of toner) just delete from card configuration line: target: 15
For icons you can change in positions: section line icon: ‘off’ to inside (will be displayed sinside bar, at the top) or outside (will be displayed below the bar and color name). Also add icon: mdi:invert-colors below the target: 15 line.
Basically there are some other customizations possible, take a look at bar-card documentation:

Thanks for quick reply. I did it and it works!! I used “water” mdi :wink:

Looking forward for a solution about the NaN value :slight_smile:

Well, I’ll look into this, but no promise :slight_smile: Even if the template is used, somehow last values need to be stored somehow… so another set of variables to hold these values and some automations to record for future use… Since this is interesting ‘generic’ problem I’ll try to investigate though…

Thank you for this excellent setup, @mirekmal! I was able to follow your instructions and now can integrate my HP P2055dn into HA. I like your printer card, too, and decided to use it with my already-integrated Brother printers as well.

One issue I had that took me awhile to track down: because the printer uptime updates frequently, my history page started slowing down to the point where it would take 10 or more minutes to load. I excluded the p2055dn sensors from the history, and now the history page loads almost instantly. I’m not positive, but from the number of lines in the history graph, I think it updates the uptime every second. That’s 10,800 updates in the 3-hour bar graph of the history chart, and it was hogging all of my resources to display the page. Thank you again for the great addition to HA!

Thanks for feedback, @tanderson1992, glad you like the setup!
Well, I did not noticed issue you reported, since I’m running my recorder already in the way that I explicitly specify entities I want to track the history. If I recall properly, the reason I do not record everything was actually SNMP sensor for bandwidth monitoring for my router, that cause exactly the same issue as you reported!
Now, it is possible to get this easily fixed by changing scan_interval parameter from 1 to for eample 60 inside cp1515n_uptime sensor definition. Actually it would make a lot of sense, since this level of accuracy for such sensor does not make too much sense… :wink:

Good call. I changed it to 60 but will still keep it excluded from History.

I also updated definition of cp1515n_printer_uptime sensor to reflect fact that seconds value changes only once a minute, so there is no sense to display these. So now it display only something like Uptime: 6d 23h 13m:

      cp1515n_printer_uptime:
        friendly_name: "Printer Uptime"
        value_template: >-
          {% set t = states('sensor.cp1515n_uptime') | int %}
          {% set t = (t/10) | int %}
          {{ '{:d}d {:02d}h {:02d}m'.format(t // 86400, (t // 3600) % 24, (t % 3600) // 60, (t % 3600) % 60) }}
1 Like

Interestingly, I found with my MFP MF477FDW that the uptime calculation was out by a factor of 10, so needed to do a t/100 rather than 1/10…

I couldn’t work out initially why the uptime was jumping so fast!

For those that want to know the usuable oid…

snmpwalk -v 1 -c public 192.168.1.100 (whatever IP your printer has)
1 Like

And there is also a GUI-tool. Just adding ip and ‘walk’ from 1 gives you all the OID nicely listed
Debug your SNMP configuration with SNMP Tester (paessler.com)

Hi,
Just found this project and I think is wonderful.
Can somebody show me what is oid for scanned pages. I want to have also that and didn’t found a proper oid for that.
For now I know that the information is obtained for my Office8022 Printer through a custom integration, so the information exists, but I scanned all available oid’s on my printer and didn’t find the value shown in integration for scanned pages.

According to HP OID documentation it should be something there:

-- 1.3.6.1.4.1.11.2.3.9.4.2.1.1.16.2.1.5
scanned-media-total-charge   OBJECT-TYPE
   SYNTAX          OCTET STRING    
   ACCESS           read-only    
   STATUS            optional   
   DESCRIPTION "The total charge for pages scanned, for this media size.
       "
::= { scanned-media-usage 5 }

-- 1.3.6.1.4.1.11.2.3.9.4.2.1.1.16.2.1.1
scanned-media-simplex-count   OBJECT-TYPE
   SYNTAX          INTEGER    
   ACCESS           read-only    
   STATUS            optional   
   DESCRIPTION "Total number of simplex pages scanned, for this media size.
       "
::= { scanned-media-usage 1 }

-- 1.3.6.1.4.1.11.2.3.9.4.2.1.1.16.2.1.2
scanned-media-simplex-charge   OBJECT-TYPE
   SYNTAX          OCTET STRING    
   ACCESS           read-write    
   STATUS            optional   
   DESCRIPTION "Charge for each simplex page printed in this media size.
       "
::= { scanned-media-usage 2 }

-- 1.3.6.1.4.1.11.2.3.9.4.2.1.1.16.2.1.3
scanned-media-duplex-count   OBJECT-TYPE
   SYNTAX          INTEGER    
   ACCESS           read-only    
   STATUS            optional   
   DESCRIPTION "Total number of duplex pages scanned, for this media size.
       "
::= { scanned-media-usage 3 }

-- 1.3.6.1.4.1.11.2.3.9.4.2.1.1.16.2.1.4
scanned-media-duplex-charge   OBJECT-TYPE
   SYNTAX          OCTET STRING    
   ACCESS           read-write    
   STATUS            optional   
   DESCRIPTION "Charge for each duplex page scanned, for this media size.
       "
::= { scanned-media-usage 4 }

-- 1.3.6.1.4.1.11.2.3.9.4.2.1.1.16.2.2
usage-scanner-total-charge   OBJECT-TYPE
   SYNTAX          OCTET STRING    
   ACCESS           read-only    
   STATUS            optional   
   DESCRIPTION "Total scanner charge or cost for all paper sizes scanned.
      "
::= { scanner-accounting 2 }

-- 1.3.6.1.4.1.11.2.3.9.4.2.1.2.2.1.62
scanner-accessory-send-job-scan-count   OBJECT-TYPE
   SYNTAX          INTEGER    
   ACCESS           read-only    
   STATUS            optional   
   DESCRIPTION "This relates to the number of pages scanned for fax/send. This
   item is incremented by 2 for each sheet scanned through the ADF
   in 2-sided scan mode, and it is incremented by 1 for flatbed
   scans. Scanning for testing and calibration purposes are NOT TO
   BE INCLUDED in this count.
       "
::= { settings-scanner 62 }

Cannot check this myself, as my printer does not have scanning functionality…

Thank you for effort, but for every oid is returning value “null2” . I’m sure that something is there :slight_smile: , but still hidden

L.E.

For everybody wanting OfficeJet Hp printer OID I found main attributes, but still have some things to bring togeter, so:

  1. found a bit of info and followed path:
    c# - snmp oid for scanner detail(HP LaserJet 3055) - Stack Overflow
    arrived here:
    https://mibs.observium.org/mib/HP-OFFICEJET-PRO-X576DW-MIB/

Noticed that from OID provided i had to bring another .0 at the end and all (almost good) like:
1.3.6.1.4.1.11.2.3.9.4.2.1.2.2.1.20.0 - adf scanned
1.3.6.1.4.1.11.2.3.9.4.2.1.2.2.1.21.0 - flatbed scanned

Started comparing with what I have from the current sensors, and I have main values: ADF and Flatbed scanned pages, but now I wonder how to get a sensor to show errors for scanning, because I cannot find sum of all scanned pages. I have 28 + 83, but total OID for scanned pages shows me…107

On the forum it says:

1.3.6.1.2.1.25.3.5.1.2 . It returns an octet string and you need to interpret it as

                Condition         Bit #    hrDeviceStatus
                lowPaper          0        warning(3)
                noPaper           1        down(5)
                lowToner          2        warning(3)
                noToner           3        down(5)
                doorOpen          4        down(5)
                jammed            5        down(5)
                offline           6        down(5)
                serviceRequested  7        warning(3)

but cannot find how to query in Passler or to do the sensor in HA based on that info to find errors.