Instant Ink Countdown for Hp Printer Integration

In the XML from the printer, I have a tag

<dd:TotalImpressions PEID="5082">1234</dd:TotalImpressions>

so the xml_grep command here is looking for that tag (dd:TotalImpressions) with the attribute, PEID=“5082”.

  • Do you have that tag with that attribute?
  • When you drop to the OS and run the same command, do you get an output? If so, what?
xml_grep 'dd:TotalImpressions[@PEID="5082"]' http://[Your_Printer_IP_Address]/DevMgmt/ProductUsageDyn.xml --text_only

Hi @EventuallyFixed
Thanks for your help. I pasted all your code

I have the tag in the xml file : <dd:TotalImpressions PEID=“5082”>424</dd:TotalImpressions>

Here is the result of the command line xml_grep


The value appears twice. Is it normal ?

When I launch the automation, this error appears

Command failed: date -d '2020-10-25 1 month' +%Y-%m-%d

For the xml_grep: Are there two tags with ‘<dd:TotalImpressions PEID=“5082”>’? If so, that is why there are two answers. Do you have a unique tag & attribute in the document that can be used, one which increments every time a page is printed? If so use that.
If not you could try something like adding | head -qn1, or | awk 'NR==1{print $1}’ to take only the first line of the output:

xml_grep 'dd:TotalImpressions[@PEID="5082"]' http://[Your_Printer_IP_Address]/DevMgmt/ProductUsageDyn.xml --text_only | head -qn1

or

xml_grep 'dd:TotalImpressions[@PEID="5082"]' http://[Your_Printer_IP_Address]/DevMgmt/ProductUsageDyn.xml --text_only | awk 'NR==1{print $1}'

For the date: Your OS is not doing the date calculation. Please tell me what OS and shell are you using? For the shell, drop to the OS and give the output from this:

echo "$SHELL"

Also, the result of this could be helpful:

ls /bin/bash

To get the date part working, it would be easier for you to use the Template Sensor instead of the command line sensor. So change this:

#    hp_envy_5540_next_renewal_date:
#      friendly_name: HP Envy 5540 Next Renewal Date
#      value_template: >-
#        {% if (states('input_datetime.hp_envy_5540_this_period_start_date').split("-")[1]|int + 1 > 12) %}
#          {{ (states('input_datetime.hp_envy_5540_this_period_start_date').split("-")[0]|int + 1)|string + "-01-" + states('input_datetime.hp_envy_5540_this_period_start_date').split("-")[2] }}
#        {% else %}
#          {{ states('input_datetime.hp_envy_5540_this_period_start_date').split("-")[0]|int|string + "-" +  ('%02d' % (states('input_datetime.hp_envy_5540_this_period_start_date').split("-")[1]|int + 1)) + "-" + states('input_datetime.hp_envy_5540_this_period_start_date').split("-")[2] }}
#        {% endif %}

to this, uncommenting the code by removing the ‘#’ at the start of the line:

    hp_envy_5540_next_renewal_date:
      friendly_name: HP Envy 5540 Next Renewal Date
      value_template: >-
        {% if (states('input_datetime.hp_envy_5540_this_period_start_date').split("-")[1]|int + 1 > 12) %}
          {{ (states('input_datetime.hp_envy_5540_this_period_start_date').split("-")[0]|int + 1)|string + "-01-" + states('input_datetime.hp_envy_5540_this_period_start_date').split("-")[2] }}
        {% else %}
          {{ states('input_datetime.hp_envy_5540_this_period_start_date').split("-")[0]|int|string + "-" +  ('%02d' % (states('input_datetime.hp_envy_5540_this_period_start_date').split("-")[1]|int + 1)) + "-" + states('input_datetime.hp_envy_5540_this_period_start_date').split("-")[2] }}
        {% endif %}

and then change this:

- platform: command_line
  name: "HP Envy 5540 Next Renewal Date"
  command: "date -d '{{ states('input_datetime.hp_envy_5540_this_period_start_date') }} 1 month' +%Y-%m-%d"
  value_template: "{{ value }}"

to this, commenting-out the code by adding a ‘#’ at the start of the line

#- platform: command_line
#  name: "HP Envy 5540 Next Renewal Date"
#  command: "date -d '{{ states('input_datetime.hp_envy_5540_this_period_start_date') }} 1 month' +%Y-%m-%d"
#  value_template: "{{ value }}"

Thanks for all your help !

echo "$SHELL"and ls /bin/bash

gives me /bin/bash

I’m confused, why I need to comment the xml_grep command line to get the date part working ?

I’m confused, why I need to comment the xml_grep command line to get the date part working ?

It’s me that is confused! :smile: I’ve corrected the code substitution above.

What is your OS? Is it HassOS? Raspbian/Raspbery Pi OS? Some other OS? I ask because it’s OS differences that are causing the command-line date sensor to not work. I’m using Raspbian, which by default uses the bash shell.

Hi,
I have tried as well for 2 days to get your solution running. Unfortunately I am not familiar linux/unix, so I guess I belong -meanwhile - to the majority using HassOS simple installation via image on SD card.
As soon as there is a code working with HassOS, I might try it again. But I do now better stick to the initial solution without page carryover.

Finally, it seems to work without errors :slight_smile:
I still have to configure according to my subscription.
I have a last (I hope) question : why “Printed Pages Total at month start” has a minimal value to 500 ?

hi, I have hassos and this code works for me:

    hp_envy_6230_next_renewal_date:
      friendly_name: "HP Envy 6230 Prossima Data Rinnovo"
      value_template: >-
        {% if (states('input_datetime.hp_envy_6230_this_period_start_date').split("-")[1]|int + 1 > 12) %}
          {{  (states('input_datetime.hp_envy_6230_this_period_start_date').split("-")[0]|int + 1)|string + "-01-" + states('input_datetime.hp_envy_6230_this_period_start_date').split("-")[2]  }}
        {% else %}
          {{  states('input_datetime.hp_envy_6230_this_period_start_date').split("-")[0]|int|string + "-" + (states('input_datetime.hp_envy_6230_this_period_start_date').split("-")[1]|int + 1)|string + "-" + states('input_datetime.hp_envy_6230_this_period_start_date').split("-")[2]  }}
        {% endif %} 

and if you don’t have it yet, created this sensor:

- platform: time_date
  display_options:
    - 'time'
    - 'date'

No reason other than I had just over 500 printed pages at the time ot was created. You can change that.

1 Like

For completeness, I have amended the configuration as follows:

  • Added the date/time sensor, as it’s a prerequisite (thanks @acuplush)
  • New Scrape sensor to get the total number of pages printed from printer’s web service.
    • This means that the configuration uses only Home Assistant objects, and removes any Operating System dependencies.

hello, since it is now a bug-free code, would it be feasible to create a package? so as to have everything in order and easy to understand for other users.

1 Like

Good idea. However I’d have to learn how to do that, and for the foreseeable future my time is rather limited.

1 Like

Hi @EventuallyFixed
Where can I find the new configuration to gest the total number of pages printed with HA objects ?
Thanks

It’s all in the post above.

Sorry, I did not see.
I had problems with the xml_grep command but thanks to this new code, everything works
Thank you so much!

As you suggested, I made this into a package file.

# /config/packages/hp_envy_5540_instant_ink.yaml

##################################################################################################################
# Inputs
##################################################################################################################

# Inputs for the HP Ink Print Plan
input_number:
# The total number of pages that had been printed
# at the start of this period of the printing plan
# Set by an automation
  hp_envy_5540_pages_at_month_start:
    name: Printed Pages Total at month start
    min: 500
    max: 10000
    step: 1
    icon: mdi:printer
    mode: box
# The current monthly allowance number of pages
# Set manually
  hp_envy_5540_pages_monthly_allowance:
    name: Monthly Allowance Pages
    min: 15
    max: 300
    step: 1
    icon: mdi:printer
    mode: box
# The maximum number of rollover pages allowed.
# Ten on the free tier, 2x pages on the paid tier.
# Set manually
  hp_envy_5540_pages_rollover_monthly_max_allowance:
    name: Rollover Maximum Pages
    min: 0
    max: 600
    step: 1
    icon: mdi:printer
    mode: box
# The rollover allowance for this month
# Set by an automation
  hp_envy_5540_pages_rollover_allowance:
    name: Rollover Allowance Pages
    min: 0
    max: 600
    step: 1
    icon: mdi:printer
    mode: box
# The number of pages in each overprint block, when
# the Monthly Allowance plus Rollover are exceeded
# Set manually
  hp_envy_5540_pages_overprint_block_size:
    name: Over Print Block Size
    min: 0
    max: 100
    step: 1
    icon: mdi:printer
    mode: box
# The cost of each overprint block, in £
# Set manually
  hp_envy_5540_pages_overprint_block_cost:
    name: Over Print Block Cost
    min: 0
    max: 50
    step: 0.01
    icon: mdi:currency-gbp
    mode: box
# The start date of this period of the print plan
# Set by automation    
input_datetime:
  hp_envy_5540_this_period_start_date:
    name: This Period Start Date
    has_date: true
    has_time: false
    icon: mdi:calendar

##################################################################################################################
# Sensors
##################################################################################################################
sensor:
- platform: template
  sensors:
# Used to track days remaining of HP Ink Printer Pages period
# Needs to have the date sensors installed as per: https://www.home-assistant.io/integrations
# Use of sensor.date ought to force a daily update, according to https://www.home-assistant.io/integrations/template/
    hp_envy_5540_allowance_days_remaining:
      friendly_name: "Allowance Days Remaining"
      value_template: >-
         {{ ((as_timestamp(strptime(states('sensor.hp_envy_5540_next_renewal_date'), '%Y-%m-%d'))|int - as_timestamp(strptime(states('sensor.date'), '%Y-%m-%d'))|int ) / 86400)|int }}
#
# The number of allowance pages remaining for this period
# Calculated when each page is printed, and at the start of each new Instant Ink period
# "{% (if states('input_datetime.hp_envy_5540_this_period_start_date') %}" is a workaround to set a listener)
    hp_envy_5540_pages_allowance_remaining:
      friendly_name: "Allowance Pages Remaining"
      value_template: >-
        {% if states('input_datetime.hp_envy_5540_this_period_start_date') %}
          {% if states('input_number.hp_envy_5540_pages_at_month_start')|int + states('input_number.hp_envy_5540_pages_monthly_allowance')|int - states('sensor.hp_envy_5540_total_pages_printed')|int >= 0 %}
            {{ states('input_number.hp_envy_5540_pages_at_month_start')|int + states('input_number.hp_envy_5540_pages_monthly_allowance')|int - states('sensor.hp_envy_5540_total_pages_printed')|int }}
          {% else %}
            0
          {% endif %}
        {% endif %}
#
# The number of rollover pages remaining for this period.
# Calculated when each page is printed, when the Rollover Allowance is reset, and at the start of each new Instant Ink period
    hp_envy_5540_pages_rollover_remaining:
      friendly_name: "Rollover Pages Remaining"
      value_template: >-
        {% if states('input_datetime.hp_envy_5540_this_period_start_date') %}
          {% if states('input_number.hp_envy_5540_pages_at_month_start')|int + states('input_number.hp_envy_5540_pages_monthly_allowance')|int - states('sensor.hp_envy_5540_total_pages_printed')|int < 0 and states('input_number.hp_envy_5540_pages_at_month_start')|int + states('input_number.hp_envy_5540_pages_monthly_allowance')|int + states('input_number.hp_envy_5540_pages_rollover_allowance')|int - states('sensor.hp_envy_5540_total_pages_printed')|int >= 0 %}
            {{ states('input_number.hp_envy_5540_pages_at_month_start')|int + states('input_number.hp_envy_5540_pages_monthly_allowance')|int + states('input_number.hp_envy_5540_pages_rollover_allowance')|int - states('sensor.hp_envy_5540_total_pages_printed')|int }}
          {% elif states('input_number.hp_envy_5540_pages_at_month_start')|int + states('input_number.hp_envy_5540_pages_monthly_allowance')|int - states('sensor.hp_envy_5540_total_pages_printed')|int < 0 and states('input_number.hp_envy_5540_pages_at_month_start')|int + states('input_number.hp_envy_5540_pages_monthly_allowance')|int + states('input_number.hp_envy_5540_pages_rollover_allowance')|int -   states('sensor.hp_envy_5540_total_pages_printed')|int < 0 %}
            0
          {% elif 1==1 %}
            {{ states('input_number.hp_envy_5540_pages_rollover_allowance')|int }}
          {% endif %}
        {% endif %}
#
# The number pages printed over and above the Monthly Allowance plus the Rollover Allowance
# Calculated when each page is printed, and at the start of each new Instant Ink period
    hp_envy_5540_pages_overprint:
      friendly_name: "Over Allowance Prints"
      value_template: >-
        {% if states('input_datetime.hp_envy_5540_this_period_start_date') %}
          {% if states('input_number.hp_envy_5540_pages_at_month_start')|int + states('input_number.hp_envy_5540_pages_monthly_allowance')|int + states('input_number.hp_envy_5540_pages_rollover_allowance')|int < states('sensor.hp_envy_5540_total_pages_printed')|int %}
            {{ states('sensor.hp_envy_5540_total_pages_printed')|int - states('input_number.hp_envy_5540_pages_rollover_allowance')|int - states('input_number.hp_envy_5540_pages_monthly_allowance')|int - states('input_number.hp_envy_5540_pages_at_month_start')|int }}
          {% else %}
            0
          {% endif %}    
        {% endif %}
# The cost so far of the pages that have been printed over the Allowance plus Rollover
# Calculated when each page is printed, and at the start of each new Instant Ink period
    hp_envy_5540_pages_overprint_cost:
      friendly_name: "Over Allowance Cost"
      value_template: >-
        {% if states('input_datetime.hp_envy_5540_total_pages_printed') or states('input_datetime.hp_envy_5540_this_period_start_date') %}
          {% if states('sensor.hp_envy_5540_pages_overprint')|int == 0 %}
            0
          {% elif states('sensor.hp_envy_5540_pages_overprint')|int > 0 and ( (states('sensor.hp_envy_5540_pages_overprint')|int - 1) % states('input_number.hp_envy_5540_pages_overprint_block_size')|int == 0 ) %}
            {{ (1 + ((states('sensor.hp_envy_5540_pages_overprint')|int - 1) / states('input_number.hp_envy_5540_pages_overprint_block_size')|int)) | multiply( states('input_number.hp_envy_5540_pages_overprint_block_cost')|int)|int  }}
          {% else %}
            {{ (1 + ((states('sensor.hp_envy_5540_pages_overprint')|int - 1) / states('input_number.hp_envy_5540_pages_overprint_block_size')|int)) | multiply( states('input_number.hp_envy_5540_pages_overprint_block_cost')|int)|int  }}
          {% endif %}    
        {% endif %}    
      unit_of_measurement: '£'

    hp_envy_5540_pages_overprint_remaining:
      friendly_name: "Over Allowance Prints Remaining"
      value_template: >-
        {% if states('sensor.hp_envy_5540_pages_overprint')|int == 0 or (states('sensor.hp_envy_5540_pages_overprint')|int % states('input_number.hp_envy_5540_pages_overprint_block_size')|int == 0) %}
          0
        {% else %}
          {{ states('input_number.hp_envy_5540_pages_overprint_block_size')|int - (states('sensor.hp_envy_5540_pages_overprint')|int % states('input_number.hp_envy_5540_pages_overprint_block_size')|int) }}
        {% endif %}    

    # Next Renewal Date
    # WILL NOT WORK FOR 29th, 30th, 31st OF THE MONTH
    hp_envy_5540_next_renewal_date:
      friendly_name: HP Envy 5540 Next Renewal Date
      value_template: >-
        {% if (states('input_datetime.hp_envy_5540_this_period_start_date').split("-")[1]|int + 1 > 12) %}
          {{ (states('input_datetime.hp_envy_5540_this_period_start_date').split("-")[0]|int + 1)|string + "-01-" + states('input_datetime.hp_envy_5540_this_period_start_date').split("-")[2] }}
        {% else %}
          {{ states('input_datetime.hp_envy_5540_this_period_start_date').split("-")[0]|int|string + "-" +  ('%02d' % (states('input_datetime.hp_envy_5540_this_period_start_date').split("-")[1]|int + 1)) + "-" + states('input_datetime.hp_envy_5540_this_period_start_date').split("-")[2] }}
        {% endif %}

# Scrape sensor for HP Envy 5540 Total Pages Printed
- platform: scrape
  resource: http://[Printer_IP]/DevMgmt/ProductUsageDyn.xml
  name: hp_envy_5540_total_pages_printed
  select: 'dd\:TotalImpressions[PEID="5082"]'
  value_template: >-
    {% if value == "" %}
      0
    {% else %}
      {{ value }}
    {% endif %}

##################################################################################################################
# Alternative sensors using the command line. Do not work in HASSOS
##################################################################################################################
#
# Used with input_datetime, & input_number, to track the state of HP Printer Instant Ink

# Gets the HP Printer Total Pages Printed from the printer's web service
# Inspired by: https://community.home-assistant.io/t/command-line-sensor-with-a-value-template-struggling/125957/3
# Needs package, 'xml-twig-tools', to be installed in Raspbian
#- platform: command_line
#  name: "HP Envy 5540 Total Pages Printed"
#  command: "xml_grep 'dd:TotalImpressions[@PEID=\"5082\"]' http://[Printer_IP]/DevMgmt/ProductUsageDyn.xml --text_only"
#  value_template: "{{ value }}"
# Gets the HP Ink Next Allowance Renewal Date, using the command line for the calculation

# It's a command line sensor because the command line is better at handling date arithmetic
#- platform: command_line
#  name: "HP Envy 5540 Next Renewal Date"
#  command: "date -d '{{ states('input_datetime.hp_envy_5540_this_period_start_date') }} 1 month' +%Y-%m-%d"
#  value_template: "{{ value }}"




##################################################################################################################
# Automations
##################################################################################################################

automation:
- id: '1588925532080'
  alias: HP Envy 5540 Page Reset
  description: 'Sets: - Total number of pages printed at the start of the period -
    Start Date of this period (to store a date to calculate the next one) - Maximum
    Rollover Allowance value for this month - Rollover Remaining to new Maximum Rollover
    Allowance value for this month - Rollover from overprint pages'
  trigger:
  - at: 00:00:00
    platform: time
  condition:
  - condition: template
    value_template: '{{ now().day|int == states(''input_datetime.hp_envy_5540_this_period_start_date'')[-2:]|int
      }}'
  action:
  - service: input_number.set_value
    entity_id: input_number.hp_envy_5540_pages_rollover_allowance
    data_template:
      value: ' {% if states(''sensor.hp_envy_5540_pages_overprint'')|int > 0 and (states(''sensor.hp_envy_5540_pages_overprint'')|int
          % states(''input_number.hp_envy_5540_pages_overprint_block_size'')|int) >
          0 %} {{ states(''input_number.hp_envy_5540_pages_overprint_block_size'')|int
          - (states(''sensor.hp_envy_5540_pages_overprint'')|int % states(''input_number.hp_envy_5540_pages_overprint_block_size'')|int)  }}
          {% elif states(''sensor.hp_envy_5540_pages_allowance_remaining'')|int + states(''sensor.hp_envy_5540_pages_rollover_remaining'')|int
          > states(''input_number.hp_envy_5540_pages_rollover_monthly_max_allowance'')|int
          %} {{ states(''input_number.hp_envy_5540_pages_rollover_monthly_max_allowance'')|int
          }} {% else %} {{ states(''sensor.hp_envy_5540_pages_allowance_remaining'')|int
          + states(''sensor.hp_envy_5540_pages_rollover_remaining'')|int }} {% endif
          %}'
  - service: input_number.set_value
    entity_id: input_number.hp_envy_5540_pages_at_month_start
    data_template:
      value: '{{ states(''sensor.hp_envy_5540_total_pages_printed'') }}'
  - service: input_datetime.set_datetime
    entity_id: input_datetime.hp_envy_5540_this_period_start_date
    data_template:
      date: '{{ states(''sensor.date'') }}'

Hope this helps.

3 Likes

@dawiebe would you know how to modify the code ?

Hi Vendo232, the pages left sensor is evaluated from this template: -
{{ states('var.printer_pages_at_month_start')|int - states('sensor.hp_printer_printer')|int + 50 }}
Check what value you have for sensor.hp_printer_printer and then change the intitial_value for var in your configuration file, so that you get the correct start point.

it works!, thank you Adam

btw both solutions work great the Counter and Var option.

I`m using the latest HA 2021.4.1

1 Like

Hello
Has anyone tried converting automation to nodered?
Thanks