Esempio n. 1
0
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
Esempio n. 2
0
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()
Esempio n. 3
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()
Esempio n. 4
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!")
Esempio n. 5
0
def main():
    # Initialize Inky wHAT display
    inky_display = InkyWHAT('black')

    # Download image and save locally
    img_data = requests.get(image_url).content
    with open(img_file, 'wb') as handler:
        handler.write(img_data)

    # Open downloaded image
    img = Image.open(img_file)

    # Dither downloaded image
    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)

    # Display dithered image
    inky_display.set_image(img)
    inky_display.show()
Esempio n. 6
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()
Esempio n. 7
0
	parser.add_argument('--longitude', '-L', type=str, required=True, help="Longitude of the location")
	args = parser.parse_args()

	res = get_weather(args.latitude, args.longitude, args.dskey)
	#print(json.dumps(res, indent=2))

	colour = args.colour
	inky_display = InkyWHAT(colour)
	for icon in glob.glob(os.path.join(PATH, "weather_resources/icon-*.png")):
		icon_name = icon.split("icon-")[1].replace(".png", "")
		icon_image = Image.open(icon)
		icons[icon_name] = icon_image
		masks[icon_name] = create_mask(icon_image, (inky_display.WHITE, inky_display.BLACK, inky_display.RED))

	img = Image.new("P", (inky_display.WIDTH, inky_display.HEIGHT), inky_display.WHITE)
	draw = ImageDraw.Draw(img)
	used_h = show_current_weather(draw, res['currently'], inky_display , 0)
	used_h = show_current_weather_icon(draw, img, res['currently'], inky_display, icons, masks, used_h)
	tile_w = int(inky_display.WIDTH / FORECARST_COLUMNS)
	tile_h = int(inky_display.HEIGHT - used_h)
	for i in range(FORECARST_COLUMNS):
		tile = Image.new("P", (tile_w, tile_h), inky_display.WHITE)
		tile_draw = ImageDraw.Draw(tile)
		draw_weather_tile(tile_draw, tile, res['daily']['data'][i], icons, masks, res['timezone'])
		img.paste(tile, (i * tile_w, used_h))
	font = ImageFont.truetype(FredokaOne, SMALL_FONT_SIZE)
	timestamp = f'Data loaded at {datetime.now(pytz.timezone(res["timezone"])).strftime("%H:%M:%S %d %b %Y")}'
	draw.text((8, inky_display.HEIGHT - SMALL_FONT_SIZE), timestamp, inky_display.RED, font=font)
	inky_display.set_image(img.rotate(180))
	inky_display.show()
Esempio n. 8
0
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from inky import InkyWHAT
from PIL import Image, ImageFont, ImageDraw
import sys

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

img = Image.new("L", (300, 400))
draw = ImageDraw.Draw(img)

font = ImageFont.load("tom-thumb.pil")

texty = 0

for i in range(4):
    draw.text((6, texty), sys.stdin.readline(), inky_display.RED, font)
    texty = (texty + 6)

for line in sys.stdin:
    draw.text((6, texty), line, inky_display.BLACK, font)
    texty = (texty + 6)

inky_display.set_image(img.rotate(270, expand=True))
inky_display.show()
Esempio n. 9
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()
Esempio n. 10
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()
Esempio n. 11
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...")
Esempio n. 12
0
now = datetime.datetime.now()
tweet_update = "Updated: " + now.strftime("%d %b %H:%M")

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:
Esempio n. 13
0
from inky import InkyWHAT
from PIL import Image
import sys

inkywhat = InkyWHAT('red')

#img = Image.open("InkywHAT-400x300.png")
img = Image.open("keystrokes_bw.png")

inkywhat.set_image(img)

inkywhat.show()



Esempio n. 14
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)
Esempio n. 15
0
        break

while len(splutForecast) > 0:
    theWord = splutForecast.pop()
    before = forecastL2
    forecastL2 = forecastL2 + ' ' + theWord
    w, h = titleFont.getsize(forecastL2)
    if w > panelWidth:
        splutForecast.append(theWord)
        forecastL2 = before
        break

while len(splutForecast) > 0:
    theWord = splutForecast.pop()
    before = forecastL3
    forecastL3 = forecastL3 + ' ' + theWord
    w, h = titleFont.getsize(forecastL3)
    if w > panelWidth:
        splutForecast.append(theWord)
        forecastL3 = before
        break

draw.text((12, 38), forecastL1, inkR.BLACK, font)
draw.text((12, 50), forecastL2, inkR.BLACK, font)
draw.text((12, 62), forecastL3, inkR.BLACK, font)
draw.text((12, 74), ' Temperature: ' +  str(forecast.currently.temperature) + '°f', inkR.BLACK, font)
draw.text((12, 86), ' High: ' + str(forecast.daily.data[0].temperature_high) + '°f  Low: ' + str(forecast.daily.data[0].temperature_low) + '°f', inkR.BLACK, font)

inkR.set_image(im)
inkR.show()
Esempio n. 16
0
def get_ip_address():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.connect(("8.8.8.8", 80))
    return s.getsockname()[0]


stream = io.BytesIO()

with PiCamera() as camera:
    camera.resolution = (1024, 768)
    #camera.start_preview()
    time.sleep(2)
    camera.capture(stream, format='jpeg')
#camera.start_preview()
# Camera warm-up time
stream.seek(0)
image = Image.open(stream)

inkywhat = InkyWHAT('red')

inkywhat.set_image(image.resize([400, 300]).convert('P'))
inkywhat.show()
imgByteArr = io.BytesIO()
image.resize([400, 300]).convert('P').save(imgByteArr, format='PNG')
alert("Doctest",
      title=f"IP: {get_ip_address()}",
      sound="magic",
      attachment=imgByteArr.getvalue(),
      url_title="School 4 One Link")
Esempio n. 17
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()
Esempio n. 18
0
        right = previousCells[rightIndex]
        rightRule = 0
        if right >= 1:
            rightRule = 1

        result = ruleset[int("%s%s%s" % (leftRule, middleRule, rightRule), 2)]

        cells[cell] = result

    if generation >= visibleGenerations:
        newImg = img.transform(img.size, Image.AFFINE, (1, 0, 0, 0, 1, cellSize))
        img.close()
        img = newImg
        draw = ImageDraw.Draw(img)

    y = min(generation, (visibleGenerations - 1)) * cellSize

    for cell in range(0, numCells):

        x = cell * cellSize

        if cells[cell] == 1:
            draw.rectangle([(x, y), (x + rectSize, y + rectSize)], fill='black')
        elif cells[cell] == 2:
            draw.rectangle([(x, y), (x + rectSize, y + rectSize)], fill='red')
        else:
            draw.rectangle([(x, y), (x + rectSize, y + rectSize)], fill='white')

inky_display.set_image(img)
inky_display.show()
Esempio n. 19
0
def main():
    first_day = pd.to_datetime('2020-1-20')  # first case in US

    print('Pulling infection histories')
    iowa = get_infection_history("https://api.covidtracking.com/v1/states/ia/daily.csv")
    us = get_infection_history("https://api.covidtracking.com/v1/us/daily.csv")
    print('Received infection histories')

    print('Pulling vaccination histories')
    # "Immune" is a little iffy here. i assume if someone had covid they are immune. i also assume that if a person
    # received one shot they are 80% immune, and 95% with two
    us_vacc, iowa_vacc, us_immune = get_number_vaccinations("https://www.nytimes.com/interactive/2020/us/covid-19-vaccine-doses.html")
    us_vacc_per_100 = 100 * us_vacc / us_pop
    iowa_vacc_per_100 = 100 * iowa_vacc / iowa_pop

    print('Received vaccination histories')

    latest_date = iowa['date'][0]

    iowa_death_average = int(iowa['deathRollingSeven'].iloc[0])
    us_death_average = int(us['deathRollingSeven'].iloc[0])
    iowa_positive_average = int(iowa['positiveRollingSeven'].iloc[0])
    us_positive_average = int(us['positiveRollingSeven'].iloc[0])

    # CDC estimates that about 1 in 4 cases of COVID have been caught by tests
    # https://www.cdc.gov/coronavirus/2019-ncov/cases-updates/burden.html
    us_immune += us['positive'].iloc[0] * 4

    # Set Inky Display stuff
    print('Initializing inky display')
    display = InkyWHAT(colour='red')
    img = Image.new("P", (display.WIDTH, display.HEIGHT))
    draw = ImageDraw.Draw(img)
    lrg_font, med_font, sml_font = ImageFont.truetype(FredokaOne, 26), ImageFont.truetype(FredokaOne, 22), ImageFont.truetype(FredokaOne, 16)
    left_pad = 3
    middle = display.WIDTH / 2
    header_y = 45
    y_cursor = header_y + 3
    max_line_length = 190
    extra_y_spacer = 3

    # header and section lines
    draw.text((left_pad, 5), f" {latest_date.strftime('%b %d')}           Day {(latest_date - first_day).days:,d}"
                             f" of COVID", display.BLACK, lrg_font)
    draw.line((left_pad, header_y, display.WIDTH - left_pad, header_y),
              fill=display.BLACK, width=3)
    draw.line((left_pad, header_y + (InkyWHAT.HEIGHT - header_y) / 3,
               display.WIDTH - left_pad, header_y + (InkyWHAT.HEIGHT - header_y) / 3),
              fill=display.BLACK, width=3)
    draw.line((left_pad, header_y + 2 * (InkyWHAT.HEIGHT - header_y) / 3,
               display.WIDTH - left_pad, header_y + 2 * (InkyWHAT.HEIGHT - header_y) / 3),
              fill=display.BLACK, width=3)
    draw.line((middle, header_y, middle, display.HEIGHT),
              fill=display.BLACK, width=3)

    # new deaths
    draw.text((get_centered_x('New Deaths', sml_font), y_cursor), 'New Deaths', display.RED, sml_font)
    y_cursor += sml_font.getsize('New Deaths')[1] + 5
    new_deaths_txt = f"IA: {iowa['deathIncrease'][0]:,d} | US: {us['deathIncrease'][0]:,d}"
    draw.text((get_centered_x(new_deaths_txt, med_font), y_cursor), new_deaths_txt, display.BLACK, med_font)
    y_cursor += med_font.getsize(new_deaths_txt)[1] + extra_y_spacer
    rolling_deaths_txt = f"Avg IA: {iowa_death_average:,d} | US: {us_death_average:,d}"
    rolling_deaths_font = ImageFont.truetype(FredokaOne, max_font_size(rolling_deaths_txt, max_line_length))
    draw.text((get_centered_x(rolling_deaths_txt, rolling_deaths_font), y_cursor),
              rolling_deaths_txt, display.BLACK, rolling_deaths_font)
    y_cursor = header_y + (InkyWHAT.HEIGHT - header_y) / 3 + 3  # reset cursor to beginning of col 1 row 2

    # new infections
    draw.text((get_centered_x('New Infections', sml_font), y_cursor), 'New Infections', display.RED, sml_font)
    y_cursor += sml_font.getsize('New Infections')[1] + 5
    new_positive_txt = f"IA: {iowa['positiveIncrease'][0]:,d} | US: {us['positiveIncrease'][0]:,d}"
    new_positive_font = ImageFont.truetype(FredokaOne, max_font_size(new_positive_txt, max_line_length))
    draw.text((get_centered_x(new_positive_txt, new_positive_font), y_cursor), new_positive_txt, display.BLACK,
              new_positive_font)
    y_cursor += med_font.getsize(new_positive_txt)[1] + extra_y_spacer
    rolling_positive_txt = f"Avg IA: {iowa_positive_average:,d} | US: {us_positive_average:,d}"
    rolling_positive_font = ImageFont.truetype(FredokaOne, max_font_size(rolling_positive_txt, max_line_length))
    draw.text((get_centered_x(rolling_positive_txt, rolling_positive_font), y_cursor), rolling_positive_txt,
              display.BLACK, rolling_positive_font)
    y_cursor = header_y + 2 * (InkyWHAT.HEIGHT - header_y) / 3 + 3  # reset cursor to beginning of col 1 row 2

    # positive test rate
    draw.text((get_centered_x('Positive Test Rate', sml_font), y_cursor), 'Positive Test Rate', display.RED, sml_font)
    y_cursor += sml_font.getsize('Positive Test Rate')[1] + 5

    # positive test rate numbers
    ptr_txt = f"IA: {100 * iowa['positiveTestRate'].iloc[0]:.1f}% | US: {100 * us['positiveTestRate'].iloc[0]:.1f}%"
    ptr_font = ImageFont.truetype(FredokaOne, max_font_size(ptr_txt, max_line_length))
    draw.text((get_centered_x(ptr_txt, ptr_font), y_cursor), ptr_txt, display.BLACK, ptr_font)
    y_cursor += med_font.getsize(ptr_txt)[1] + extra_y_spacer
    rolling_positive_txt = f"LW IA: {100 * iowa['positiveTestRate'].iloc[7]:.1f}% | " \
                           f"US: {100 * us['positiveTestRate'].iloc[7]:.1f}%"
    rolling_positive_font = ImageFont.truetype(FredokaOne, max_font_size(rolling_positive_txt, max_line_length))
    draw.text((get_centered_x(rolling_positive_txt, rolling_positive_font), y_cursor), rolling_positive_txt,
              display.BLACK, rolling_positive_font)

    # % dead
    y_cursor = header_y + 3
    draw.text((get_centered_x('US Percent Dead', sml_font, 'third'), y_cursor), 'US Percent Dead', display.RED, sml_font)
    y_cursor += sml_font.getsize('US Percent Dead')[1] + 10
    death_pct_text = f'{100 * us["death"].iloc[0] / us_pop:.4f}%'
    death_pct_font = ImageFont.truetype(FredokaOne, max_font_size(death_pct_text, max_line_length))
    draw.text((get_centered_x(death_pct_text, death_pct_font, 'third'), y_cursor), death_pct_text, display.BLACK, death_pct_font)
    y_cursor = header_y + (InkyWHAT.HEIGHT - header_y) / 3 + 3  # reset cursor to beginning of col 1 row 3

    # immunity
    draw.text((get_centered_x('US Percent Vaccinated', sml_font, 'third'), y_cursor), 'US Percent Vaccinated', display.RED, sml_font)
    y_cursor += sml_font.getsize('US Percent Vaccinated')[1] + 10
    immune_text = f'{100 * us_vacc / us_pop:.2f}%'  # have to subtract dead from immune :(
    immune_font = ImageFont.truetype(FredokaOne, max_font_size(immune_text, max_line_length))
    draw.text((get_centered_x(immune_text, immune_font, 'third'), y_cursor), immune_text, display.BLACK, immune_font)
    y_cursor = header_y + 2 * (InkyWHAT.HEIGHT - header_y) / 3 + 3  # reset cursor to beginning of col 1 row 3

    # num vaccinated
    draw.text((get_centered_x('People Vaccinated', sml_font, 'third'), y_cursor), 'People Vaccinated', display.RED, sml_font)
    y_cursor += sml_font.getsize('People Vaccinated')[1] + 3
    total_vacc_txt = f'US: {int(us_vacc):,d}'
    total_vacc_font = ImageFont.truetype(FredokaOne, max_font_size(total_vacc_txt, max_line_length, upper_lim=20))
    draw.text((get_centered_x(total_vacc_txt, total_vacc_font, 'third'), y_cursor), total_vacc_txt, display.BLACK, total_vacc_font)
    y_cursor += sml_font.getsize('Vaccination')[1] + 10

    # vacc per hundred
    vacc_per_hundred_txt = f'IA: {iowa_vacc_per_100:.1f}% | {iowa_vacc / 1_000_000:.3f}M'
    vacc_per_hundred_font = ImageFont.truetype(FredokaOne, max_font_size(vacc_per_hundred_txt, max_line_length, upper_lim=20))
    draw.text((get_centered_x(vacc_per_hundred_txt, vacc_per_hundred_font, 'third'), y_cursor), vacc_per_hundred_txt,
              display.BLACK, vacc_per_hundred_font)

    # update display
    display.set_image(img)
    print('Updating display')
    display.show()
    print('Display updated')
Esempio n. 20
0
            pixels[x, y] = (256, 256, 256)
    return canvas


def assemble_canvas(org, tweet, pomodoro, inky_display):
    canvas = Image.new("P", (inky_display.WIDTH, inky_display.HEIGHT))
    # insert org
    canvas.paste(org, (0, 0))  # no offset
    # insert tweet
    canvas.paste(tweet, (org.width, 0))
    # insert pomodoro
    canvas.paste(tomato, (org.width, inky_display.HEIGHT - tomato.size[1]))
    return canvas


# Generate org file image

org_accomplishments = Image.open('./org.png')
ow, oh = org_accomplishments.size
tomato = Image.open('./assets/tomato_3.png')
tw, th = tomato.size
rem_w = inky_display.WIDTH - ow
rem_h = inky_display.HEIGHT - th
tweet = get_recent_care_tweet()
tweet_img = get_text_image(tweet, rem_w, rem_h)
org_img = org_accomplishments
canvas = assemble_canvas(org_img, tweet_img, tomato, inky_display)
# canvas.show()
inky_display.set_image(canvas)
inky_display.show()
Esempio n. 21
0
def main(forecast, latlong, bg_file, bg_map, zoom, show_on_inky, inky_colour,
         show_image, save_image, banner, location_banner, verbose):

    import os
    import datetime

    #choose and format data for image display

    #don't use temperature_high_time= forecast.daily.data[0].temperature_high_time
    #because high for the next day would appear after midnight
    #and I wanted to see the low at 7am (or whenever it was still coming)
    high = max(forecast.hourly.data[:24], key=lambda x: x.temperature)
    low = min(forecast.hourly.data[:24], key=lambda x: x.temperature)

    #daily[0] = TODAY
    sunrise_time = forecast.daily.data[0].sunrise_time
    sunset_time = forecast.daily.data[0].sunset_time

    temperature_msg = str(round(forecast.currently.temperature)) + "°"

    #hi/lo

    if (
            low.time < high.time
    ) and low.time - forecast.currently.time > datetime.timedelta(
            hours=1
    ):  # and (low.time- forecast.currently.time).seconds > datetime.timedelta(hours= 1).seconds:
        high_next = False
        hi_lo_msg = "low {}°\n{}".format(str(round(low.temperature)),
                                         low.time.strftime("%H:%M"))

    else:
        #high time is next
        high_next = True
        hi_lo_msg = "high {}°\n{}".format(str(round(high.temperature)),
                                          high.time.strftime("%H:%M"))

    #sunrise/sunset time
    try:
        if (sunrise_time < forecast.currently.time < sunset_time):
            #it's day time
            sun_msg = "sunset\n{}".format(sunset_time.strftime("%H:%M"))
            summary = forecast.hourly.summary.rstrip(".")

        else:
            # night time
            sun_msg = "sunrise\n{}".format(sunrise_time.strftime("%H:%M"))
            summary = forecast.daily.summary.rstrip(".")
    except:
        #We're at the North pole and there's no sunset
        sun_msg = ""
        summary = forecast.hourly.summary.rstrip(".")

    #replace summary with soonest alert
    alerts = forecast.alerts
    if alerts:
        min_alert = min(alerts, key=lambda x: x.time)
        alert = "{}: {}".format(min_alert.time.strftime("%A %H:%M"),
                                min_alert.title)
    else:
        alert = None

    if alert:
        summary = alert  #replace summary with alert

    #here is where you could do a check to see if the screen needs updating-
    #save old version and if new != old, update

    # create display image

    # Set up the correct display and scaling factors
    try:
        w, h, ink_black, ink_color = setup_inky(inky_colour)
    except:
        #go_to_screen= True# ...get screen size?
        w, h, ink_black, ink_color = setup_screen()

    #setup canvas
    try:
        if bg_file:

            #user has specified a background
            if os.path.isfile(bg_file):
                #load image from absolute file path or file path relative to their location
                img = Image.open(bg_file)

            elif os.path.isfile(
                    os.path.join(os.path.dirname(__file__), bg_file)):
                #load file relative to this script
                img = Image.open(
                    os.path.join(os.path.dirname(__file__), bg_file))

            elif os.path.isdir(bg_file):
                #choose icon from named structure within folder
                #the dirs are icon names
                basedir = os.path.join(bg_file, forecast.currently.icon)
                if os.path.isdir(basedir):
                    img = choose_bg_from_folder(basedir)

                else:
                    #choose random bg from folder
                    img = choose_bg_from_folder(bg_file)

            elif os.path.isdir(os.path.join(os.path.dirname(__file__),
                                            bg_file)):
                #choose icon from named structure within folder
                #the dirs are icon names
                basedir = os.path.join(
                    os.path.join(os.path.dirname(__file__), bg_file),
                    forecast.currently.icon)
                if os.path.isdir(basedir):
                    img = choose_bg_from_folder(basedir)

                else:
                    #choose random bg from folder
                    img = choose_bg_from_folder(
                        os.path.join(os.path.dirname(__file__), bg_file))

            else:
                print(
                    "Can't load \n{}\n as background. Please specify a directory or filename. Try using an absolute path?"
                    .format(os.path.abspath(bg_file)))

            img = remove_transparency(img)
            img = resize_fill(img, w, h)

        elif bg_map:
            #load map image
            img = load_map(latlong)
            img = resize_distort(img, w, h)
        elif zoom:
            #load zoomed map image
            img = load_map_zoom(latlong)

        else:
            #choose from default icon list
            basedir = os.path.join(os.path.dirname(__file__), 'icons',
                                   'default', forecast.currently.icon)
            img = choose_bg_from_folder(basedir)
            img = resize_fill(img, w, h)

    except Exception as e:
        print(e, ": using blank background.")

        #blank bg
        img = Image.new("RGB", (w, h), color=(255, 255, 255))

    #add soft white top and bottom
    softshadow = Image.new("RGBA", (w, h), color=(255, 255, 255, 255))
    draw = ImageDraw.Draw(softshadow)
    draw.rectangle((0, 10, w, h - 50), fill=(0, 0, 0, 0))

    #strongshadow= bg.filter(ImageFilter.GaussianBlur(25))

    softshadow = softshadow.filter(ImageFilter.GaussianBlur(50))
    img.paste("white", mask=softshadow)
    img.convert("RGB")

    draw = ImageDraw.Draw(img)

    # messages at top of screen: banner, location_banner, forecast time

    top_line = 0
    # banner
    if banner:
        img = write_in_box(img,
                           0,
                           0,
                           400,
                           40,
                           banner,
                           20,
                           summary_font_loader(20),
                           fill=(0, 0, 0, 255),
                           spacing=0,
                           align_x="center",
                           align_y="top")
        top_line += 25
    # location_banner
    if location_banner:
        img = write_in_box(img,
                           0,
                           top_line,
                           400,
                           40 + top_line,
                           location_banner,
                           20,
                           summary_font_loader(20),
                           fill=(0, 0, 0, 255),
                           spacing=0,
                           align_x="center",
                           align_y="top")
        top_line += 25

    # forecast time
    img = write_in_box(img,
                       0,
                       top_line,
                       400,
                       40 + top_line,
                       forecast.currently.time.strftime("%A %d %b %Y"),
                       20,
                       summary_font_loader(20),
                       fill=(0, 0, 0, 255),
                       spacing=0,
                       align_x="center",
                       align_y="top")

    #current temperature
    x0, y0, x1, y1 = text_box2(img,
                               0,
                               0,
                               w,
                               h - 90,
                               temperature_msg,
                               int(50 * 2.2),
                               temperature_font_loader(int(50 * 2.2)),
                               fill=(255, 255, 0, 255),
                               spacing=0,
                               align_x="center",
                               align_y="center")

    temperature_y = (y1 - y0) / 2

    #HI/Lo on LHS MIDDLE
    padding = 50
    max_width = w - padding
    max_height = 250
    font_size = 24
    below_max_length = False
    scale_adjust = 1
    msg = hi_lo_msg

    while not below_max_length:
        summary_font = summary_font_loader(font_size * scale_adjust)
        reflowed = reflow_summary(msg, max_width, summary_font)
        p_w, p_h = summary_font.getsize(
            reflowed)  # Width and height of summary
        p_h = p_h * (reflowed.count("\n") + 1
                     )  # Multiply through by number of lines

        if p_h < max_height:
            below_max_length = True  # The summary fits! Break out of the loop.
        else:
            # scale down text to fit
            scale_adjust *= .95

    # x- and y-coordinates for the top left of the summary
    summary_x = 5  #do i need to check for the longest linw and get size of that?
    summary_y = temperature_y + 48

    #draw it now
    bg = Image.new("RGBA", img.size, color=(0, 0, 0, 0))

    draw = ImageDraw.Draw(bg)

    if mean_of_area(img, summary_x, summary_y, summary_x + p_w,
                    summary_y + p_h) > .5 * 255:
        #area is white, use black text and white shadow
        fill = (0, 0, 0, 255)
        shadowfill = (255, 255, 255)
    else:
        fill = (255, 255, 255, 255)
        shadowfill = (0, 0, 0)

    draw.multiline_text((summary_x, summary_y),
                        reflowed,
                        fill=fill,
                        font=summary_font,
                        align="left")

    strongshadow = bg.filter(ImageFilter.GaussianBlur(25))

    softshadow = bg.filter(ImageFilter.GaussianBlur(50))
    img.paste(shadowfill, mask=softshadow)
    img.convert("RGB")
    img.paste(shadowfill, mask=strongshadow)
    img.convert("RGB")
    img.paste(bg, mask=bg)
    img.convert("RGB")

    draw = ImageDraw.Draw(img)

    #sunrise/sunset on RHS MIDDLE
    padding = 0
    max_width = w - padding
    max_height = 250
    font_size = 24
    below_max_length = False
    scale_adjust = 1
    msg = sun_msg

    if msg:
        while not below_max_length:
            summary_font = summary_font_loader(font_size * scale_adjust)
            reflowed = reflow_summary(msg, max_width, summary_font)
            p_w, p_h = max(
                (summary_font.getsize(line) for line in reflowed.splitlines()
                 ))  # Width and height of summary
            p_h = p_h * (reflowed.count("\n") + 1
                         )  # Multiply through by number of lines

            if p_h < max_height:
                below_max_length = True  # The summary fits! Break out of the loop.
            else:
                # scale down text to fit
                scale_adjust *= .95

        # x and y coordinates for the top left of the summary
        summary_x = w - p_w - 5
        summary_y = temperature_y + 48

        bg = Image.new("RGBA", img.size, color=(0, 0, 0, 0))

        draw = ImageDraw.Draw(bg)
        #print (mean_of_area(img, summary_x, summary_y, summary_x+ p_w, summary_y+ p_h))
        if mean_of_area(img, summary_x, summary_y, summary_x + p_w,
                        summary_y + p_h) > .5 * 255:
            #area is white, use black text and white shadow
            fill = (0, 0, 0, 255)
            shadowfill = (255, 255, 255)
        else:
            fill = (255, 255, 255, 255)
            shadowfill = (0, 0, 0)
        draw.multiline_text((summary_x, summary_y),
                            reflowed,
                            fill=fill,
                            font=summary_font,
                            align="right")

        strongshadow = bg.filter(ImageFilter.GaussianBlur(25))
        softshadow = bg.filter(ImageFilter.GaussianBlur(50))

        img.paste(shadowfill, mask=softshadow)
        img.convert("RGB")
        img.paste(shadowfill, mask=strongshadow)
        img.convert("RGB")
        img.paste(bg, mask=bg)
        img.convert("RGB")

    #rain graphic / sun (UV) strength

    y0 = 0
    y1 = 130

    rain_img = Image.new("RGBA", (w, y1), color=(255, 255, 255, 0))
    draw = ImageDraw.Draw(rain_img)
    font = summary_font_loader(14)

    for i, hour in enumerate(forecast.hourly.data[:24]):
        t = hour.time.strftime("%H")
        p = int(hour.precip_probability * hour.precip_intensity *
                25500)  #should be x 255
        if verbose:
            print(hour.time.strftime("%A %d %b %Y %H:%M"),
                  hour.precip_probability, hour.precip_intensity)
            if p:
                print(hour.precip_type, p)
        x0 = int(w / 24 * i)
        x1 = int(w / 24 * (i + 1))
        #pcolor=255- p
        pcolor = int(hour.precip_probability * 255 *
                     .5)  #.5 is a fade factor - don't want bars too strong
        #tcolor=(pcolor+ 128)% 255
        tcolor = 0
        if p:  #>17:#>17 gives a value when inkied
            #amount and probability of rain
            #the /2 means scale london weather down to look good - your country may vary
            #rain_indicator
            draw.rectangle((x0, y1 - 16 - 1, x1 - 1, y1 - 16 - 3),
                           fill=(0, 0, 0, p))  #color), outline= (0, 0, 0, p))

            #rain bars
            draw.rectangle(
                (x0,
                 clamp(y0, y1 - (hour.precip_intensity / 2 *
                                 (y1 - y0)), y1 - 16), x1 - 1, y1 - 16),
                fill=(0, 0, 0, pcolor),
                outline=(0, 0, 0, 255))

        #UV rectangles
        if hour.uv_index:

            if hour.uv_index == 1:
                uv = int(255 * .025)
            elif hour.uv_index == 2:
                uv = int(255 * .05)
            elif hour.uv_index == 3:
                uv = int(255 * .075)
            else:
                uv = (hour.uv_index > 3) * 255
            draw.rectangle((x0, y1, x1 - 1, y1 - 16),
                           fill=(255, 255, 255, 255),
                           outline=(0, 0, 0, 255))
            draw.rectangle((x0, y1, x1 - 1, y1 - 16),
                           fill=(255, 255, 0, uv),
                           outline=(0, 0, 0, 255))

        draw.text((x0 + 2, y0 - 16 + y1),
                  str(t),
                  fill=(0, 0, 0, 255),
                  font=font,
                  align='center')  #added a plus one to look better lined up

        img.paste(rain_img, box=(0, 300 - y1), mask=rain_img)

    img.convert("RGB")

    #forecast hourly summary at bottom
    img = write_in_box(img,
                       0,
                       280 - 120,
                       400,
                       270,
                       summary,
                       20,
                       summary_font_loader(20),
                       fill=(0, 0, 0, 255),
                       spacing=0,
                       align_x="center",
                       align_y="bottom")

    #print(img.mode)

    if show_on_inky:
        #dither before saving or displaying
        img.convert("RGB")
        img = inky_dither(img)

    if save_image:
        img.convert("RGB")
        #save image
        img.save(save_image)
        print(save_image)

    if show_image:
        img.convert("RGB", 0)
        #show image
        img.show()

    # Display the completed canvas on Inky wHAT
    if show_on_inky:
        from inky import InkyWHAT
        inky_display = InkyWHAT(inky_colour)

        inky_display.set_image(img)
        #To Show upside down inky_display.set_image(img.rotate(180))

        inky_display.show()