Last active
December 31, 2023 01:15
-
-
Save cmsj/a008d3bf044ad211605fdf9410f20791 to your computer and use it in GitHub Desktop.
Home Assistant python_scripts script to render info from the Waste Collection Schedule HACS integration
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# eInk Waste Collection Renderer | |
# v1.0 Copyright Chris Jones <[email protected]> | |
# Licensed under the MIT License | |
# This can be called as a Home Assistant service if you follow: https://www.home-assistant.io/integrations/python_script/ | |
# Calendar is expected to be populated by the Waste Collection Schedule integration from HACS | |
# (although I only tested with my home region, it's likely the data is formatted differently for other regions) | |
# eInk tag to render to | |
tag_entity = "open_epaper_link.000002838f103b16" | |
# eInk tag battery entity to display | |
tag_battery_entity = "sensor.tag5_battery" | |
# Calendar entry to take information from | |
# This calendar can be auto-populated if you live in a region supported by: | |
# https://github.com/mampfes/hacs_waste_collection_schedule | |
cal_entity = "calendar.the_royal_borough_of_kingston_council" | |
# Start tag rendering with an offset from the edges of the screen | |
y = 2 | |
x = 2 | |
# Sizes for the two types of lines of text we'll render | |
day_size = 21 | |
bin_size = 19 | |
# Number of days to show data for | |
# Default is 13 because our garbage collections happen weekly and I want to show no more than two weeks | |
display_days = 13 | |
# Define some metadata for different collection types so we can choose their names and icons | |
bin_types = { | |
"BLUE": { | |
"name": "Blue (cardboard)", | |
"icon": "package-variant" | |
}, | |
"GREEN": { | |
"name": "Green(glass/metal/plastic)", | |
"icon": "glass-fragile" | |
}, | |
"BLACK": { | |
"name": "Black (general)", | |
"icon": "delete-outline" | |
} | |
} | |
# Data storage we'll need later | |
tag_items = [] | |
bin_days = {} | |
# Calculate the start and end dates for our calendar search | |
start_date_time = dt_util.start_of_local_day().replace(hour=0, minute=0, second=0) | |
end_date_time = (start_date_time.replace(hour=23, minute=59, second=59) + datetime.timedelta(days=display_days)) | |
# Do the calendar search | |
cal_data = hass.services.call("calendar", "get_events", target={"entity_id": cal_entity}, | |
service_data={"start_date_time": start_date_time, "end_date_time": end_date_time}, | |
blocking=True, return_response=True) | |
# Loop over the calendar we searched, if it is in the results | |
if cal_entity not in cal_data: | |
# No calendar data was available, so render an error | |
tag_items.append({ | |
"type": "text", | |
"value": "Unable to read calendar", | |
"x": x, | |
"y": y, | |
"size": 20, | |
"color": "red" | |
}) | |
else: | |
logger.debug(cal_data) | |
# Loop over events in the current calendar | |
for event in cal_data[cal_entity]["events"]: | |
day = event["start"] | |
bin_type = event["summary"] | |
if day not in bin_days: | |
# This is a day we haven't seen yet, create an empty array to hold its items | |
bin_days[day] = [] | |
# Process the collection types from the calendar. These likely need to change for different regions than ours | |
if bin_type == "food waste bin": | |
# We don't do this bin in our house | |
continue | |
elif bin_type == "mixed recycling bin": | |
bin_days[day].append("GREEN") | |
elif bin_type == "paper and card recycling bin": | |
bin_days[day].append("BLUE") | |
elif bin_type == "refuse bin": | |
bin_days[day].append("BLACK") | |
else: | |
logger.warning("Unknown bin type: %s" % bin_type) | |
bin_days[day].append(bin_type) | |
# Now we have all of the collection days neatly collected, loop over that data for rendering | |
for day in sorted(bin_days): | |
logger.info("Adding tag items for day: %s" % day) | |
# Calendar info just has a string for the day of the bin collection. | |
# Turn that into a human-readable delta, by way of a lot of annoying python date/time calls | |
collection_date_datetime = dt_util.as_local(datetime.datetime.fromtimestamp(time.mktime(time.strptime(day, "%Y-%m-%d")))) | |
collection_day_delta = collection_date_datetime - start_date_time | |
num_days = collection_day_delta.days | |
day_string = "Unknown" | |
if num_days == 0: | |
day_string = "Today" | |
elif num_days == 1: | |
day_string = "Tomorrow" | |
elif num_days > 6: | |
day_string = day | |
elif num_days > 1: | |
day_string = "In %s days" % num_days | |
# Render the date | |
tag_items.append({ | |
"type": "text", | |
"value": day_string, | |
"x": 2, | |
"y": y, | |
"size": day_size, | |
"color": "black" | |
}) | |
y = y + day_size | |
# Render the collections for that date | |
for bin in bin_days[day]: | |
# First the icon for this bin | |
tag_items.append({ | |
"type": "icon", | |
"value": bin_types[bin]["icon"], | |
"x": 2, | |
"y": y + 1, | |
"size": bin_size, | |
"color": "red" | |
}) | |
# Then the name | |
tag_items.append({ | |
"type": "text", | |
"value": bin_types[bin]["name"], | |
"x": bin_size + 2, | |
"y": y, | |
"size": bin_size, | |
"color": "black" | |
}) | |
y = y + bin_size + 4 | |
y = y + 4 | |
# Add "Last Modified" and battery info footer | |
cur_datetime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) | |
battery_level = 0 | |
try: | |
battery_level = int(hass.states.get(tag_battery_entity).state) | |
except ValueError: | |
pass | |
tag_items.append({ | |
"type": "text", | |
"value": "Last updated: %s" % cur_datetime, | |
"size": 10, | |
"x": 45, | |
"y": 118, | |
"color": "black" | |
}) | |
# Battery shape | |
tag_items.append({ | |
"type": "rectangle", | |
"x_start": 275, | |
"y_start": 118, | |
"x_end": 295, | |
"y_end": 126, | |
"width": 1, | |
"fill": "white", | |
"outline": "black" | |
}) | |
# Battery bar | |
tag_items.append({ | |
"type": "rectangle", | |
"x_start": 293 - (battery_level / 100 * 16), | |
"y_start": 120, | |
"x_end": 293, | |
"y_end": 124, | |
"width": 1, | |
"fill": "black", | |
"outline": "black" | |
}) | |
# Battery terminal | |
tag_items.append({ | |
"type": "rectangle", | |
"x_start": 272, | |
"y_start": 120, | |
"x_end": 275, | |
"y_end": 124, | |
"width": 1, | |
"fill": "white", | |
"outline": "black" | |
}) | |
# Dispatch our rendering data structure to OpenEPaperLink | |
hass.services.call("open_epaper_link", "drawcustom", target={"entity_id": [tag_entity]}, service_data={"background": "white", "ttl": 300, "payload": tag_items}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment