From 6bc9847a518848a2f0050126c649b25f59a1a860 Mon Sep 17 00:00:00 2001 From: Andrew de Quincey Date: Mon, 19 Apr 2021 21:42:33 +0100 Subject: [PATCH] Add kiln-display --- kiln-display.py | 137 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 kiln-display.py diff --git a/kiln-display.py b/kiln-display.py new file mode 100644 index 0000000..3ca26be --- /dev/null +++ b/kiln-display.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python + +import websocket +import json +import time +import datetime +import digitalio +import board +import adafruit_rgb_display.st7789 as st7789 +from PIL import Image, ImageDraw, ImageFont + + +KILN_HOSTNAME = 'localhost:8081' +MIN_UPDATE_SECS = 10 + +status_ws = websocket.WebSocket() +storage_ws = websocket.WebSocket() + +# Configuration for CS and DC pins for Raspberry Pi +cs_pin = digitalio.DigitalInOut(board.CE0) +dc_pin = digitalio.DigitalInOut(board.D25) +reset_pin = None +BAUDRATE = 64000000 # The pi can be very fast! +# Create the ST7789 display: +display = st7789.ST7789( + board.SPI(), + cs=cs_pin, + dc=dc_pin, + rst=reset_pin, + baudrate=BAUDRATE, + height=240, y_offset=80, rotation=180 +) +display.fill() + +# turn backlight on +backlight = digitalio.DigitalInOut(board.D22) +backlight.switch_to_output() +backlight.value = True + +# create screen and font +screen = Image.new("RGB", (display.width, display.height), (0, 0, 0)) +screend = ImageDraw.Draw(screen) +screenfont = ImageFont.truetype("/home/adq/DroidSans.ttf", 46) +chartminx = 0 +chartw = display.width +chartminy = int(display.height / 2) +charth = int(display.height / 2) + +# main loop +cur_profile = None +last_update = datetime.datetime.now() +while True: + # gather data from kiln controller. + try: + msg = json.loads(status_ws.recv()) + if msg.get('profile') and not cur_profile: + storage_ws.send('GET') + for profile in json.loads(storage_ws.recv()): + if profile['name'] == msg.get('profile'): + cur_profile = profile + break + + elif not msg.get('profile'): + cur_profile = None + + except websocket.WebSocketException: + try: + status_ws.connect(f'ws://{KILN_HOSTNAME}/status') + storage_ws.connect(f'ws://{KILN_HOSTNAME}/storage') + except Exception: + time.sleep(5) + + continue + + # we don't need to update ALL the time + if (datetime.datetime.now() - last_update).total_seconds() < MIN_UPDATE_SECS: + continue + last_update = datetime.datetime.now() + + # setup the basic display + screend.rectangle([0, 0, display.width, display.height], fill='black') + screend.line([chartminx, chartminy, chartminx + chartw, chartminy], fill='white') + + # show the current temperature + if msg.get('temperature'): + temp = int(msg['temperature']) + text = f"{temp}°" + (tw, th) = screenfont.getsize(text) + screend.text((0, display.height - th), text, font=screenfont, fill='yellow') + + # inform if we're actively heating + if msg.get('heat'): + screend.ellipse((display.width - 25, display.height - 25, display.width - 5, display.height - 5), fill='red') + + # if we have a profile, show details of that! + if cur_profile: + cur_profile_data = cur_profile['data'] + + # compute ranges of data + mintime = min([i[0] for i in cur_profile_data]) + maxtime = max([i[0] for i in cur_profile_data]) + timerange = maxtime - mintime + mintemp = 0 + maxtemp = max([i[1] for i in cur_profile_data]) + temprange = maxtemp - mintemp + + # draw chart of the temperature profie + line = [] + for i in sorted(cur_profile_data, key=lambda x: x[0]): + x = chartminx + (((i[0] - mintime) * chartw) / timerange) + y = chartminy - (((i[1] - mintemp) * charth) / temprange) + line.extend([x, y]) + screend.line(line, fill='yellow') + + # draw current position as a blue line + cur_time = msg['runtime'] if msg['runtime'] > 0 else 0 + cur_time_x = ((cur_time - mintime) * chartw) / timerange + cur_temp = int(msg['temperature']) + cur_temp_y = ((cur_temp - mintemp) * charth) / temprange + screend.line([chartminx + cur_time_x, chartminy, chartminx + cur_time_x, chartminy - charth], fill='blue') + + # show the where we are + time_done = msg['runtime'] if msg['runtime'] > 0 else 0 + time_done_mins = int((time_done / 60) % 60) + time_done_hours = int(time_done / 60 / 60) + screend.text((0, chartminy), f"{time_done_hours:02d}:{time_done_mins:02d}", font=screenfont, fill='blue') + + # show how long we have left + time_left = msg['totaltime'] - msg['runtime'] + time_left_mins = int((time_left / 60) % 60) + time_left_hours = int((time_left / 60) / 60) + text = f"{time_left_hours:02d}:{time_left_mins:02d}" + (tw, th) = screenfont.getsize(text) + screend.text((display.width - tw, chartminy), text, font=screenfont, fill='white') + + # update display + display.image(screen)