Epaper Displays and waste management
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: