Implement design

This commit is contained in:
Kenneth Allen 2025-04-30 14:57:28 +10:00
parent f714df41bf
commit fd52a7bb91
11 changed files with 9929 additions and 54 deletions

View File

@ -1,66 +1,89 @@
#!/usr/bin/python from datetime import datetime
import sys
import os
picdir = os.path.dirname(os.path.realpath(__file__))
import logging
import epd7in3g
import time
from PIL import Image, ImageDraw, ImageFont from PIL import Image, ImageDraw, ImageFont
logging.basicConfig(level=logging.DEBUG) def scale_to_height(icon):
scale = 100 / icon.height
return icon.resize((int(icon.width * scale), int(icon.height * scale)))
try: BLACK = 0x000000 # 00 BGR
logging.info("epd7in3g Demo") WHITE = 0xffffff # 01
YELLOW = 0x00ffff # 10
RED = 0x0000ff # 11
font18 = ImageFont.truetype('Font.ttc', 18)
font24 = ImageFont.truetype('Font.ttc', 24)
font40 = ImageFont.truetype('Font.ttc', 40)
font64 = ImageFont.truetype('Font.ttc', 64)
font100 = ImageFont.truetype('Font.ttc', 100)
epd = epd7in3g image = Image.new('RGB', (800, 480), WHITE)
logging.info("init and Clear") draw = ImageDraw.Draw(image)
# Date/time
now = datetime.now()
draw.text((10, 480-10-64), f'{now:%y/%m/%d}', font=font64, fill=BLACK)
draw.text((10, 480-10-64-10-100), f'{now:%I:%M}', font=font100, fill=BLACK)
# TODO: weather
draw.text((10, 10), '?mm', font=font64, fill=BLACK)
draw.text((10, 10+64), '20°', font=font100, fill=BLACK)
draw.text((10, 10+64+100), '6° - 24°', font=font64, fill=BLACK)
# Bus
y = 0
with Image.open('icon_bus.png') as icon:
image.paste(scale_to_height(icon), (230, y+50))
draw.polygon((200, 0, 475, 0, 475, 50, 212.5, 50), fill=BLACK)
draw.text((215, y+5+16), 'Camberwell', font=font24, fill=WHITE)
draw.text((400, y+5), '612 S', font=font40, fill=WHITE, anchor='ma')
draw.text((400, y+55), '15', font=font64, fill=BLACK, anchor='ma')
draw.text((550, y+5), '612 N', font=font40, fill=BLACK, anchor='ma')
draw.text((550, y+55), '5', font=font64, fill=BLACK, anchor='ma')
draw.text((700, y+5), '766 N', font=font40, fill=BLACK, anchor='ma')
draw.text((700, y+55), '20', font=font64, fill=BLACK, anchor='ma')
# Train
y = 160
with Image.open('icon_train.png') as icon:
image.paste(scale_to_height(icon), (280, y+50))
draw.polygon((240, 160, 595, 160, 595, 210, 252.5, 210), fill=BLACK)
draw.text((255, y+5+16), 'City', font=font24, fill=WHITE)
draw.text((400, y+5), 'Express', font=font40, fill=WHITE, anchor='ma')
draw.text((400, y+55), '15', font=font64, fill=BLACK, anchor='ma')
draw.text((550, y+5), 'All', font=font40, fill=WHITE, anchor='ma')
draw.text((550, y+55), '5', font=font64, fill=BLACK, anchor='ma')
draw.text((700, y+5), 'Outbound', font=font40, fill=BLACK, anchor='ma')
draw.text((700, y+55), '20', font=font64, fill=BLACK, anchor='ma')
# Tram (y=320 to 470)
y = 320
with Image.open('icon_tram.png') as icon:
image.paste(scale_to_height(icon), (310, y+50))
draw.polygon((280, 320, 800, 320, 800, 370, 292.5, 370), fill=BLACK)
draw.text((295, y+5+16), 'City', font=font24, fill=WHITE)
draw.text((550, y+5), '109', font=font40, fill=WHITE, anchor='ma')
draw.text((550, y+55), '7', font=font64, fill=BLACK, anchor='ma')
draw.text((700, y+5), '70', font=font40, fill=WHITE, anchor='ma')
draw.text((700, y+55), '14', font=font64, fill=BLACK, anchor='ma')
# Line between left and right
draw.line((200, 0, 400, 800), fill=BLACK)
image.save('test_before_palette.png')
# Dither into eink palette
pal_image = Image.new('P', (1, 1))
pal_image.putpalette((0x00,0x00,0x00, 0xff,0xff,0xff, 0xff,0xff,0x00, 0xff,0x00,0x00) + (0x00,0x00,0x00)*252)
# Convert the source image to the 4 colors, dithering if needed
image_4color = image.quantize(palette=pal_image)
image_4color.save('test.png')
show_on_screen = False
if show_on_screen:
import epd7in3g as epd
try:
epd.init() epd.init()
#epd.clear() epd.display(epd.get_buffer(image))
font24 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 24) input('Press Enter to clear')
font18 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 18) finally:
font40 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 40)
# Drawing on the image
logging.info("1.Drawing on the image...")
h_image = Image.new('RGB', (epd.width, epd.height), epd.WHITE) # 255: clear the frame
draw = ImageDraw.Draw(h_image)
draw.text((5, 0), 'hello world', font = font18, fill = epd.RED)
draw.text((5, 20), '7.3inch e-Paper', font = font24, fill = epd.YELLOW)
draw.text((5, 45), u'微雪电子', font = font40, fill = epd.BLACK)
draw.text((5, 85), u'微雪电子', font = font40, fill = epd.YELLOW)
draw.text((5, 125), u'微雪电子', font = font40, fill = epd.RED)
draw.line((5, 170, 80, 245), fill = epd.RED)
draw.line((80, 170, 5, 245), fill = epd.YELLOW)
draw.rectangle((5, 170, 80, 245), outline = epd.BLACK)
draw.rectangle((90, 170, 165, 245), fill = epd.YELLOW)
draw.arc((5, 250, 80, 325), 0, 360, fill = epd.BLACK)
draw.chord((90, 250, 165, 325), 0, 360, fill = epd.RED)
epd.display(epd.get_buffer(h_image))
time.sleep(3)
## read bmp file
#logging.info("2.read bmp file")
#h_image = Image.open(os.path.join(picdir, '7.3inch-1.bmp'))
#epd.display(epd.get_buffer(h_image))
#time.sleep(3)
#logging.info("3.read bmp file")
#h_image = Image.open(os.path.join(picdir, '7.3inch-2.bmp'))
#epd.display(epd.get_buffer(h_image))
#time.sleep(3)
#logging.info("4.read bmp file")
#h_image = Image.open(os.path.join(picdir, '7.3inch-3.bmp'))
#epd.display(epd.getbuffer(h_image))
#time.sleep(3)
logging.info("Clear...")
epd.clear() epd.clear()
epd.epdconfig.module_exit(cleanup=True)
logging.info("Goto Sleep...")
epd.sleep()
finally:
epd7in3g.epdconfig.module_exit(cleanup=True)

15
bom.py Normal file
View File

@ -0,0 +1,15 @@
from ftplib import FTP
import xml.etree.ElementTree as ET
ftp = FTP('ftp.bom.gov.au')
file = []
try:
ftp.login()
ftp.cwd('anon/gen/fwo')
ftp.retrbinary('RETR IDV17000.xml', file.append)
finally:
ftp.quit()
root = ET.fromstringlist(file)
print(root)
print([e.attrib['description'] for e in root.findall('./forecast/area')])

66
demo.py Normal file
View File

@ -0,0 +1,66 @@
#!/usr/bin/python
import sys
import os
picdir = os.path.dirname(os.path.realpath(__file__))
import logging
import epd7in3g
import time
from PIL import Image, ImageDraw, ImageFont
logging.basicConfig(level=logging.DEBUG)
try:
logging.info("epd7in3g Demo")
epd = epd7in3g
logging.info("init and Clear")
epd.init()
#epd.clear()
font24 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 24)
font18 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 18)
font40 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 40)
# Drawing on the image
logging.info("1.Drawing on the image...")
h_image = Image.new('RGB', (epd.width, epd.height), epd.WHITE) # 255: clear the frame
draw = ImageDraw.Draw(h_image)
draw.text((5, 0), 'hello world', font = font18, fill = epd.RED)
draw.text((5, 20), '7.3inch e-Paper', font = font24, fill = epd.YELLOW)
draw.text((5, 45), u'微雪电子', font = font40, fill = epd.BLACK)
draw.text((5, 85), u'微雪电子', font = font40, fill = epd.YELLOW)
draw.text((5, 125), u'微雪电子', font = font40, fill = epd.RED)
draw.line((5, 170, 80, 245), fill = epd.RED)
draw.line((80, 170, 5, 245), fill = epd.YELLOW)
draw.rectangle((5, 170, 80, 245), outline = epd.BLACK)
draw.rectangle((90, 170, 165, 245), fill = epd.YELLOW)
draw.arc((5, 250, 80, 325), 0, 360, fill = epd.BLACK)
draw.chord((90, 250, 165, 325), 0, 360, fill = epd.RED)
epd.display(epd.get_buffer(h_image))
time.sleep(3)
## read bmp file
#logging.info("2.read bmp file")
#h_image = Image.open(os.path.join(picdir, '7.3inch-1.bmp'))
#epd.display(epd.get_buffer(h_image))
#time.sleep(3)
#logging.info("3.read bmp file")
#h_image = Image.open(os.path.join(picdir, '7.3inch-2.bmp'))
#epd.display(epd.get_buffer(h_image))
#time.sleep(3)
#logging.info("4.read bmp file")
#h_image = Image.open(os.path.join(picdir, '7.3inch-3.bmp'))
#epd.display(epd.getbuffer(h_image))
#time.sleep(3)
logging.info("Clear...")
epd.clear()
logging.info("Goto Sleep...")
epd.sleep()
finally:
epd7in3g.epdconfig.module_exit(cleanup=True)

BIN
icon_bus.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
icon_train.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
icon_tram.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

67
ptv.py Normal file
View File

@ -0,0 +1,67 @@
from collections import defaultdict
from datetime import datetime
from hashlib import sha1
import hmac
import httpx
import os
dev_id = os.environ['PTV_USER_ID']
api_key = os.environ['PTV_API_KEY']
def sign(request):
request += '&' if ('?' in request) else '?'
request += 'devid='
request += dev_id
hashed = hmac.new(api_key.encode(), request.encode(), sha1)
return f'https://timetableapi.ptv.vic.gov.au{request}&signature={hashed.hexdigest().upper()}'
def fetch(path):
res = httpx.get(sign(path))
try:
res.raise_for_status()
except:
try:
print(res.json())
except:
pass
raise
return res.json()
# Lilydale route 9 (type 0) (dir 1 in, 8 out) (stop 1229)
# Belgrave route 2 (type 0) (dir 1 in, 2 out) (stop 1229)
# 109 route 722 (type 1) (dir 2 E, 3 W) (stop 2415 E, 2460 W)
# 70 route 940 (type 1) (dir 28 E, 29 W) (stop 2161 E, 2162 W)
# 766 route 15800 (type 2) (dir 13 N, 207 S) (stop 17861)
# 612 route 13024 (type 2) (dir 13 N, 158 S) (stop 17861)
class Route:
def __init__(self, name, route_id, route_type_id, directions, stops):
self.name = name
self.route_id = route_id
self.route_type_id = route_type_id
self.directions = directions
self.stops = stops
local_routes = [
Route('Lilydale', 9 , 0, [(1, 'in'), (8, 'out')] , [1229] ),
Route('Belgrave', 2 , 0, [(1, 'in'), (2, 'out')] , [1229] ),
Route('109' , 722 , 1, [(2, 'E'), (3, 'W')] , [2415, 2460]),
Route('70' , 940 , 1, [(28, 'E'), (29, 'W')] , [2415, 2460]),
Route('766' , 15800, 2, [(13, 'N'), (207, 'S')] , [17861] ),
Route('612' , 13024, 2, [(13, 'N'), (158, 'S')] , [17861] ),
]
def fetch_departures(stop_id, route_type_id):
deps = fetch(f'/v3/departures/route_type/{route_type_id}/stop/{stop_id}')['departures']
for dep in deps:
for key in ['estimated_departure_utc', 'scheduled_departure_utc']:
if dep[key]:
dep[key] = datetime.fromisoformat(dep[key])
deps.sort(key=lambda dep: dep['estimated_departure_utc'] or dep['scheduled_departure_utc'])
return deps
def get_departure_data():
by_route_type = defaultdict(list)
for route_type, stop in set((r.route_type_id, s) for r in local_routes for s in r.stops):
by_route_type[route_type] += fetch_departures(stop, route_type)
return by_route_type

BIN
reuben.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

9704
routes.json Normal file

File diff suppressed because it is too large Load Diff

BIN
test.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
test_before_palette.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB