Implement design
This commit is contained in:
parent
f714df41bf
commit
fd52a7bb91
143
__main__.py
143
__main__.py
@ -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)))
|
||||||
|
|
||||||
|
BLACK = 0x000000 # 00 BGR
|
||||||
|
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)
|
||||||
|
|
||||||
|
image = Image.new('RGB', (800, 480), WHITE)
|
||||||
|
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:
|
try:
|
||||||
logging.info("epd7in3g Demo")
|
|
||||||
|
|
||||||
epd = epd7in3g
|
|
||||||
logging.info("init and Clear")
|
|
||||||
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)
|
|
||||||
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:
|
finally:
|
||||||
epd7in3g.epdconfig.module_exit(cleanup=True)
|
epd.clear()
|
||||||
|
epd.epdconfig.module_exit(cleanup=True)
|
||||||
|
|||||||
15
bom.py
Normal file
15
bom.py
Normal 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
66
demo.py
Normal 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
BIN
icon_bus.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
BIN
icon_train.png
Normal file
BIN
icon_train.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
BIN
icon_tram.png
Normal file
BIN
icon_tram.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
67
ptv.py
Normal file
67
ptv.py
Normal 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
BIN
reuben.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
9704
routes.json
Normal file
9704
routes.json
Normal file
File diff suppressed because it is too large
Load Diff
BIN
test_before_palette.png
Normal file
BIN
test_before_palette.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 100 KiB |
Loading…
Reference in New Issue
Block a user