Pellet bag counter

Hello,

I am building a simple arduino device that will help me count the amount of pellets that I used for my heating. Pellets are packed in bags of 15kg.

On the device I choose how many bags I loaded into my fornace - it can be an integer between -10 and +10 (negative values just to enable the user to correct mistaken previous input).
And then after confirming the number is sent via mqtt… So far so good…

Now I have a question, how to consume this number in Home Assisstant and then how to count the total consumption over month/year…

I have already discovered the Utility meter that could do the second part of the job, but it needs some sort of sensor that consumes this numbers… But among mqtt components I haven’t found the right one.

Thanks for suggestions.

Hi Trapezz

I have the same problem.
Currently I store pellets bags and load them 1 by 1 into my stove.
To track bags used, for the moment I have created a counter of bags left in stock like this:

configuration.yaml

counter:
  compteur_sacs_pellets:
    name: Nbre de sacs en stock
    icon: mdi:bag-personal
    initial: 79
    step: 1

and a button in Lovelace

type: button
entity: counter.compteur_sacs_pellets
show_icon: true
icon_height: 30px
show_name: true
show_state: false
name: +1 sac consommé
hold_action:
  action: none
tap_action:
  action: call-service
  service: counter.decrement
  service_data:
    entity_id: counter.compteur_sacs_pellets

Next step, I’m trying to calculate an average of bags used over 10 or 15 sliding days and then calculate the date until which I could heat up.
For example:
10 bags used between November 1st and November 15th.
That’s 0.66 bags per day.
So if I have 70 bags in stock, I could heat for another 106 days and thus until about the end of February.

If you have ideas to create this…

I worked on this :

screenshot

You must create a button for decreament the counter of bags :

type: button
entity: counter.counter_number_of_bags_in_stock
show_icon: true
icon_height: 30px
show_name: true
show_state: false
name: +1 bag used
tap_action:
  action: call-service
  service: counter.decrement
  service_data:
    entity_id: counter.counter_number_of_bags_in_stock

Next, in configuration.yaml an imput date for the date when you power ON the stove.
I calculate the average of bags since stove power On:

input_datetime:
  stove_start_date:
    name: Start date of MCZ stove
    has_date: true
    has_time: false
    initial: '2020-10-01'

A counter for bags (indicate as initial your pellet bags in stock) :

counter:
  counter_number_of_bags_in_stock:
    name: Number of bags in stock
    icon: mdi:bag-personal
    initial: 79
    step: 1

and sensors :

average_used_bags:
        friendly_name: Average used bags
        value_template: "{{ ((state_attr('counter.counter_number_of_bags_in_stock', 'initial')|float - states('counter.counter_number_of_bags_in_stock')|float) / states('sensor.counter_days_since_power')|float)|round(3) }}"
      number_of_remaining_minutes_of_heat:
        friendly_name: Number of_remaining minutes of heat
        value_template: "{{ ((states('counter.counter_number_of_bags_in_stock')|float / states('sensor.average_used_bags')|float) * 1440)|round(0) }}"
      counter_days_since_power:
        friendly_name: Days since power On
        value_template: '{{ ((as_timestamp(now())-(states.input_datetime.stove_start_date.attributes.timestamp)) | int /60/1440) | round(0) }}'
        unit_of_measurement: 'Days'
        entity_id: input_datetime.stove_start_date,sensor.time
      bags_days_left:
        friendly_name: 'Time Remaining'
        value_template: >-
          {%- set time  = states.sensor.number_of_remaining_minutes_of_heat.state | round -%}
          {%- set sep   = '  ' -%}
          {%- set TIME_MAP = {
             'month': (time / 43800) % 12,
              'week': (time / 10080) % 4,
               'day': (time / 1440) % 7,
              'hour': (time / 60) % 24,
          }
          -%}

          {%- for unit, duration in TIME_MAP.items() if duration >= 1 -%}
            {%- if not loop.first -%}
              {{ sep }}
            {%- endif -%}
              
            {{ (duration | string).split('.')[0] }} {{ unit }}

            {%- if duration >= 2 -%}
              s
            {%- endif -%}
          {%- endfor -%}

          {%- if time < 1 -%}
            no stock
          {%- endif -%}

I will check this code during few days.
If you have any improvements to make…

1 Like

Hello,

sorry for late reply and thank you for your information. Since last post unfortunately I didn’t really managed to tinker with this pellet counter.

The basic Idea I had was not to use Home Assistant directly (on the phone) to click when loading bags into the furnace but to have a dedicated interface near to the furnace that anybody can use when filling up the pellets.

So I built an arduino based device that:

  • trough display and rotary encoder you can select the number of bags that were loaded -> the value is transmitted via mqtt to HA
  • monitors the automatic pellet loader to calculate the consumtion - basically it measures voltage on pellet loader and counts miliseconds when the loader is ON. This is regulary send to HA via mqtt too. Here I had hard times to determine the average miliseconds per bag, have to finish this.
  • monitors the temperature of the water and chimney to determine the furnace status (sometimes it does not turn on properly and goes in alarm state -> so I created HA notification that I have to do a manual intervention)
  • drives the pumps

I have to properly use the received numbers to properly count pellets useds and pellets still in the furnace.
I will check your implementation if I can use it on my case…

@manouille49 Thanks for sharing. I’ve implemented this but made some changes in the sensors mainly on the calculations and added a button that call a script to refill the stock and keeping cumulative calculations.
Here is the sensors code:

        icon_template: mdi:bag-personal-outline
        friendly_name: Used Bags (Total)
        value_template: "{{ state_attr('counter.number_of_bags_in_stock', 'initial') | int - states('counter.number_of_bags_in_stock') | int + 1}}"
      counter_days_since_power:
        icon_template: mdi:hours-24
        friendly_name: Total Usage (days)
        value_template: '{{ (((as_timestamp(now())-(states.input_datetime.stove_start_date.attributes.timestamp)) | int /60/1440)) | round(0,default=none) + 1 }}'
        unit_of_measurement: 'Days'
      average_used_bags:
        icon_template: mdi:bag-personal-off-outline
        friendly_name: Used Bags Usados (Average)
        value_template: "{{ (states('sensor.total_used_bags') | float(0) / states('sensor.counter_days_since_power') | float(0)) | round(3,default=none) }}"
      number_of_remaining_hours_of_heat:
        icon_template: mdi:hours-24
        friendly_name: Remaining time of_heat (hours)
        value_template: "{{ (states('counter.number_of_bags_in_stock') | float(0) / states('sensor.average_used_bags') | float(0) *24) | round(0,default=none) }}"
      bags_days_left:
        icon_template: mdi:timetable
        friendly_name: 'Stock forecast'
        value_template: >-
          {%- set time  = states.sensor.number_of_remaining_hours_of_heat.state | round(0,default=none) -%}
          {%- set sep   = '  ' -%}
          {%- set TIME_MAP = {
             'month': (time // 730), 
             'week': (time % 730) // 168,
             'day': ((time % 730) % 168) // 24,
             'hours': ((time % 730) % 168) % 24,
          } 
          -%}
          {%- if state_attr('counter.number_of_bags_in_stock', 'initial') | int !=  states('counter.number_of_bags_in_stock')| int -%}
            {%- for unit, duration in TIME_MAP.items() if duration >= 1 -%}
              {%- if not loop.first -%}
                {{ sep }}
              {%- endif -%} 
              {{ (duration | string).split('.')[0] }} {{ unit }}
              {%- if duration >= 2 -%}
                s
              {%- endif -%}
            {%- endfor -%}
          {%- endif -%}  
          {%- if state_attr('counter.number_of_bags_in_stock', 'initial') | int ==  states('counter.number_of_bags_in_stock') | int -%}
            No bags used yet to provide forecast
          {%- endif -%}  
          {%- if time < 1 or states('counter.number_of_bags_in_stock') == 0 -%}
            Nao bags in stock
          {%- endif -%}