Epaper Displays and waste management

Epaper Displays and waste management
The Epaper display showing when my bins are due.

So, if you have read any of my other posts you may have already setup your waste management reminders and your epaper display access point(s) and tags. So if we have both of these things, why not combine them?

I wish I could claim credit for this project, but that really belongs to my friend who gave me the epaper displays and the code to do this. You can check out his repo here.

The premise for the code is simple. We have 4 bins. We want to divide the display in to 4 areas. We want each area to display the bin name and the amount of days until the bin is due. When the bin is due, we want to change the background colour so we know we have to do something. Since this changes every day, we need to run this automation once, but early enough that it's not going to confuse you.

This post will break down how this automation works, so that you can modify it for your own needs. You may still require a bit or trial and error, as that's just part of how this works.

The trigger

So, first off then. Our automation needs a trigger. We said earlier, that this needs to be every day, at a set time. Preferably, before I wake up. As you can probably tell from my automations, I mainly take the bins out at night and bring them back in the following day. Sometimes though, I may be rushing to put them out that morning. So, having the automation update around 2am fits right in. Setting this through the gui is pretty straight forward, but I've included the yaml incase you need it.

trigger:
  - platform: time
    at: "02:00:00"

We don't need to set any conditions, but you could add a check to see if you are home. If you are away for a week, why update the tag? Just bear in mind, if you return on the night your bins go out, the automation won't fire until the day. Nothing stopping you having the update as part of your return home routine, of course.

The display background

To update the display, we are going to start with the drawcustom service. You'll also need the entity id of the tag you want to display this on. The easiest way to start this is in gui mode, then move to yaml once done. Now to give the display something to do.

For this picture that we are drawing out, we start with a white background and set the rotation to 0. You can see what we are aiming for on the main picture to this article.

Centre icon

With the background set, we can now add our first part of the display: the center icon. While this appears last in the code, this places the most constraints on the other elements of the display. We want our icon straight in the center. For that we can use the following code:

payload:
- type: icon
          value: trash-can
          x: 123
          "y": 39
          size: 50
          color: 'black'

The value for x and y will vary for displays of a differenet size and if you choose a different icon. To add in the code to make the icon change colour, we can change it to this:

payload:
- type: icon
          value: trash-can
          x: 123
          "y": 39
          size: 50
          color: >-
            {{ 'red' if (([(14 if states('sensor.black_bin_schedule') ==
            'unknown' else states('sensor.black_bin_schedule')),(14 if
            states('sensor.blue_bin_schedule') == 'unknown' else
            states('sensor.blue_bin_schedule')),(14 if
            states('sensor.green_bin_schedule') == 'unknown' else
            states('sensor.green_bin_schedule')),(14 if
            states('sensor.brown_bin_schedule') == 'unknown' else
            states('sensor.brown_bin_schedule')) ]) | min ) | int < 2 else
            'black' }}

Before we move, lets just look at what this is doing. We want to turn the bin red, if the bins are due to go out (i.e, in less than 2 days). Essentially we are doing:

colour: >-
  {{ 'red' if any schedule is due in less than 2 days else 'black' }}

So, for each of our 4 schedules, we are assigning a value of "14" if any value is unknown, otherwise we return the states of our variable ( in this case, the number of days til the bin is due). This is achieved in the following bit of code for just the one variable:

(14 if states('sensor.black_bin_schedule') ==
            'unknown' else states('sensor.black_bin_schedule'))

The code then places each of these values (which we'll call w,x,y and z) in to an array and checks the minimum value of the array.

([ w,x,y,z ]) | min 

The lines

To divide up the screen in to the four quadrants, we are going to use lines. With the center icon, we need to make sure we don't accidently draw over the center icon. The display I'm using is approx 300 x 128 for positioning elements.

The lines were drawn taking in to account the central icon and were all drawn in red.  The only thing the lines need are start and end co-ordinates. Starting a little bit in wards (5 in the x direction) we can find the mid point (64 for the y direction ) then move to the center, altering the x component only. The line should end around 150 for the middle, but will require shortening for the centre icon. Repeat with the second half of the line, which will end at 290 in the x direction ( 300 - 2 x 5 - 5 being our offset from the edge. Once happy, repeat for varying x, where y is fixed at around 150.

- type: line
  fill: red
  width: 3
  x_start: 5
  y_start: 64
  x_end: 121
  y_end: 64

The text box

Again, for the text boxes we are doing this four times. We are changing each of the bin types each time.

- type: rectangle
          outline: white
          fill: >-
            {{'white' if states('sensor.green_bin_schedule') == 'unknown' or
            states('sensor.green_bin_schedule') | int > 1 else 'red' }}
          width: 1
          x_start: 178
          y_start: 70
          x_end: 290
          y_end: 123

First off, we start with a rectangle to contain our text. The code on the fill section is similar to the icon colour, so I won't cover exactly what is going on. Also, the x_start, y_start, x_end and y_end are similar to the lines we drew as well. The main difference is you are drawing a shape which has heigh and width, rather than a straight line. Again, you may need to play with the placement of your box. Feel free to change the outline colour to help you zero in on the box placement.

Once complete, we can move on to the 2 lines of text within the box we just drew. The first line of text is going to be the bin name and hence static. NB, we select the font ppb.ttf to write the text in. We again pick the colour depending on the number of days remaining, but we choose white text if we have less than 1 day to go.

- type: text
  value: Green
  font: ppb.ttf
  x: 190
  "y": 80
  size: 18
  color: >-
  {{'black' if states('sensor.green_bin_schedule') == 'unknown' or
   states('sensor.green_bin_schedule') | int > 1 else 'white' }}

For the last line of text we have:

- type: text
  value: >-
  {% if states('sensor.green_bin_schedule') == 'unknown' %}Unknown{%
   elif states('sensor.green_bin_schedule') | int == 0 %}Today{% elif
   states('sensor.green_bin_schedule') | int == 1 %}Tonight{% else
   %}{{states('sensor.green_bin_schedule')}} days{% endif %}
  font: ppb.ttf
  x: 190
  "y": 103
  size: 18
  color: >-
  {{'black' if states('sensor.green_bin_schedule') == 'unknown' or
  states('sensor.green_bin_schedule') | int > 1 else 'white' }}

The value here is a slight modification on the code we have used previous. This time, the value of the text is changed based on the number of days. Again, the last bit of code determines the colour of the text.

Putting it all together

Ultimtely, the final code looks like this.

alias: Update Bins Tag
description: ""
trigger:
  - platform: time
    at: "02:00:00"
condition: []
action:
  - service: open_epaper_link.drawcustom
    target:
      entity_id: open_epaper_link.0000021ee1763b1a
    data:
      background: white
      rotate: 0
      payload:
        - type: line
          fill: red
          width: 3
          x_start: 5
          y_start: 64
          x_end: 121
          y_end: 64
        - type: line
          fill: red
          width: 3
          x_start: 168
          y_start: 64
          x_end: 290
          y_end: 64
        - type: line
          fill: red
          width: 3
          x_start: 148
          y_start: 5
          x_end: 148
          y_end: 34
        - type: line
          fill: red
          width: 3
          x_start: 148
          y_start: 89
          x_end: 148
          y_end: 123
        - type: rectangle
          outline: white
          fill: >-
            {{'white' if states('sensor.black_bin_schedule') == 'unknown' or
            states('sensor.black_bin_schedule') | int > 1 else 'red' }}
          width: 1
          x_start: 5
          y_start: 5
          x_end: 123
          y_end: 60
        - type: text
          value: Black
          font: ppb.ttf
          x: 35
          "y": 10
          size: 18
          color: >-
            {{'black' if states('sensor.black_bin_schedule') == 'unknown' or
            states('sensor.black_bin_schedule') | int > 1 else 'white' }}
        - type: text
          value: >-
            {% if states('sensor.black_bin_schedule') == 'unknown' %}Unknown{%
            elif states('sensor.black_bin_schedule') | int == 0 %}Today{% elif
            states('sensor.black_bin_schedule') | int == 1 %}Tonight{% else
            %}{{states('sensor.black_bin_schedule')}} days{% endif %}
          font: ppb.ttf
          x: 35
          "y": 33
          size: 18
          color: >-
            {{'black' if states('sensor.black_bin_schedule') == 'unknown' or
            states('sensor.black_bin_schedule') | int > 1 else 'white' }}
        - type: rectangle
          outline: white
          fill: >-
            {{'white' if states('sensor.blue_bin_schedule') == 'unknown' or
            states('sensor.blue_bin_schedule') | int > 1 else 'red' }}
          width: 1
          x_start: 168
          y_start: 5
          x_end: 290
          y_end: 60
        - type: text
          value: Blue
          font: ppb.ttf
          x: 190
          "y": 10
          size: 18
          color: >-
            {{'black' if states('sensor.blue_bin_schedule') == 'unknown' or
            states('sensor.blue_bin_schedule') | int > 1 else 'white' }}
        - type: text
          value: >-
            {% if states('sensor.blue_bin_schedule') == 'unknown' %}Unknown{%
            elif states('sensor.blue_bin_schedule') | int == 0 %}Today{% elif
            states('sensor.blue_bin_schedule') | int == 1 %}Tonight{% else
            %}{{states('sensor.blue_bin_schedule')}} days{% endif %}
          font: ppb.ttf
          x: 190
          "y": 33
          size: 18
          color: >-
            {{'black' if states('sensor.blue_bin_schedule') == 'unknown' or
            states('sensor.blue_bin_schedule') | int > 1 else 'white' }}
        - type: rectangle
          outline: white
          fill: >-
            {{'white' if states('sensor.brown_bin_schedule') == 'unknown' or
            states('sensor.brown_bin_schedule') | int > 1 else 'red' }}
          width: 1
          x_start: 5
          y_start: 70
          x_end: 123
          y_end: 123
        - type: text
          value: Brown
          font: ppb.ttf
          x: 35
          "y": 80
          size: 18
          color: >-
            {{'black' if states('sensor.brown_bin_schedule') == 'unknown' or
            states('sensor.brown_bin_schedule') | int > 1 else 'white' }}
        - type: text
          value: >-
            {% if states('sensor.brown_bin_schedule') == 'unknown' %}Unknown{%
            elif states('sensor.brown_bin_schedule') | int == 0 %}Today{% elif
            states('sensor.brown_bin_schedule') | int == 1 %}Tonight{% else
            %}{{states('sensor.brown_bin_schedule')}} days{% endif %}
          font: ppb.ttf
          x: 35
          "y": 103
          size: 18
          color: >-
            {{'black' if states('sensor.brown_bin_schedule') == 'unknown' or
            states('sensor.brown_bin_schedule') | int > 1 else 'white' }}
        - type: rectangle
          outline: white
          fill: >-
            {{'white' if states('sensor.green_bin_schedule') == 'unknown' or
            states('sensor.green_bin_schedule') | int > 1 else 'red' }}
          width: 1
          x_start: 168
          y_start: 70
          x_end: 290
          y_end: 123
        - type: text
          value: Green
          font: ppb.ttf
          x: 190
          "y": 80
          size: 18
          color: >-
            {{'black' if states('sensor.green_bin_schedule') == 'unknown' or
            states('sensor.green_bin_schedule') | int > 1 else 'white' }}
        - type: text
          value: >-
            {% if states('sensor.green_bin_schedule') == 'unknown' %}Unknown{%
            elif states('sensor.green_bin_schedule') | int == 0 %}Today{% elif
            states('sensor.green_bin_schedule') | int == 1 %}Tonight{% else
            %}{{states('sensor.green_bin_schedule')}} days{% endif %}
          font: ppb.ttf
          x: 190
          "y": 103
          size: 18
          color: >-
            {{'black' if states('sensor.green_bin_schedule') == 'unknown' or
            states('sensor.green_bin_schedule') | int > 1 else 'white' }}
        - type: icon
          value: trash-can
          x: 123
          "y": 39
          size: 50
          color: >-
            {{ 'red' if (([(14 if states('sensor.black_bin_schedule') ==
            'unknown' else states('sensor.black_bin_schedule')),(14 if
            states('sensor.blue_bin_schedule') == 'unknown' else
            states('sensor.blue_bin_schedule')),(14 if
            states('sensor.green_bin_schedule') == 'unknown' else
            states('sensor.green_bin_schedule')),(14 if
            states('sensor.brown_bin_schedule') == 'unknown' else
            states('sensor.brown_bin_schedule')) ]) | min ) | int < 2 else
            'black' }}
mode: single

Update: just so you get an idea of the colour blocks look like:

As an Amazon Associate I earn from qualifying purchases.

If you have found this post useful, please consider donating.