class Inkywhatrbw(Observer):

    def __init__(self, observable, mode):
        super().__init__(observable=observable)
        self.inky_display = InkyWHAT("red")
        self.inky_display.set_border(self.inky_display.WHITE)
        self.image = Image.new('P', (SCREEN_WIDTH, SCREEN_HEIGHT))
        self.mode = mode

    def form_image(self, prices):
        WHITE = self.inky_display.WHITE
        RED = self.inky_display.RED
        BLACK = self.inky_display.BLACK
        screen_draw = ImageDraw.Draw(self.image)
        screen_draw.rectangle([0,0,SCREEN_WIDTH,SCREEN_HEIGHT],fill=WHITE)
        if self.mode == "candle":
            Plot.candle(prices, size=(SCREEN_WIDTH - LEFT_MARGIN, SCREEN_HEIGHT - BOTTOM_MARGIN), position=(LEFT_MARGIN, 0), draw=screen_draw, fill_neg=RED, fill_pos=BLACK)
        else:
            last_prices = [x[3] for x in prices]
            Plot.line(last_prices, size=(SCREEN_WIDTH - LEFT_MARGIN, SCREEN_HEIGHT - BOTTOM_MARGIN), position=(LEFT_MARGIN, 0), draw=screen_draw, fill=BLACK)

        flatten_prices = [item for sublist in prices for item in sublist]
        Plot.y_axis_labels(flatten_prices, FONT_SMALL, (0, 0), (LEFT_MARGIN, SCREEN_HEIGHT - BOTTOM_MARGIN - SMALL_FONT_SIZE - 3), draw=screen_draw, fill=BLACK)
        screen_draw.line([(0, SCREEN_HEIGHT - BOTTOM_MARGIN), (SCREEN_WIDTH, SCREEN_HEIGHT - BOTTOM_MARGIN)], fill=BLACK)
        screen_draw.line([(LEFT_MARGIN, 0), (LEFT_MARGIN, SCREEN_HEIGHT - BOTTOM_MARGIN)], fill=BLACK)
        Plot.caption(flatten_prices[len(flatten_prices) - 1], SCREEN_HEIGHT - BOTTOM_MARGIN, SCREEN_WIDTH, FONT_LARGE, screen_draw, fill=BLACK, currency_offset=LEFT_MARGIN, price_offset=LEFT_MARGIN)

    def update(self, data):
        self.form_image(data)
        self.inky_display.set_image(self.image)
        self.inky_display.show()

    def close(self):
        pass
 def try_real_hw():
     try:
         from inky import InkyWHAT
         inky_display = InkyWHAT('red')
         inky_display.set_border(inky_display.WHITE)
         return inky_display
     except ImportError:
         return None
def inky_show(im):
    im = Image.open(im)
    im = im.transpose(Image.ROTATE_90)
    inky_display = InkyWHAT("black")
    inky_display.set_border(inky_display.WHITE)
    assert inky_display.WIDTH == 400
    assert inky_display.HEIGHT == 300
    inky_display.set_image(im)
    inky_display.show()
Exemple #4
0
def setup_inky(inky_colour):
    from inky import InkyWHAT

    inky_display = InkyWHAT(inky_colour)
    ink_white = inky_display.WHITE  #0
    ink_black = inky_display.BLACK  #1
    ink_color = inky_display.YELLOW  #2

    inky_display.set_border(inky_display.WHITE)

    w = inky_display.WIDTH
    h = inky_display.HEIGHT

    return w, h, ink_black, ink_color  #,fonts_dict
Exemple #5
0
def send_to_display():
    # TODO: do only in python... was having some issues with svg2png
    output_svg_path = os.path.abspath("output.svg")
    output_png_path = os.path.abspath("output.png")
    os.system(
        f"inkscape -z -w 400 -h 300 {output_svg_path} -e {output_png_path}")
    img = Image.open(output_png_path)
    pal_img = Image.new("P", (1, 1))
    pal_img.putpalette((255, 255, 255, 0, 0, 0, 255, 0, 0) + (0, 0, 0) * 252)
    img = img.convert("RGB").quantize(palette=pal_img)

    # send
    inky_display = InkyWHAT("red")
    inky_display.set_border(inky_display.RED)
    inky_display.set_image(img)
    inky_display.show()
Exemple #6
0
def glyphe():
  # Load the icons and rotate them each time. This gives us
  # a horoscope which rotates during the day, potentially 
  # making us think differently about their meaning
  print("Starting...")
  icons = pickle.load( open( "glyphes.pickle", "rb" ) )
  print(icons)
  icons.insert(0, icons.pop()) # put the last element at the front
  pickle.dump( icons, open( "glyphes.pickle", "wb" ) )
  print(icons)

  total_width = 1947 # to make this 400/300 on resize
  total_height = 1460 # 2 * 700 + 60

  new_image = Image.new('RGBA', (total_width, total_height), 255)

  offset = ( int(total_width / 2) - 700, 30)
  new_image.paste( Image.open(dir + 'icons/' + str(icons[0])), offset )

  offset = ( int(total_width / 2), 30 )
  new_image.paste( Image.open(dir + 'icons/' + icons[1]), offset )

  offset = ( int(total_width / 2) - 700, int(new_image.height / 2) + 10)
  new_image.paste( Image.open(dir + 'icons/' + icons[2]), offset )

  offset = ( int(new_image.width / 2), int(new_image.height / 2) + 10 )
  new_image.paste( Image.open(dir + 'icons/' + icons[3]), offset )

  new_image.convert('P')
  new_image.save(dir + 'saved/glyphe.png')

  # Now resize the image to 400x300 and save it for eink display
  img = Image.open(dir + 'saved/glyphe.png')
  img = img.resize((400, 300), resample=Image.LANCZOS)
  img = img.quantize() 
  img.save(dir + 'saved/glyphe-resized.png')

  from inky import InkyWHAT
  inky_display = InkyWHAT("black")
  inky_display.set_border(inky_display.WHITE)

  inky_display.set_image(img)
  inky_display.show() 
  print("Done!")
Exemple #7
0
def create(quote):
  inky_display = InkyWHAT("black")
  inky_display.set_border(inky_display.WHITE)

  # From https://gist.github.com/jasondilworth56/27764ae8ed2327a34ceebb06e75c30ea
  from PIL import ImageFont, ImageDraw, Image

  text = quote[0]
  author = quote[1]
  title = quote[2]

  #font = "/usr/share/fonts/truetype/freefont/FreeMono.ttf"
  font = "/usr/share/fonts/truetype/freefont/FreeSans.ttf"
  #font = "/home/pi/.fonts/Roboto-Bold.ttf"

  #font = "/home/pi/.fonts/Bitter-Regular.otf"
  #font = "/home/pi/.fonts/ufonts.com_rockwell.ttf"
  #font = "/home/pi/.fonts/Bookerly/Bookerly-Regular.ttf"
  #font = "/home/pi/.fonts/static/PlayfairDisplay-Regular.ttf"
  #font = "/home/pi/.fonts/PlayfairDisplay-VariableFont_wght.ttf"
  font = "/home/pi/.fonts/FredokaOne-Regular.ttf"
  #font = "/home/pi/.fonts/AmaticSC-Regular.ttf"

  img = ImageText((400, 300), background=(255, 255, 255))

  img.fill_text_box((20, 20), text, box_width=340, box_height=250, font_filename=font)

  meta_line = author + ', ' + title
  #img.write_text( (10, inky_display.HEIGHT - 20), meta_line, font_filename=font)
  #img.fill_text_box((30, inky_display.HEIGHT - 40), meta_line, box_width=320, box_height=30, font_filename=font)
  img.write_text_box((30, inky_display.HEIGHT - 30), meta_line, box_width=320, font_filename=font, font_size=12, place='right')

  filename = '/home/pi/src/coten/images/coten.png'
  img.save(filename)

  img = Image.open(filename)
  img = img.quantize()

  inky_display.set_image(img)
  inky_display.set_border(inky_display.WHITE)
  inky_display.show()
updateTextWidth, updateTextHeight = accountFont.getsize(tweet_update)
draw.text(
    ((displayWidth - updateTextWidth), (headerHeight - updateTextHeight)),
    tweet_update, white, updateFont)

########################
## FINALISE THE IMAGE ##
########################
# Set a PIL image, numpy array or list to Inky's internal buffer. The image dimensions should match the dimensions of the pHAT or wHAT you're using.
# You should use PIL to create an image. PIL provides an ImageDraw module which allow you to draw text, lines and shapes over your image.
# See: https://pillow.readthedocs.io/en/stable/reference/ImageDraw.html

inky.set_image(img)

###############################
## SET DISPLAY BORDER COLOUR ##
###############################
# .set_border(colour) sets the colour at the edge of the display
# colour should be one of 'inky.RED', 'inky.YELLOW', 'inky.WHITE' or 'inky.BLACK' with available colours depending on your display type.

inky.set_border(white)

########################
## UPDATE THE DISPLAY ##
########################
# Once you've prepared and set your image, and chosen a border colour, you can update your e-ink display with .show()

if test == True:
    img.save("debug.png")
else:
    inky.show()
Exemple #9
0
from math import floor
from random import randint
from inky import InkyWHAT

from PIL import Image, ImageDraw

inky_display = InkyWHAT("red")
inky_display.set_border(inky_display.WHITE)
rules = [18, 22, 26, 30, 45, 57, 60, 62, 73, 75, 82, 86, 89, 90, 101, 102, 105, 109, 110, 124, 126, 129, 131, 135, 137,
         145, 146, 149, 150, 153, 154, 161, 165, 167, 181, 182, 190, 193, 195, 210, 214, 218, 225]

rulesetNo = rules[randint(0, len(rules) - 1)]
ruleset = list(map(int, bin(rulesetNo)[2:].zfill(8)[::-1]))

for i in range(0, 8):
    if ruleset[i] == 1:
        if randint(0, 100) <= 25:
            ruleset[i] = 2

print(ruleset)

width = inky_display.WIDTH
height = inky_display.HEIGHT

cellSize = randint(1, 5)
rectSize = cellSize - 1

visibleGenerations = floor(height / cellSize)
numCells = floor(width / cellSize)
cells = [0] * numCells
Exemple #10
0
    parser.add_argument("--write", action="store_true", default=False)
    parser.add_argument("--border", action="store_true", default=False)
    parser.add_argument("--font", default="Gidole-Regular")
    parser.add_argument("--font-size", type=int, default=25)
    parser.add_argument("--font-padding", type=int, default=5)
    parser.add_argument("--filename",
                        type=str,
                        help="resources/matisse.png|promenade_des_anglais.jpg")
    args = parser.parse_args()
    logging.basicConfig(format='%(asctime)s %(levelname)s: %(message)s',
                        level=logging.INFO)

    inky_display = InkyWHAT("black")

    if args.border:
        inky_display.set_border(inky_display.BLACK)

    if args.clear:
        logging.info("Clearing Inky")
        clear(inky_display)

    if args.draw and args.filename:
        logging.info(f"Drawing Inky {args.filename}")
        image = prepare(inky_display, args.filename)
        draw(inky_display, image)

    if args.write:
        logging.info(f"Writing Inky lines from stdin")
        font = ImageFont.truetype(args.font, args.font_size)
        # font = ImageFont.truetype(FredokaOne, args.font_size)
        lines = fit_lines(
Exemple #11
0
#make the image - commented for LED
#img = qr.make_image(fill_color="orange", back_color="purple")
img = qr.make_image(fill_color="black", back_color="white")

#save as a file
img.save('qr_image.png')

imgURL = "./displayScreens/qrscan_bw.png"
im = Image.open(imgURL)
#resizing the image so it fits to the screen adding RGB support
size = (400, 300)
out = im.resize(size)
out.save('resize-output.png')

#combine the images, note: must have ImageMagick installed on pi
subprocess.call(
    'composite -blend 100 -gravity center qr_image.png resize-output.png displayImage.png',
    shell=True)
print("Merged images")

img = Image.open('displayImage.png')
pal_img = Image.new("P", (1, 1))
pal_img.putpalette((255, 255, 255, 0, 0, 0, 255, 0, 0) + (0, 0, 0) * 252)

img = img.convert("RGB").quantize(palette=pal_img)

inkywhat.set_image(img)  #NOTE can only have this line on a rasberry pi
inkywhat.set_border('white')
inkywhat.show()
Exemple #12
0
def create_pimoroni(quote):
	import argparse
	import random
	import sys

	from inky import InkyWHAT

	from PIL import Image, ImageFont, ImageDraw
	from font_source_serif_pro import SourceSerifProSemibold
	from font_source_sans_pro import SourceSansProSemibold
	
	# Set up the correct display and scaling factors
	inky_display = InkyWHAT('black')
	inky_display.set_border(inky_display.WHITE)
	# inky_display.set_rotation(180)

	w = inky_display.WIDTH
	h = inky_display.HEIGHT

	# Create a new canvas to draw on
	img = Image.new("P", (inky_display.WIDTH, inky_display.HEIGHT))
	draw = ImageDraw.Draw(img)

	# Load the fonts
	font_size = 24
	author_font_size = 18

	quote_font = ImageFont.truetype(SourceSansProSemibold, font_size)
	author_font = ImageFont.truetype(SourceSerifProSemibold, author_font_size)

	# The amount of padding around the quote. Note that
	# a value of 30 means 15 pixels padding left and 15
	# pixels padding right.
	#
	# Also define the max width and height for the quote.

	padding = 50
	max_width = w - padding
	max_height = h - padding - author_font.getsize("ABCD ")[1]

	below_max_length = False

	# Only pick a quote that will fit in our defined area
	# once rendered in the font and size defined.

	while not below_max_length:
			reflowed = reflow_quote(quote, max_width, quote_font)
			p_w, p_h = quote_font.getsize(reflowed)  # Width and height of quote
			p_h = p_h * (reflowed.count("\n") + 1)   # Multiply through by number of lines

			if p_h < max_height:
					below_max_length = True              # The quote fits! Break out of the loop.

			else:
					font_size = font_size - 1
					author_font_size = author_font_size - 1

					quote_font = ImageFont.truetype(SourceSansProSemibold, font_size)
					author_font = ImageFont.truetype(SourceSerifProSemibold, author_font_size)

					continue

	# x- and y-coordinates for the top left of the quote
	quote_x = (w - max_width) / 2
	quote_y = ((h - max_height) + (max_height - p_h - author_font.getsize("ABCD ")[1])) / 2

	# x- and y-coordinates for the top left of the author
	author_x = quote_x
	author_y = quote_y + p_h

	author = [ '— ' + quote[1] + ', ' + quote[2] ]
	reflowed_author = reflow_quote(author, max_width, author_font)

	# Write our quote and author to the canvas
	draw.multiline_text((quote_x, quote_y), reflowed, fill=inky_display.BLACK, font=quote_font, align="left")
	draw.multiline_text((author_x, author_y), reflowed_author, fill=inky_display.BLACK, font=author_font, align="right")

	print(reflowed + "\n" + reflowed_author + "\n")

	# Display the completed canvas on Inky wHAT
	inky_display.set_image(img)
	inky_display.show()
Exemple #13
0
def on_message(mosq, obj, msg):

    # Set MQTT Message

    message = str(msg.payload.decode('UTF-8'))

    print(message)

    # Set Font etc and Refresh

    inky_display = InkyWHAT("red")
    inky_display.set_border(inky_display.WHITE)
    img = Image.open("/home/pi/scripts/resources/whatbackground.png"
                     )  #adds a red line at the bottom
    draw = ImageDraw.Draw(img)

    # Display the completed canvas on Inky wHAT

    if 'Weather' in message:
        fonttop = ImageFont.truetype("/home/pi/scripts/resources/hm.ttf",
                                     30)  # any ttf font can be used
        font = ImageFont.truetype("/home/pi/scripts/resources/hm.ttf",
                                  30)  # any ttf font can be used
        wrapped = textwrap.wrap(message, width=24)

        if (len(wrapped) >= 1):
            # Status Line 1
            status_one = wrapped[0]
            w, h = font.getsize(status_one)
            # Center the text and align it with the name strip
            x = (inky_display.WIDTH / 2) - (w / 2)
            y = 10 - (h / 2)
            draw.text((15, 30),
                      status_one,
                      inky_display.RED,
                      fonttop,
                      align="left")

        if (len(wrapped) >= 2):
            # Status Line 2
            status_two = wrapped[1]
            w, h = font.getsize(status_one)
            # Center the text and align it with the name strip
            x = (inky_display.WIDTH / 2) - (w / 2)
            y = 35 - (h / 2)
            draw.text((15, 70),
                      status_two,
                      inky_display.BLACK,
                      font,
                      align="left")

        if (len(wrapped) >= 3):
            # Status Line 3
            status_three = wrapped[2]
            w, h = font.getsize(status_one)
            # Center the text and align it with the name strip
            x = (inky_display.WIDTH / 2) - (w / 2)
            y = 60 - (h / 2)
            draw.text((15, 110),
                      status_three,
                      inky_display.BLACK,
                      font,
                      align="left")

        if (len(wrapped) >= 4):
            # Status Line 4
            status_four = wrapped[3]
            w, h = font.getsize(status_one)
            # Center the text and align it with the name strip
            x = (inky_display.WIDTH / 2) - (w / 2)
            y = 85 - (h / 2)
            draw.text((15, 150),
                      status_four,
                      inky_display.BLACK,
                      font,
                      align="left")

        if (len(wrapped) >= 5):
            # Status Line 5
            status_five = wrapped[4]
            w, h = font.getsize(status_one)
            # Center the text and align it with the name strip
            x = (inky_display.WIDTH / 2) - (w / 2)
            y = 85 - (h / 2)
            draw.text((15, 190),
                      status_five,
                      inky_display.BLACK,
                      font,
                      align="left")

        if (len(wrapped) >= 6):
            # Status Line 5
            status_six = wrapped[5]
            w, h = font.getsize(status_one)
            # Center the text and align it with the name strip
            x = (inky_display.WIDTH / 2) - (w / 2)
            y = 85 - (h / 2)
            draw.text((15, 230),
                      status_six,
                      inky_display.BLACK,
                      font,
                      align="left")

    elif 'Time' in message:
        fonttop = ImageFont.truetype("/home/pi/scripts/resources/hm.ttf",
                                     50)  # larger text for time
        font = ImageFont.truetype("/home/pi/scripts/resources/hm.ttf",
                                  50)  # larger text for time
        wrapped = textwrap.wrap(message, width=14)

        if (len(wrapped) >= 1):
            # Status Line 1
            status_one = wrapped[0]
            w, h = font.getsize(status_one)
            # Center the text and align it with the name strip
            x = (inky_display.WIDTH / 2) - (w / 2)
            y = 10 - (h / 2)
            draw.text((15, 40),
                      status_one,
                      inky_display.RED,
                      fonttop,
                      align="left")

        if (len(wrapped) >= 2):
            # Status Line 2
            status_two = wrapped[1]
            w, h = font.getsize(status_two)
            # Center the text and align it with the name strip
            x = (inky_display.WIDTH / 2) - (w / 2)
            y = 35 - (h / 2)
            draw.text((15, 100),
                      status_two,
                      inky_display.BLACK,
                      font,
                      align="left")

        if (len(wrapped) >= 3):
            # Status Line 3
            status_three = wrapped[2]
            w, h = font.getsize(status_three)
            # Center the text and align it with the name strip
            x = (inky_display.WIDTH / 2) - (w / 2)
            y = 60 - (h / 2)
            draw.text((15, 160),
                      status_three,
                      inky_display.BLACK,
                      font,
                      align="left")

        if (len(wrapped) >= 4):
            # Status Line 4
            status_four = wrapped[3]
            w, h = font.getsize(status_four)
            # Center the text and align it with the name strip
            x = (inky_display.WIDTH / 2) - (w / 2)
            y = 85 - (h / 2)
            draw.text((15, 220),
                      status_four,
                      inky_display.BLACK,
                      font,
                      align="left")

    else:
        fonttop = ImageFont.truetype("/home/pi/scripts/resources/hm.ttf", 24)
        font = ImageFont.truetype("/home/pi/scripts/resources/hm.ttf", 26)
        wrapped = textwrap.wrap(message, width=27.5)

        if (len(wrapped) >= 1):
            # Status Line 1
            status_one = wrapped[0]
            w, h = font.getsize(status_one)
            # Center the text and align it with the name strip
            x = (inky_display.WIDTH / 2) - (w / 2)
            y = 10 - (h / 2)
            draw.text((15, 10),
                      status_one,
                      inky_display.RED,
                      fonttop,
                      align="left")

        if (len(wrapped) >= 2):
            # Status Line 2
            status_two = wrapped[1]
            w, h = font.getsize(status_two)
            # Center the text and align it with the name strip
            x = (inky_display.WIDTH / 2) - (w / 2)
            y = 35 - (h / 2)
            draw.text((15, 50),
                      status_two,
                      inky_display.BLACK,
                      font,
                      align="left")

        if (len(wrapped) >= 3):
            # Status Line 3
            status_three = wrapped[2]
            w, h = font.getsize(status_three)
            # Center the text and align it with the name strip
            x = (inky_display.WIDTH / 2) - (w / 2)
            y = 60 - (h / 2)
            draw.text((15, 90),
                      status_three,
                      inky_display.BLACK,
                      font,
                      align="left")

        if (len(wrapped) >= 4):
            # Status Line 4
            status_four = wrapped[3]
            w, h = font.getsize(status_four)
            # Center the text and align it with the name strip
            x = (inky_display.WIDTH / 2) - (w / 2)
            y = 85 - (h / 2)
            draw.text((15, 130),
                      status_four,
                      inky_display.BLACK,
                      font,
                      align="left")

        if (len(wrapped) >= 5):
            # Status Line 5
            status_five = wrapped[4]
            w, h = font.getsize(status_five)
            # Center the text and align it with the name strip
            x = (inky_display.WIDTH / 2) - (w / 2)
            y = 85 - (h / 2)
            draw.text((15, 170),
                      status_five,
                      inky_display.BLACK,
                      font,
                      align="left")

        if (len(wrapped) >= 6):
            # Status Line 5
            status_six = wrapped[5]
            w, h = font.getsize(status_six)
            # Center the text and align it with the name strip
            x = (inky_display.WIDTH / 2) - (w / 2)
            y = 85 - (h / 2)
            draw.text((15, 210),
                      status_six,
                      inky_display.BLACK,
                      font,
                      align="left")

        if (len(wrapped) >= 7):
            # Status Line 5
            status_seven = wrapped[6]
            w, h = font.getsize(status_seven)
            # Center the text and align it with the name strip
            x = (inky_display.WIDTH / 2) - (w / 2)
            y = 85 - (h / 2)
            draw.text((15, 250),
                      status_seven,
                      inky_display.BLACK,
                      font,
                      align="left")

            # Display the completed canvas on Inky wHAT

    inky_display.set_image(img)
    inky_display.show()
    print(message)
Exemple #14
0
api_key = "<your API key>"
if (api_key == "<your API key>"):
    print("You forgot to enter your API key")
    exit()
lat = "52.988040"
lon = "8.866697"
url = "https://api.openweathermap.org/data/2.5/onecall?lat=%s&lon=%s&exclude=hourly&appid=%s&units=metric" % (
    lat, lon, api_key)

tile_positions = []
for i in range(2):
    for j in range(4):
        tile_positions.append((j * TILE_WIDTH, i * TILE_HEIGHT))

inky_display = InkyWHAT("red")
inky_display.set_border(inky_display.RED)

font = ImageFont.truetype("fonts/BungeeColor-Regular_colr_Windows.ttf",
                          FONT_SIZE)

old_days = []

while (True):
    try:
        response = requests.get(url)
        data = json.loads(response.text)
    except:
        None

    days = []
    daily = data["daily"]
Exemple #15
0
def update_inky():
    raw = get_today()
    data = build_today(raw)
    print(data)

    # INIT
    # ====
    inky = InkyWHAT("yellow")
    inky.set_border(inky.BLACK)

    # initiate image
    img = Image.new("P", (inky.WIDTH, inky.HEIGHT))
    draw = ImageDraw.Draw(img)

    # HEADER
    # ======

    # add name
    x = "WFH"
    font = build_font(20)
    w, h = get_font_size(font, x)
    draw.text((X_EDGE, Y_EDGE), x, inky.YELLOW, font)

    # add date
    now = data["now"]
    date_str = now.strftime("%d.%m.%Y")
    wd, _ = get_font_size(font, date_str)
    time_str = now.strftime("%H:%M")
    wt, _ = get_font_size(font, time_str)

    draw.text((inky.WIDTH - wt - wd - X_EDGE, Y_EDGE), date_str, inky.BLACK,
              font)
    draw.text((inky.WIDTH - wt, Y_EDGE), time_str, inky.YELLOW, font)

    # add divider
    HEADER_HEIGHT = h + Y_EDGE
    draw.line(
        (X_EDGE, HEADER_HEIGHT + 2, inky.WIDTH - X_EDGE, HEADER_HEIGHT + 2),
        fill=inky.BLACK,
        width=DIVIDER_HEIGHT)

    # FOOTER
    # ======
    TIME_END = inky.WIDTH - 2 * X_EDGE
    dx = (TIME_END - X_LABEL) // len(TIMES)

    x = X_LABEL + X_EDGE
    y = inky.HEIGHT - ICON_SIZE * 1.5

    # determine absolute start/end time (for referencing)
    TIME_START = x + (dx + ICON_SIZE) // 2
    TIME_END -= ICON_SIZE // 2 - X_EDGE

    # add ENTIRE time bar
    draw.line((TIME_START, y, TIME_END, y),
              fill=inky.BLACK,
              width=DIVIDER_HEIGHT)

    # add icons
    for k, v in TIMES.items():
        icon = load_image(v, ICON_SIZE)

        # add icons
        img.paste(icon,
                  box=(x + dx // 2, inky.HEIGHT - ICON_SIZE - 2 * Y_EDGE))

        # add MAJOR time ticks
        draw.line((x + (dx + ICON_SIZE) // 2, y + TICK_HEIGHT, x +
                   (dx + ICON_SIZE) // 2, y - TICK_HEIGHT),
                  fill=inky.BLACK,
                  width=int(1.25 * DIVIDER_HEIGHT))
        # add MINOR time ticks
        draw.line((x + dx + ICON_SIZE // 2, y + TICK_HEIGHT,
                   x + dx + ICON_SIZE // 2, y - TICK_HEIGHT),
                  fill=inky.BLACK,
                  width=int(0.75 * DIVIDER_HEIGHT))
        x += dx

    now_px = _convert_time(data["now"], TIME_START, TIME_END)
    draw.line((now_px, y + TICK_HEIGHT, now_px, y - TICK_HEIGHT),
              fill=inky.YELLOW,
              width=int(1.25 * DIVIDER_HEIGHT))

    # WORK
    # ====

    Y = 60

    # add label
    label = "Work"
    font = build_font(30)
    w, h = get_font_size(font, label[0])
    draw.text((X_EDGE + w, Y - h // 2), label[1:], inky.BLACK, font)
    draw.text((X_EDGE, Y - h // 2), label[0], inky.YELLOW, font)

    # fix logoff if not existing
    if len(data["login"]) != len(data["logoff"]):
        data["logoff"].append(data["now"])
    working_times = list(zip(data["login"], data["logoff"]))

    total_sec = 0
    font = build_font(18)
    for working_time in working_times:
        # start
        start_px = _convert_time(working_time[0], TIME_START, TIME_END)
        start_str = working_time[0].strftime("%H:%M")
        draw.text((start_px, Y + 4), start_str, inky.BLACK, font)

        # end
        stop_px = _convert_time(working_time[1], TIME_START, TIME_END)
        if (stop_px - start_px) > 100:
            stop_str = working_time[1].strftime("%H:%M")
            w, h = get_font_size(font, stop_str)
            draw.text((stop_px - int(0.75 * w), Y + 4), stop_str, inky.BLACK,
                      font)

        # total
        total_sec += (working_time[1] - working_time[0]).total_seconds()

        # add time bar for working time
        draw.line((start_px, Y, stop_px, Y),
                  fill=inky.YELLOW,
                  width=3 * DIVIDER_HEIGHT)

    # write total work time
    total_str = "Σ {:.2f} hr".format(total_sec / 3600)
    font = build_font(25)
    w, h = get_font_size(font, total_str)
    draw.text((inky.WIDTH - w - X_EDGE, HEADER_HEIGHT + 5), total_str,
              inky.YELLOW, font)

    # FOOD
    # ====

    Y = 128

    # add label
    label = "Food"
    font = build_font(30)
    w, h = get_font_size(font, label[0])
    draw.text((2 * X_EDGE + w // 3, Y - h // 2), label[1:], inky.BLACK, font)
    draw.text((X_EDGE, Y - h // 2), label[0], inky.YELLOW, font)

    # add lunch icon
    if data["lunch"]:
        icon = load_image(ICONS["lunch"], int(ICON_SIZE * .75))
        lunch_px = _convert_time(data["lunch"][0], TIME_START,
                                 TIME_END)  # ASSUME SINGLE LUNCH
        img.paste(icon, box=(lunch_px, Y - ICON_SIZE))

    # add coffee icons
    for coffee in data["coffee"]:
        icon = load_image(ICONS["coffee"], ICON_SIZE)
        coffee_px = _convert_time(coffee, TIME_START, TIME_END)
        img.paste(icon, box=(coffee_px - ICON_SIZE // 2, Y + ICON_SIZE // 3))

    # HEALTH
    # ======

    Y = 205

    # add label
    label = "Health"
    font = build_font(30)
    w, h = get_font_size(font, label[0])
    draw.text((X_EDGE + w, Y - h // 2), label[1:], inky.BLACK, font)
    draw.text((X_EDGE, Y - h // 2), label[0], inky.YELLOW, font)

    # add pushup icons
    for pushups in data["pushups"]:
        icon = load_image(ICONS["pushups"], ICON_SIZE)
        pushups_px = _convert_time(pushups, TIME_START, TIME_END)
        img.paste(icon, box=(pushups_px - ICON_SIZE // 2, Y - ICON_SIZE))

    # add move icons
    for move in data["move"]:
        icon = load_image(ICONS["move"], ICON_SIZE)
        move_px = _convert_time(move, TIME_START, TIME_END)
        img.paste(icon, box=(move_px - ICON_SIZE // 2, Y + ICON_SIZE // 3))

    # set image to inky
    inky.set_image(img)
    inky.show()
Exemple #16
0
def changeScreens(cardID):
    """Changes the screen shown on the Raspberry Pi Hat.

    Checks to see if the card is in the database and displays
    the corresponding screen.

    We are using the inkywHAT Red/Black/White:
    https://shop.pimoroni.com/products/inky-what?variant=13590497624147 

    Documentation:
    https://github.com/pimoroni/inky 

    TODO: Change the screen back to "please scan card" after a set amount of time has passed. 
    Needs some multithreading or something to accomplish that I think.
    """
    
    ######## Pi Hat Setup ########
    print("Changing screens...")

    inkywhat = InkyWHAT('black')
    
    # Establish a new connection for checking if the card is in the DB.
    # Not sure if this is required, but this is the easiest way I could find to do it.
    # Copy-pasted from the earlier mqtt_connection variable.
    pi_hat_connection = mqtt_connection_builder.mtls_from_path(
        endpoint=args.endpoint,
        cert_filepath=args.cert,
        pri_key_filepath=args.key,
        client_bootstrap=client_bootstrap,
        ca_filepath=args.root_ca,
        client_id=args.client_id,
        clean_session=False, 
        keep_alive_secs=6)

    # Query the DB to see if that card is in it.
    # Use the config defined at the top of the file to hide connection information.
    cardInDBResult = False
    try:
        mysqlConn = mysql.connector.connect(host=config['database']['dbHostname'],
                                            database=config['database']['dbName'],
                                            user=config['database']['dbUsername'],
                                            password=config['database']['dbPassword'])
        if mysqlConn.is_connected():
            print("Connected to database...")
            cursor = mysqlConn.cursor()
            cursor.execute("select database();")
            record = cursor.fetchone()
            lookForCardQuery = "SELECT * FROM Student_ID WHERE SID = " + str(cardID)
            cursor.execute(lookForCardQuery)
            records = cursor.fetchall()
            if(cursor.rowcount > 0):
                cardInDBResult = True
    except Error as e:
        print("Error while connecting to MySQL Database", e)
    finally:
        if (mysqlConn.is_connected()):
            cursor.close()
            mysqlConn.close()
            print("Disconnected from database...")

    # If the card is in the database, set the screen to be shown to the "Welcome" screen
    if (cardInDBResult):
        print("ID Found - Displaying Welcome...")
        imgURL = "../../../qrcode/displayScreens/welcome_bw.png"
        im = Image.open(imgURL)

        # Resizing the image so it fits to the screen
        # This is specific to the inkywhat, otherwise it claims that there is a size-mismatch.
        size = (400,300)
        out = im.resize(size)
        out.save('../../../qrcode/resize-output.png')
        img = Image.open('../../../qrcode/resize-output.png')
        pal_img = Image.new("P", (1, 1))
        pal_img.putpalette((255, 255, 255, 0, 0, 0, 255, 0, 0) + (0, 0, 0) * 252)
        img = img.convert("RGB").quantize(palette=pal_img)
        
    # If the card is not in the database, make a QR code and show the "QR Code" screen
    elif (not cardInDBResult):
        print("ID Not Found - Displaying Registration...")
        imgURL = "../../../qrcode/displayScreens/qrscan_bw.png"
        displayURL = "../../../qrcode/qrCodeScreenMerged.png"

        # Generate a QR Code Object
        qr = qrcode.QRCode(
            version=None,
            error_correction=qrcode.constants.ERROR_CORRECT_L,
            box_size=3,
            border=2,
        )

        # Generate the URL the code points to and add it to the QR Code
        wURL = config['aws_endpoints']['registrationSite'] + str(cardID)
        qr.add_data(wURL)
        qr.make(fit=True)
        img = qr.make_image(fill_color="black", back_color="white")

        # Save the generated QR Code to the proper folder
        img.save('../../../qrcode/qr_image.png')
        im = Image.open(imgURL)

        # Resizing the image so it fits to the screen
        size = (400,300)
        out = im.resize(size)
        out.save('../../../qrcode/resize-output.png')

        # We are using ImageMagick installed on the Raspberry Pi to 
        # composite our generated QR Code onto the premade image
        # with this subprocess call. This could be changed to a 
        # bash script called in the same way.
        s = pyshorteners.Shortener(Shorteners.TINYURL)
        shortLink = s.short(wURL)
        composeQRCodeOntoImageCommand = 'composite -blend 100 -gravity center ../../../qrcode/qr_image.png ../../../qrcode/resize-output.png ../../../qrcode/qrCodeScreenMerged.png'
        composeURLOntoImageCommand = 'convert ../../../qrcode/qrCodeScreenMerged.png -gravity North -pointsize 24 -annotate +0+215 \'' + shortLink + '\' ../../../qrcode/qrCodeScreenMerged.png'
        subprocess.call(composeQRCodeOntoImageCommand, shell=True)
        subprocess.call(composeURLOntoImageCommand, shell=True)

        img = Image.open(displayURL)

        # Continue resizing, inkywhat complains otherwise.
        pal_img = Image.new("P", (1, 1))
        pal_img.putpalette((255, 255, 255, 0, 0, 0, 255, 0, 0) + (0, 0, 0) * 252) 
        img = img.convert("RGB").quantize(palette=pal_img)

    # Update the image on the screen and show it.
    inkywhat.set_image(img)
    inkywhat.set_border('white')
    inkywhat.show()
    print("Finished changing screens...")