fintic-tracker/stockTicker.py
2022-03-03 21:14:29 +08:00

2774 lines
115 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Copyright (C) 2020 Fintic, finticofficial@gmail.com
#
# This file is part of Fintic project, developed by Neythen Treloar and Justin Dunn
#
# stockTicker can not be copied and/or distributed without the express
# permission of Fintic
import sys, select
import os
import threading
from PIL import Image, ImageDraw, ImageFont, ImageSequence
Image.init()
import time
import csv
import requests
import pexpect
from rgbmatrix import RGBMatrix, RGBMatrixOptions
from rgbmatrix.graphics import *
from multiprocessing import Process
import traceback
import json
from datetime import datetime
import matplotlib.colors as mcolors
def getInput(Block=False):
if Block or select.select([sys.stdin], [], [], 0) == ([sys.stdin], [], []):
msg = sys.stdin.read(1)
#sys.stdin.flush()
else:
msg = ''
return msg
class StockTicker():
def __init__(self):
#Define global resources
self.symbols = []
self.delay = 0.02
self.greenORred = (255, 255, 255)
#self.blank = Image.open('logos/blank.png')
self.blank = Image.new('RGB', (10, 32))
self.running = True
settings = json.load(open('csv/general_settings.json', 'r'))
self.brightness = settings['brightness']*10
# Configuration for the matrix
options = RGBMatrixOptions()
options.rows = 32
options.cols = 64
options.chain_length = 2
options.parallel = 1
options.hardware_mapping = 'adafruit-hat' # If you have an Adafruit HAT: 'adafruit-hat'
options.gpio_slowdown = 4
options.brightness = self.brightness
self.matrix = RGBMatrix(options = options)
print(dir(self.matrix))
#sys.exit()
self.points = True # display crypto change in points or percent
self.functions = {'Stocks': self.getStockImage, 'Crypto': self.getCryptoImage, 'Forex': self.getForexImage,
'Daily Forecast':self.getDailyWeatherImage, 'Current Weather': self.getTodayWeatherImage,
'Sports (Team Stats)':lambda : self.getLeagueTableImage('premier_league'), 'Sports (Past Games)': lambda:self.getLeagueImage('NBA', 'past'),
'Sports (Upcoming Games)': lambda : self.getLeagueImage('NHL', 'future'), 'Sports (Live Games)': lambda: self.getLeagueImage('NBA', 'live'),
'News':self.getNewsImage, 'Custom Messages': self.getUserMessages,
'Stocks Prof': self.getStockProfessional, 'Crypto Prof': self.getCryptoProfessional, 'Forex Prof': self.getForexProfessional,
'Current Weather Prof': self.getTodayWeatherProfessional, 'News Prof':self.getNewsProfessional}
self.JSONs = {'Stocks': 'csv/stocks_settings.json', 'Crypto': 'csv/crypto_settings.json', 'Forex': 'csv/forex_settings.json',
'Daily Forecast':'csv/daily_weather.json', 'Current Weather': 'csv/current_weather.json',
'Sports (Team Stats)': 'csv/league_tables.json', 'Sports (Past Games)': 'csv/past_games.json',
'Sports (Upcoming Games)': 'csv/upcoming_games.json', 'Sports (Live Games)': 'csv/live_games.json',
'News':'csv/news_settings.json', 'Custom Images': 'csv/image_settings.json', 'Custom GIFs': 'csv/GIF_settings.json', 'Custom Messages': 'csv/message_settings.json',
'Stocks Prof': 'csv/stocks_settings.json', 'Crypto Prof': 'csv/crypto_settings.json', 'Forex Prof': 'csv/forex_settings.json',
'Current Weather Prof': 'csv/current_weather.json', 'News Prof':'csv/news_settings.json'}
def openImage(self, image_file):
image = Image.open(image_file)
image = image.convert('RGB')
# Make image fit our screen.
#image.thumbnail((self.matrix.width, self.matrix.height), Image.ANTIALIAS)
#image = image.convert('RGB')
return image
def degreesToCompass(self, deg):
dirs = ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW']
return dirs[int((deg+22.5)//45)%8]
def setImage(self, image, offset_x = 0, offset_y = 0, unsafe=True, min_x = 0, max_x = 128, min_y = 0, max_y = 32):
if (image.mode != "RGB"):
image = image.convert('RGB')
if unsafe:
#In unsafe mode we directly acceshow to send commands to running python processs the underlying PIL image array
#in cython, which is considered unsafe pointer accecss,
#however it's super fast and seems to work fine
#https://groups.google.com/forum/#!topic/cython-users/Dc1ft5W6KM4
img_width, img_height = image.size
self.matrix.SetPixelsPillow(offset_x, offset_y, img_width, img_height, image)
else:
# First implementation of a SetImage(). OPTIMIZE_ME: A more native
# implementation that directly reads the buffer and calls the underlying
# C functions can certainly be faster.
img_width, img_height = image.size
pixels = image.load()
for y in range(max(0, -offset_y), min(img_height, self.matrix.height - offset_y)):
for x in range(max(0, -offset_x), min(img_width, self.matrix.width - offset_x)):
if min_x <= x + offset_x <= max_x and min_y <= y + offset_y <= max_y:
(r, g, b) = pixels[x, y]
self.matrix.SetPixel(x + offset_x, y + offset_y, r*self.brightness, g*self.brightness, b*self.brightness)
def scrollImage(self, image, offset_x = 0, offset_y = 0, frame_skip = 10, gif = False, pause_frames = 0):
img_width, img_height = image.size
kill = False
while offset_x > -(img_width+1):
if offset_x == 0:
while pause_frames > 0:
if pause_frames%frame_skip == 0:
self.incrementGIF(image)
pause_frames -=1
if gif:
self.double_buffer.SetImage(image.convert('RGB'), offset_x, offset_y)
else:
self.double_buffer.SetImage(image, offset_x, offset_y)
for y in range(self.matrix.height):
self.matrix.SetPixel(offset_x + img_width +1 , y , 0,0,0)
self.matrix.SetPixel(offset_x + img_width , y , 0,0,0)
self.double_buffer = self.matrix.SwapOnVSync(self.double_buffer)
time.sleep(self.delay)
kill = self.checkKilled()
if kill: break
if kill: break
# for animation in gifs
if offset_x%frame_skip == 0:
self.incrementGIF(image)
#image = image.convert('RGB')
offset_x -= 1
#self.setImage(image.convert('RGB'), offset_x = offset_x, offset_y = offset_y)
if gif:
self.double_buffer.SetImage(image.convert('RGB'), offset_x, offset_y)
else:
self.double_buffer.SetImage(image, offset_x, offset_y)
buff = 0
# remove the ppixels behind the image, to stop trailing
self.double_buffer = self.matrix.SwapOnVSync(self.double_buffer)
for y in range(self.matrix.height):
self.matrix.SetPixel(offset_x + img_width +1 , y , 0,0,0)
self.matrix.SetPixel(offset_x + img_width , y , 0,0,0)
time.sleep(self.delay)
kill = self.checkKilled()
if kill: break
return kill
def scrollImageY(self, image, direction = 1, offset_x = 0, offset_y = 0, frame_skip = 10, gif = False):
kill = False
while offset_y != 0:
# for animation in gifs
if offset_y%frame_skip == 0:
self.incrementGIF(image)
offset_y += direction
if gif:
self.double_buffer.SetImage(image.convert('RGB'), offset_x, offset_y)
else:
self.double_buffer.SetImage(image, offset_x, offset_y)
self.double_buffer = self.matrix.SwapOnVSync(self.double_buffer)
time.sleep(self.delay)
kill = self.checkKilled()
if kill: break
return kill
def scrollImageTransition(self, image_files, offset_x = 0, offset_y = 0, stocks = True):
# use two image files and switch between them with a seemless transition
current_img = 1
image1 = self.openImage(image_files[0]).convert('RGB')
image2 = self.openImage(image_files[1]).convert('RGB')
double_buffer = self.matrix.CreateFrameCanvas()
kill = False
while True:
if current_img == 1:
if stocks:
update_process = Process(target = self.getFullStockImage, args = (1,))
update_process.start()
image1 = self.openImage(image_files[0]).convert('RGB')
image2 = self.openImage(image_files[1]).convert('RGB')
elif current_img == 2:
if stocks:
update_process = Process(target = self.getFullStockImage, args = (2,))
update_process.start()
image1 = self.openImage(image_files[1]).convert('RGB')
image2 = self.openImage(image_files[0]).convert('RGB')
img_width, img_height = image1.size
while offset_x > -img_width:
offset_x -= 1
double_buffer.SetImage(image1, offset_x, offset_y)
if offset_x + img_width < self.matrix.width: # if the image is ending
double_buffer.SetImage(image2, offset_x, offset_y)
double_buffer = self.matrix.SwapOnVSync(double_buffer)
time.sleep(self.delay)
kill = self.checkKilled()
if kill: break
if stocks:
image1.close()
image2.close()
if kill: break
if stocks:
update_process.join()
update_process.terminate()
if current_img == 1:
current_img = 2
elif current_img == 2:
current_img = 1
offset_x = 0
update_process.join()
update_process.terminate()
def scrollImageStacked(self, image, offset_x = 0, offset_y = 0):
img_width, img_height = image.size
while offset_x > -img_width - 128:
offset_x -= 1
self.setImage(image, offset_x = offset_x+128, offset_y = offset_y)
self.setImage(image, offset_x = offset_x, offset_y = offset_y+20)
kill = self.checkKilled()
time.sleep(self.delay)
return kill
def updateMultiple(self, options):
print('options', options)
for option in options:
if option not in ['Custom GIFs', 'Custom Images', 'Custom Messages']: # these images are already saved in user uploads, dodnt need to update them
img = self.functions[option]()
img.save('./display_images/'+ option+ '.ppm')
def incrementGIF(self, image):
try:
image.seek(self.frame)
except EOFError:
self.frame = 0
image.seek(self.frame)
self.frame +=1
def checkKilled(self):
kill = False
try:
msg = getInput()
if msg == 'K':
self.resetMatrix()
kill = True
self.process_msg(msg)
except KeyboardInterrupt:
sys.stdout.flush()
pass
return kill
def set_delay(self,speed):
if speed.lower() == 'slow':
self.delay = 0.03
elif speed.lower() == 'medium':
self.delay = 0.02
elif speed.lower() == 'fast':
self.delay = 0.01
return self.delay
def scrollFunctionsAnimated(self, options, animation = 'down', repeat = True):
# scrolls trhough all functions with animation. Updates functions and remakes images when each function not being dispplayed
self.updateMultiple([options[0]])
kill = False
i = 0 # keep track of which image we are displaying
self.double_buffer = self.matrix.CreateFrameCanvas()
while True:
update_process = Process(target = self.updateMultiple, args = ([options[(i+1) % len(options)]],))
update_process.start()
settings = json.load(open(self.JSONs[options[(i) % len(options)]]))
self.set_delay(settings['speed'])
animation = settings['animation'].lower()
if options[i % len(options)] == 'Custom Images':
images = self.getUserImages()
elif options[i % len(options)] == 'Custom GIFs':
images = self.getUserGIFs()
elif options[i % len(options)] == 'Custom Messages':
images = self.getUserMessages()
else: #these options just have a single ppm image
image = self.openImage('./display_images/' + options[i % len(options)] +'.ppm')
images = [image]
for image in images:
img_width, img_height = image.size
offset_x = 0
if animation == 'continuous':
offset_x = 128
elif animation in ['up', 'down']:
offset_x = max(0, 128-img_width)
offset_y = 0
#first scroll image in from bottom
frame_skip = int((1/15)/self.delay) #controls how fast gifs run
self.frame = 0
pause_frames = int(0.5/self.delay)
if animation == 'up':
offset_y = 33
direction = -1
kill = self.scrollImageY(image, direction = direction, offset_x = offset_x, offset_y = offset_y, frame_skip = frame_skip, gif = options[i % len(options)] == 'Custom GIFs')
elif animation == 'down':
direction = 1
offset_y = -33
kill = self.scrollImageY(image, direction = direction, offset_x = offset_x, offset_y = offset_y, frame_skip = frame_skip, gif = options[i % len(options)] == 'Custom GIFs')
if kill: break
offset_y = 0
if animation in ['up', 'down']:
while pause_frames > 0:
if pause_frames%frame_skip == 0:
self.incrementGIF(image)
pause_frames -=1
if options[i % len(options)] != 'Custom GIFs':
self.double_buffer.SetImage(image, offset_x, offset_y)
else:
self.double_buffer.SetImage(image.convert('RGB'), offset_x, offset_y)
self.double_buffer = self.matrix.SwapOnVSync(self.double_buffer)
time.sleep(self.delay)
kill = self.checkKilled()
if kill: break
if kill: break
if kill: break
try:
pause = float(settings['pause'])
except:
pause = 0
pause_frames = int(float(pause)/self.delay)
kill = self.scrollImage(image, offset_x = offset_x, offset_y = offset_y, frame_skip = frame_skip, gif = options[i % len(options)] == 'Custom GIFs', pause_frames = pause_frames)
if kill: break
if kill:break
if not repeat:
break
update_process.join()
update_process.terminate()
i+=1
def scrollProfessionalAnimated(self, options, animation = 'on'):
# scrolls trhough all functions with animation. Updates functions and remakes images when each function not being dispplayed
top = options[0]
bottom = options[1]
self.updateMultiple([top[0], bottom[0]])
kill = False
i1 = 0 # keep track of which image we are displaying
i2 = 0 # keep track of which image we are displaying
self.double_buffer = self.matrix.CreateFrameCanvas()
update_process = Process(target = self.updateMultiple, args = ([top[(i1+1) % len(top)]+ ' Prof', bottom[(i2+1) % len(bottom)]+ ' Prof' ],))
update_process.start()
self.updateMultiple([top[i1 % len(top)]+ ' Prof', bottom[i2 % len(bottom)]+ ' Prof' ])
image1 = self.openImage('./display_images/' + top[i1 % len(top)] +' Prof.ppm')
image1 = image1.convert('RGB')
image2 = self.openImage('./display_images/' + bottom[i2 % len(bottom)] +' Prof.ppm')
image2 = image2.convert('RGB')
settings1 = json.load(open(self.JSONs[top[i1 % len(top)]]))
delay_t1 = self.set_delay(settings1['speed'])
animation1 = settings1['animation'].lower()
settings2 = json.load(open(self.JSONs[bottom[i2 % len(bottom)] ]))
delay_t2 = self.set_delay(settings2['speed'])
animation2 = settings2['animation'].lower()
if animation1 == 'continuous':
offset_y1 = 0
offset_x1 = 128
else:
offset_y1 = -16
offset_x1 = 0
if animation2 == 'continuous':
offset_y2 = 16
offset_x2 = 128
else:
offset_y2 = 32
offset_x2 = 0
frame_skip = int((1/15)/self.delay) #controls how fast gifs run
self.frame = 0
img_width1, img_height1 = image1.size
img_width2, img_height2 = image2.size
kill = False
update_t1 = time.time()
update_t2 = time.time()
while True:
if offset_x1 < -(img_width1+1):
i1 += 1
settings1 = json.load(open(self.JSONs[top[i1 % len(top)]]))
delay_t1 = self.set_delay(settings1['speed'])
animation1 = settings1['animation'].lower()
if animation1 == 'continuous':
offset_y1 = 0
offset_x1 = 128
else:
offset_y1 = -16
offset_x1 = 0
update_process.join()
update_process.terminate()
update_process = Process(target = self.updateMultiple, args = ([top[(i1+1) % len(top)]+ ' Prof'],))
update_process.start()
image1 = self.openImage('./display_images/' + top[i1 % len(top)] +' Prof.ppm')
image1 = image1.convert('RGB')
img_width1, img_height1 = image1.size
if offset_x2 < -(img_width2+1):
i2 += 1
settings2 = json.load(open(self.JSONs[bottom[(i2) % len(bottom)]]))
delay_t2 = self.set_delay(settings2['speed'])
animation2 = settings2['animation'].lower()
if animation2 == 'continuous':
offset_y2 = 16
offset_x2 = 128
else:
offset_y2 = 32
offset_x2 = 0
update_process.join()
update_process.terminate()
update_process = Process(target = self.updateMultiple, args = ([bottom[i2 % len(bottom)]+ ' Prof'],))
update_process.start()
image2 = self.openImage('./display_images/' + bottom[(i2+1) % len(bottom)] +' Prof.ppm')
image2 = image2.convert('RGB')
img_width2, img_height2 = image2.size
if time.time() - update_t1 > delay_t1:
update_t1 = time.time()
if offset_y1 < 0:
offset_y1+=1
else:
offset_x1 -= 1
if time.time() - update_t2 > delay_t2:
update_t2 = time.time()
if offset_y2 > 16:
offset_y2-=1
else:
offset_x2 -= 1
if kill: break
#image = image.convert('RGB')
self.double_buffer.SetImage(image1, offset_x1, offset_y1)
self.double_buffer.SetImage(image2, offset_x2, offset_y2)
buff = 0
# remove the ppixels behind the image, to stop trailing
self.double_buffer = self.matrix.SwapOnVSync(self.double_buffer)
for y in range(16):
self.matrix.SetPixel(offset_x1 + img_width1 +1 , y , 0,0,0)
self.matrix.SetPixel(offset_x1 + img_width1 , y , 0,0,0)
for y in range(16,32):
self.matrix.SetPixel(offset_x2 + img_width2 +1 , y , 0,0,0)
self.matrix.SetPixel(offset_x2 + img_width2 , y , 0,0,0)
kill = self.checkKilled()
if kill: break
if kill: break
def scrollMultiple(self, animation = 'down'):
# scrolls trhough all functions with animation. Updates functions and remakes images when each function not being dispplayed
# read lines from csv
images = []
delays = []
kinds = []
f = open('csv/multiple.csv', 'r')
CSV = csv.reader(f)
next(CSV)
font = ImageFont.load("./fonts/texgyre-27.pil")
for row in CSV:
kind, content, delay = row
delays.append(delay)
kinds.append(kind)
print(kind, content, delay)
if kind == 'text':
images.append(self.textImage(content, font, 255, 255, 0, True, w_buff = 50))
elif kind == 'image':
images.append(self.openImage(content).convert('RGB'))
elif kind == 'gif':
images.append(self.openImage(content))
f.close()
kill = False
i = 0 # keep track of which image we are displaying
self.double_buffer = self.matrix.CreateFrameCanvas()
while True:
image = images[i%len(images)]
delay = delays[i%len(images)]
kind = kinds[i%len(images)]
img_width, img_height = image.size
offset_x = 0
if animation == 'traditional':
offset_x = 128
elif animation == 'continuous':
offset_x = 0
elif animation in ['up', 'down']:
offset_x = max(0, 128-img_width)
offset_y = 0
#first scroll image in from bottom
frame_skip = int((1/15)/self.delay) #controls how fast gifs run
self.frame = 0
pause_frames = int(float(delay)/self.delay)
if animation == 'up':
offset_y = 33
direction = -1
kill = self.scrollImageY(image, direction = direction, offset_x = offset_x, offset_y = offset_y, frame_skip = frame_skip, gif = kind=='gif')
elif animation == 'down':
direction = 1
offset_y = -33
kill = self.scrollImageY(image, direction = direction, offset_x = offset_x, offset_y = offset_y, frame_skip = frame_skip, gif = kind=='gif')
offset_y = 0
if kill: break
kill = self.scrollImage(image, offset_x = offset_x, offset_y = offset_y, frame_skip = frame_skip, gif = kind=='gif', pause_frames = pause_frames)
if kill: break
i+=1
def textImage(self, text, font, r = 255, g = 255, b = 255, matrix_height = False, w_buff = 3, h_buff = 3, background = False, location = False):
'''
creates and returns a ppm image containing the text in the supplied font and colour
'''
width, height = self.get_text_dimensions(text, font)
if matrix_height:
height = 32
img = Image.new('RGB', (width + w_buff, height + h_buff))
d = ImageDraw.Draw(img)
if background:
br, bg, bb = background
d.rectangle(xy = (0, 0, width + w_buff, height + h_buff),
fill = (br, bg, bb))
#outline = (255, 255, 255),
#width = 0) #use outline and width to add a border
if location:
d.text(location, text, fill=(r, g, b), font=font)
else:
d.text((0, 0), text, fill=(r, g, b), font=font)
return img
def getUserMessages(self):
'''
displays the text entered in the webpage by the user.
'''
f = open('csv/message_settings.json', 'r')
all_settings = json.load(f)
f.close()
colours = {'Black':(0,0,0),
'White':(255,255,255),
'Red':(255,0,0),
'Green':(0,255,0),
'Blue':(0,0,255),
'Purple':(255,0,255),
'Yellow':(255,255,0),
'Cyan':(0,255,255)}
imgs = []
for ind, message in enumerate(all_settings['messages']):
font = ImageFont.load("./fonts/10x20.pil")
location = (0, 4)
if message["size"] == 'Large':
font = ImageFont.load("./fonts/texgyre-27.pil")
location = (0, -2)
elif message["size"] == 'Small':
font = ImageFont.load("./fonts/6x13.pil")
location = (0, 7)
r,g,b = colours[message['text_colour']]
background = colours[message['background_colour']]
img = self.textImage(message['text'], font, int(r), int(g), int(b), True, w_buff = 5, background = background, location = location)
if all_settings['title'] and ind == 0:
title_img = self.openImage('feature_titles/message.png')
imgs.append(self.stitchImage([title_img, img]))
else:
imgs.append(img)
return imgs
def displayGIF(self, gif, delay = 0.5, repeat = True):
# To iterate through the entire gif
i = 0
while True:
try:
gif.seek(i)
except EOFError:
if not repeat: break
i = 0
gif.seek(i)
# do something to im
self.setImage(gif.convert('RGB'))
time.sleep(delay)
i += 1
try:
msg = getInput()
if msg == 'K':
gif.close()
self.resetMatrix()
break
self.process_msg(msg)
except KeyboardInterrupt:
sys.stdout.flush()
pass
def scrollGIF(self, gif, offset_x = 0, offset_y = 0):
# To iterate through the entire gif
i = 0
img_width, img_height = gif.size
while offset_x > -img_width:
offset_x -= 1
try:
gif.seek(i)
except EOFError:
i = 0
gif.seek(i)
# do something to im
self.setImage(gif.convert('RGB'), offset_x = offset_x)
time.sleep(self.delay)
if offset_x % 20 == 0:
i += 1
for x in range(offset_x + img_width, 128):
for y in range(self.matrix.height):
self.matrix.SetPixel(x , y , 0,0,0)
kill = self.checkKilled()
if kill:
break
return kill
#Using change between min and day price give appropriate arrow
#and set the overall change colour
def getArrow(self, CHANGE, professional = False):
self.greenORred
logos_path = os.path.join(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logos'), 'stocks')
if(CHANGE>0):
Arrow = Image.open(os.path.join(logos_path, 'up-1.png'))
self.greenORred = (0, 255, 0)
else:
Arrow = Image.open(os.path.join(logos_path, 'down-1.png'))
self.greenORred = (255, 0, 0)
CHANGE = (CHANGE * -1)
if professional:
w, h = Arrow.size
Arrow = Arrow.resize((int(w/2), int(h/2)))
return Arrow, CHANGE
def get_text_dimensions(self, text_string, font):
canvas = Image.new('RGB', (10000,100))
draw = ImageDraw.Draw(canvas)
monospace = font
text = text_string
white = (255,255,255)
draw.text((0, 0), text, font=monospace, fill=white)
bbox = canvas.getbbox()
width = bbox[2]-bbox[0]
height = bbox[3]-bbox[1]
return width,height
#Draw Ticker, current and change onto one image
def textToImage(self, TICKER, CURRENT, ARROW, percent_change = False, point_change = False, font = ImageFont.load("./fonts/10x20.pil")):
w1, text_height = self.get_text_dimensions(TICKER, font)
w2, text_height = self.get_text_dimensions(CURRENT, font)
text_width_current = max(w1,w2)
img = Image.new('RGB', (text_width_current +1000 , 32))
d = ImageDraw.Draw(img)
d.text((4, 0), TICKER, fill=(255, 255, 255), font=font)
d.text((4, 16), CURRENT, fill=self.greenORred, font=font)
if percent_change:
d.text(((w1+7), 14 - text_height), percent_change, fill=self.greenORred, font=font)
w, h = self.get_text_dimensions(percent_change, font)
w1 += 7 + w
if point_change:
img.paste(ARROW, ((w2+ 9),18))
d.text(((w2+29), 16), point_change, fill=self.greenORred, font=font)
w,h = self.get_text_dimensions(point_change, font)
w2 += 29 + w
img = img.crop((0,0,max(w1, w2) + 20,32))
return img
def textToImageProf(self, TICKER, CURRENT, CHANGE, ARROW, font):
text_width_current, text_height = self.get_text_dimensions(CURRENT, font)
img = Image.new('RGB', (text_width_current +100 , 32))
d = ImageDraw.Draw(img)
d.text((4, 0), TICKER, fill=(255, 255, 255), font=font)
d.text((4, 8), CURRENT, fill=self.greenORred, font=font)
img.paste(ARROW, ((text_width_current + 7),10))
d.text(((text_width_current+18), 8), CHANGE, fill=self.greenORred, font=font)
text_width_change, text_height = self.get_text_dimensions(CHANGE, font)
newWidth = text_width_current + text_width_change +30
img = img.crop((0,0,newWidth,32))
return img
#Stitch the logo & prices picture into one image
def stitchImage(self, image_list):
widths, heights = zip(*(i.size for i in image_list))
total_width = sum(widths)
max_height = max(heights)
new_im = Image.new('RGB', (total_width, max_height))
x_offset = 0
for im in image_list:
new_im.paste(im, (x_offset,0))
x_offset += im.size[0]
return new_im
def resetMatrix(self):
for x in range(self.matrix.width):
for y in range(self.matrix.height):
self.matrix.SetPixel(x , y , 0,0,0)
def getCryptoImage(self):
f = open('csv/crypto_settings.json', 'r')
all_crypto_settings = json.load(f)
f.close()
if all_crypto_settings['title']:
title_img = self.openImage('feature_titles/crypto.png')
image_list = [title_img]
image_list.append(self.blank)
else:
image_list = []
coin_info = all_crypto_settings['symbols']
coin_bases = list(coin_info.keys())
for i, cb in enumerate(coin_bases):
try:
ticker, base = cb.split(',')
current = float(coin_info[cb]["current"])
point_change = float(coin_info[cb]["24hr_change"])
percent_change = float(coin_info[cb]["percent_change"])
arrow, change = self.getArrow(point_change)
percent_change = str(abs(percent_change)) + '%'
point_change = str(abs(point_change))
current = str(current)
if not all_crypto_settings['percent']:
percent_change = False
if not all_crypto_settings['point']:
point_change = False
midFrame = self.textToImage(ticker + '(' + base + ')', current, arrow, percent_change, point_change) #IMAGE THE TEXT
if all_crypto_settings['logos']:
try:
logos_path = os.path.join(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logos'), 'crypto')
logo = self.openImage(os.path.join(logos_path, ticker + '.png'))
stitchedStock = self.stitchImage([logo,midFrame])
except Exception as e:
stitchedStock = midFrame
else:
stitchedStock = midFrame
image_list.append(stitchedStock)
image_list.append(self.blank)
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logf.write(str(e))
self.logf.write('. file: ' + fname)
self.logf.write('. line: ' + str(exc_tb.tb_lineno))
self.logf.write('. type: ' + str(exc_type))
self.logf.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))
finalDisplayImage = self.stitchImage(image_list)
return finalDisplayImage
def getCryptoProfessional(self):
self.blank = Image.new('RGB', (0, 16))
f = open('csv/crypto_settings.json', 'r')
all_crypto_settings = json.load(f)
f.close()
if all_crypto_settings['title']:
title_img = self.openImage('feature_titles/small_feature_titles/crypto.png')
image_list = [title_img]
image_list.append(self.blank)
else:
image_list = []
coin_info = all_crypto_settings['symbols']
coin_bases = list(coin_info.keys())
for i, cb in enumerate(coin_bases):
try:
ticker, base = cb.split(',')
current = float(coin_info[cb]["current"])
change = float(coin_info[cb]["24hr_change"])
arrow, change = self.getArrow(change, professional=True)
if all_crypto_settings["percent"]:
# convert percent to points
change = str(abs(float(coin_info[cb]['percent_change']))) + '%'
else:
change = str(abs(float(change)))
current = str(current)
midFrame = self.textToImageProf(ticker + '(' + base + ')', current, change, arrow, font=ImageFont.load("./fonts/6x10.pil")) #IMAGE THE TEXT
if all_crypto_settings['logos']:
try:
logos_path = os.path.join(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logos'), 'crypto')
logo = self.openImage(os.path.join(logos_path, ticker + '.png'))
w,h = logo.size
logo=logo.resize((int(w/2), int(h/2)))
stitchedStock = self.stitchImage([logo,midFrame])
except:
stitchedStock = midFrame
else:
stitchedStock = midFrame
image_list.append(stitchedStock)
image_list.append(self.blank)
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logf.write(str(e))
self.logf.write('. file: ' + fname)
self.logf.write('. line: ' + str(exc_tb.tb_lineno))
self.logf.write('. type: ' + str(exc_type))
self.logf.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))
finalDisplayImage = self.stitchImage(image_list)
self.blank = Image.new('RGB', (10, 32))
return finalDisplayImage
def getForexImage(self):
f = open('csv/forex_settings.json', 'r')
all_forex_settings = json.load(f)
f.close()
if all_forex_settings['title']:
title_img = self.openImage('feature_titles/forex.png')
image_list = [title_img]
image_list.append(self.blank)
else:
image_list = []
forex_settings = all_forex_settings['symbols']
symbol_bases = list(forex_settings.keys())
for i, sb in enumerate(symbol_bases):
try:
symbol, base = sb.split(',')
current = float(forex_settings[sb]['current'])
change = float(forex_settings[sb]['24hr_change'])
percent_change = str(abs(float(forex_settings[sb]['percent_change']))) +'%'
point_change = str(abs(change))
if not all_forex_settings['percent']:
percent_change = False
if not all_forex_settings['point']:
point_change = False
arrow, change = self.getArrow(change)
current = str(current)
midFrame = self.textToImage(base+ '(' + symbol + ')', current, arrow, percent_change, point_change) #IMAGE THE TEXT
if all_forex_settings['logos']:
try:
logos_path = os.path.join(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logos'), 'currencies')
logo = Image.open(os.path.join(logos_path, symbol.upper() + '.png'))
bse = Image.open(os.path.join(logos_path, base.upper() + '.png'))
new_im = Image.new('RGB', (32, 32))
new_im.paste(bse, (0,10), bse.convert('RGBA'))
new_im.paste(logo, (10,0), logo.convert('RGBA'))
stitchedStock = self.stitchImage([new_im, midFrame])
image_list.append(new_im)
except Exception as e:
print(e)
image_list.append(midFrame)
image_list.append(self.blank)
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logf.write(str(e))
self.logf.write('. file: ' + fname)
self.logf.write('. line: ' + str(exc_tb.tb_lineno))
self.logf.write('. type: ' + str(exc_type))
self.logf.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))
finalDisplayImage = self.stitchImage(image_list)
return finalDisplayImage
def getForexProfessional(self):
self.blank = Image.new('RGB', (0, 16))
f = open('csv/forex_settings.json', 'r')
all_forex_settings = json.load(f)
f.close()
if all_forex_settings['title']:
title_img = self.openImage('feature_titles/small_feature_titles/forex.png')
image_list = [title_img]
image_list.append(self.blank)
else:
image_list = []
forex_settings = all_forex_settings['symbols']
symbol_bases = list(forex_settings.keys())
for i, sb in enumerate(symbol_bases):
try:
symbol, base = sb.split(',')
current = float(forex_settings[sb]['current'])
change = float(forex_settings[sb]['24hr_change'])
arrow, change = self.getArrow(change, professional = True)
if all_forex_settings["percent"]:
# convert percent to points
change = abs(float(forex_settings[sb]['percent_change']))
change = str(change) + '%'
else:
change = str(change)
current = str(current)
midFrame = self.textToImageProf(symbol + '(' + base + ')', current, change, arrow, font = ImageFont.load("./fonts/6x10.pil")) #IMAGE THE TEXT
if all_forex_settings['logos']:
try:
logos_path = os.path.join(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logos'), 'currencies')
logo = Image.open(os.path.join(logos_path, symbol.upper() + '.png'))
bse = Image.open(os.path.join(logos_path, base.upper() + '.png'))
new_im = Image.new('RGB', (32, 32))
new_im.paste(bse, (0,10), bse.convert('RGBA'))
new_im.paste(logo, (10,0), logo.convert('RGBA'))
width, height = new_im.size
new_im = new_im.resize((int(width/2), int(height/2)))
stitchedStock = self.stitchImage([new_im, midFrame])
image_list.append(new_im)
except Exception as e:
print(e)
image_list.append(midFrame)
image_list.append(self.blank)
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logf.write(str(e))
self.logf.write('. file: ' + fname)
self.logf.write('. line: ' + str(exc_tb.tb_lineno))
self.logf.write('. type: ' + str(exc_type))
self.logf.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))
finalDisplayImage = self.stitchImage(image_list)
self.blank = Image.new('RGB', (10, 32))
return finalDisplayImage
def getStockImage(self):
f = open('csv/stocks_settings.json', 'r')
all_stocks_settings = json.load(f)
f.close()
if all_stocks_settings['title']:
title_img = self.openImage('feature_titles/stocks.png')
image_list = [title_img]
image_list.append(self.blank)
else:
image_list = []
stock_info = all_stocks_settings['symbols']
symbols = list(stock_info.keys())
for i, symbol in enumerate(symbols):
try:
info = stock_info[symbol]
change = float(info['change']) #TEXT
ticker = symbol #TEXT
arrow, change = self.getArrow(change)
percent_change = '%.2f' % abs(float(info['percent_change'])) + '%'
point_change = '%.2f' % abs(change)
print(percent_change, point_change)
current = '%.2f' % float(info['current']) #TEXT
if not all_stocks_settings['percent']:
percent_change = False
if not all_stocks_settings['point']:
point_change = False
midFrame = self.textToImage(ticker, current, arrow, percent_change, point_change) #IMAGE THE TEXT
if all_stocks_settings['logos']:
try:
logos_path = os.path.join(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logos'), 'stocks')
logo = self.openImage(os.path.join(logos_path, ticker + '.png'))
stitchedStock = self.stitchImage([logo,midFrame])
except Exception as e:
print(str(e))
stitchedStock = midFrame
else:
stitchedStock = midFrame
image_list.append(stitchedStock)
image_list.append(self.blank)
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logf.write(str(e))
self.logf.write('. file: ' + fname)
self.logf.write('. line: ' + str(exc_tb.tb_lineno))
self.logf.write('. type: ' + str(exc_type))
self.logf.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))
finalDisplayImage = self.stitchImage(image_list)
return finalDisplayImage
def getStockProfessional(self):
self.blank = Image.new('RGB', (0, 16))
f = open('csv/stocks_settings.json', 'r')
all_stocks_settings = json.load(f)
f.close()
if all_stocks_settings['title']:
title_img = self.openImage('feature_titles/small_feature_titles/stocks.png')
image_list = [title_img, Image.new('RGB', (5, 16))]
image_list.append(self.blank)
else:
image_list = []
stock_info = all_stocks_settings['symbols']
symbols = list(stock_info.keys())
for i, symbol in enumerate(symbols):
try:
info = stock_info[symbol]
change = float(info['change'])#TEXT
ticker = symbol #TEXT
arrow, change = self.getArrow(change, professional=True)
if all_stocks_settings["percent"]:
change = '%.2f' % abs(float(info['percent_change'])) + '%'
else:
change = '%.2f' % abs(change)
current = '%.2f' % float(info['current']) #TEXT
midFrame = self.textToImageProf(ticker, current, change, arrow, font=ImageFont.load("./fonts/6x10.pil")) #IMAGE THE TEXT
if all_stocks_settings['logos']:
try:
try: #load the tiny logo
logos_path = os.path.join(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logos'), 'tiny_stocks')
logo = Image.open(os.path.join(logos_path, ticker + '.png'))
except: # load the big logo and scale it
logos_path = os.path.join(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logos'), 'stocks')
logo = Image.open(os.path.join(logos_path, ticker + '.png'))
# half the size of the logo
width, height = logo.size
logo = logo.resize((int(width/2), int(height/2)))
stitchedStock = self.stitchImage([logo,midFrame])
except Exception as e:
stitchedStock = midFrame
else:
stitchedStock = midFrame
image_list.append(stitchedStock)
image_list.append(self.blank)
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logf.write(str(e))
self.logf.write('. file: ' + fname)
self.logf.write('. line: ' + str(exc_tb.tb_lineno))
self.logf.write('. type: ' + str(exc_type))
self.logf.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))
finalDisplayImage = self.stitchImage(image_list)
self.blank = Image.new('RGB', (10, 32))
return finalDisplayImage
def getNewsImage(self):
all_settings = json.load(open('csv/news_settings.json', 'r'))
if all_settings['title']:
title_img = self.openImage('feature_titles/news.png')
image_list = [title_img]
else:
image_list = []
headline_font = ImageFont.load("./fonts/6x13.pil")
source_font = ImageFont.load("./fonts/6x13.pil")
headline_info = all_settings['headlines']
headlines = []
source_date_times = []
source = []
for i, hi in enumerate(headline_info):
try:
headline, source, date_time = hi
date, time = date_time.split('T')
time = time[:-1]
source_date_time = source + ': ' + date + ' ' + time
headline = headline.replace("^", ",")
headline = headline.replace("", "'")
headline = headline.replace("", "'")
headline = headline.replace('', '"')
headline = headline.replace('', '"')
headline = headline.replace('', '-')
headline = headline.replace('', '-')
headline = ''.join([h for h in headline if ord(h) < 256])
lst = headline.rsplit('-', 1) #remove source name at end of headline
headline = lst[0]
headline_img = self.textImage(headline, headline_font, matrix_height = True)
source_img = self.textImage(source_date_time, source_font, r=255, g=255, b=0, matrix_height = True)
try:
logo_name = source.lower().replace(' ', '-')
logos_path = os.path.join(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logos'), 'news_logos')
logo = Image.open(os.path.join(logos_path, logo_name + '.png'))
except Exception as e:
logo_name = 'default'
logos_path = os.path.join(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logos'), 'news_logos')
logo = Image.open(os.path.join(logos_path, logo_name + '.png'))
img = Image.new('RGB', (headline_img.size[0], 32))
img.paste(headline_img, (2, 0))
img.paste(source_img, (2,16))
img= self.stitchImage([logo,img])
image_list.append(img)
image_list.append(self.blank)
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logf.write(str(e))
self.logf.write('. file: ' + fname)
self.logf.write('. line: ' + str(exc_tb.tb_lineno))
self.logf.write('. type: ' + str(exc_type))
self.logf.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))
news_image = self.stitchImage(image_list)
return news_image
def getNewsProfessional(self):
all_settings = json.load(open('csv/news_settings.json', 'r'))
if all_settings['title']:
title_img = self.openImage('feature_titles/small_feature_titles/news.png')
image_list = [title_img]
else:
image_list = []
headline_font = ImageFont.load("./fonts/6x13.pil")
source_font = ImageFont.load("./fonts/6x13.pil")
headline_info = all_settings['headlines']
headlines = []
source_date_times = []
source = []
blank = Image.new('RGB', (0, 16))
for i, hi in enumerate(headline_info):
try:
headline, source, date_time = hi
date, time = date_time.split('T')
time = time[:-1]
source_date_time = source + ': ' + date + ' ' + time
headline = headline.replace("^", ",")
headline = headline.replace("", "'")
headline = headline.replace("", "'")
headline = headline.replace('', '"')
headline = headline.replace('', '"')
headline = headline.replace('', '-')
headline = headline.replace('', '-')
headline = ''.join([h for h in headline if ord(h) < 256])
lst = headline.rsplit('-', 1) #remove source name at end of headline
headline = lst[0]
headline_img = self.textImage(headline, headline_font, matrix_height = True)
source_img = self.textImage(source_date_time+ ':', source_font, r=255, g=255, b=0, matrix_height = True)
try:
logo_name = source[i].lower().replace(' ', '-')
logos_path = os.path.join(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logos'), 'news_logos')
logo = Image.open(os.path.join(logos_path, logo_name + '.png'))
except Exception as e:
logo_name = 'default'
logos_path = os.path.join(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logos'), 'news_logos')
logo = Image.open(os.path.join(logos_path, logo_name + '.png'))
width, height = logo.size
logo = logo.resize((int(width/2), int(height/2)))
img = Image.new('RGB', (headline_img.size[0]+ source_img.size[0] + logo.size[0] +5, 32))
img.paste(headline_img, (source_img.size[0]+ logo.size[0] -5, 3))
img.paste(source_img, (2,3))
img= self.stitchImage([logo,img])
image_list.append(img)
image_list.append(blank)
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logf.write(str(e))
self.logf.write('. file: ' + fname)
self.logf.write('. line: ' + str(exc_tb.tb_lineno))
self.logf.write('. type: ' + str(exc_type))
self.logf.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))
news_image = self.stitchImage(image_list)
return news_image
def getLeagueImage(self, league=False, time = 'past'):
if time in ['past', 'live']:
filepath = 'csv/{}_games.json'.format(time)
else:
print(time)
filepath = 'csv/upcoming_games.json'
all_settings = json.load(open(filepath, 'r'))
title_img = self.openImage('feature_titles/sports_'+ time + '.png')
if all_settings['title']:
title_img = self.openImage('feature_titles/sports_{}.png'.format(time))
imgs = [title_img, self.blank]
else:
imgs = []
leagues_info = all_settings['leagues']
leagues = list(leagues_info.keys())
for league in leagues:
try:
x_offset = 0
img = Image.new('RGB', (10000, 32))
league_info = leagues_info[league]
try:
league_logo = Image.open('logos/sports/league_logos/{}.png'.format(league)).convert('RGB')
img.paste(league_logo, (x_offset,0))
x_offset += league_logo.size[0] +self.blank.size[0]
except:
pass
small_font = ImageFont.load("./fonts/5x7.pil")
med_font = ImageFont.load("./fonts/7x14B.pil")
large_font = ImageFont.load("./fonts/9x18B.pil")
sports_info = self.readSportsCSV(league)
print(sports_info)
buff_size = 25
for match in league_info:
home_team = match['home_team']
away_team = match['away_team']
if time != 'future':
home_score = match['home_score']
away_score = match['away_score']
date = match['date'].replace('-', '.')
#rond = match['round']
try:
home_logo = Image.open('logos/sports/{}/{}'.format(league, sports_info[home_team]['logo']))
except Exception as e:
home_logo = self.textImage(home_team.replace(' ', '\n'), small_font, r = 255, g = 255, b = 255)
try:
away_logo = Image.open('logos/sports/{}/{}'.format(league, sports_info[away_team]['logo']))
except Exception as e:
away_logo = self.textImage(away_team.replace(' ', '\n'), small_font, r = 255, g = 255, b = 255)
date_timage = self.textImage(date, small_font, r = 255, g = 255, b = 255)
img.paste(home_logo, (x_offset,0))
x_offset += home_logo.size[0] + 2
if time == 'future':
img.paste(date_timage, (x_offset+5, 0))
h_colour = mcolors.to_rgb(sports_info[home_team]['colour'].replace(' ', ''))
a_colour = mcolors.to_rgb(sports_info[away_team]['colour'].replace(' ', ''))
hc_timage = self.textImage(sports_info[home_team]['code'], med_font, r = int(h_colour[0]*255), g = int(h_colour[1]*255), b = int(h_colour[2]*255))
ac_timage = self.textImage(sports_info[away_team]['code'], med_font, r = int(a_colour[0]*255), g = int(a_colour[1]*255), b = int(a_colour[2]*255))
vs_timage = self.textImage('vs', med_font, r = 255, g = 255, b = 255, h_buff = 5)
img.paste(hc_timage, (x_offset, 9))
img.paste(vs_timage, (x_offset + hc_timage.size[0], 9))
img.paste(ac_timage, (x_offset + hc_timage.size[0] + vs_timage.size[0], 9))
x_offset += max( date_timage.size[0], hc_timage.size[0] + vs_timage.size[0] + ac_timage.size[0])
else:
score_image = self.textImage(home_score + '-' + away_score, large_font, h_buff = 5, r = 255, g = 255, b = 255)
#vs_timage = self.textImage(sports_info[home_team]['code'] + 'vs' + sports_info[away_team]['code'], small_font, r = 255, g = 255, b = 255)
h_colour = mcolors.to_rgb(sports_info[home_team]['colour'].replace(' ', ''))
a_colour = mcolors.to_rgb(sports_info[away_team]['colour'].replace(' ', ''))
hc_timage = self.textImage(sports_info[home_team]['code'], small_font, r = int(h_colour[0]*255), g = int(h_colour[1]*255), b = int(h_colour[2]*255))
ac_timage = self.textImage(sports_info[away_team]['code'], small_font, r = int(a_colour[0]*255), g = int(a_colour[1]*255), b = int(a_colour[2]*255))
vs_timage = self.textImage('vs', small_font, r = 255, g = 255, b = 255)
if date_timage.size[0] > score_image.size[0]:
img.paste(date_timage, (x_offset+2, 0))
img.paste(hc_timage, (x_offset+6, 9))
img.paste(vs_timage, (x_offset+5 + hc_timage.size[0], 9))
img.paste(ac_timage, (x_offset+6 + hc_timage.size[0] + vs_timage.size[0], 9))
img.paste(score_image, (x_offset + 2 + int((date_timage.size[0] - score_image.size[0])/2), 15))
else:
img.paste(date_timage, (x_offset+1+int((score_image.size[0] - date_timage.size[0] )/2), 0))
vs_size = hc_timage.size[0] + vs_timage.size[0] + ac_timage.size[0]
img.paste(hc_timage, (x_offset + 1 + int((score_image.size[0] - vs_size)/2), 9))
img.paste(vs_timage, (x_offset + int((score_image.size[0] - vs_size)/2) + hc_timage.size[0], 9))
img.paste(ac_timage, (x_offset+1 + int((score_image.size[0] - vs_size)/2) + hc_timage.size[0] + vs_timage.size[0], 9))
img.paste(score_image, (x_offset+1, 15))
x_offset += max( date_timage.size[0]+4, hc_timage.size[0] + vs_timage.size[0] + ac_timage.size[0]+4, 2 + int(score_image.size[0]))
#img.paste(vs_timage, (x_offset+4, 9))
#if league == 'NHL':
#
#img.paste(round_timage, (x_offset+ 7, 8))
#x_offset += max(home_timage.size[0], away_timage.size[0], date_timage.size[0], round_timage.size[0], score_image.size[0])
img.paste(away_logo, (x_offset,0))
x_offset += away_logo.size[0]
x_offset += buff_size
img = img.crop((0,0,x_offset ,32))
imgs.append(img)
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logf.write(str(e))
self.logf.write('. file: ' + fname)
self.logf.write('. line: ' + str(exc_tb.tb_lineno))
self.logf.write('. type: ' + str(exc_type))
self.logf.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))
return self.stitchImage(imgs)
def getLeagueTableImage(self, league = False):
all_settings = json.load(open('csv/league_tables.json', 'r'))
leagues_info = all_settings['leagues']
leagues = list(leagues_info.keys())
if all_settings['title']:
title_img = self.openImage('feature_titles/sports_team_stats.png')
imgs = [title_img, self.blank]
else:
imgs = []
for league in leagues:
try:
x_offset = 0
img = Image.new('RGB', (10000, 32))
league_logo = Image.open('logos/sports/league_logos/{}.png'.format(league)).convert('RGB')
img.paste(league_logo, (x_offset,0))
x_offset += league_logo.size[0] +self.blank.size[0]
team_info = leagues_info[league]
small_font = ImageFont.load("./fonts/5x7.pil")
med_font = ImageFont.load("./fonts/8x13B.pil")
large_font = ImageFont.load("./fonts/10x20.pil")
#if league =='NHL': # read the NHl info from the csv, prem will need this as well
sports_info = self.readSportsCSV(league) # gets colour and symbol info etc from csv
buff_size = 20
for team in team_info:
try:
logo = Image.open('logos/sports/{}/{}'.format(league, sports_info[team['name']]['logo']))
img.paste(logo, (x_offset, 0))
x_offset += logo.size[0] + 2
except Exception as e:
print('no logo for:', team['name'])
name_timage = self.textImage(team['name'], med_font, r = 255, g = 255, b = 0)
wins_timage = self.textImage('Wins:' + team['wins'], small_font, r = 0, g = 255, b = 0)
loss_timage = self.textImage('Losses:' + team['loss'], small_font, r = 255, g = 0, b = 0)
draw_timage = self.textImage('Draws:' + team['draw'], small_font, r = 0, g = 0, b = 255)
#points_timage = self.textImage('Points:' + team['points'], small_font, r = 255, g = 255, b = 255)
standing_timage = self.textImage('Standing:' + team['standing'], small_font, r = 255, g = 255, b = 255)
img.paste(name_timage, (x_offset, -1))
img.paste(wins_timage, (x_offset, 12))
img.paste(loss_timage, (x_offset, 19))
img.paste(draw_timage, (x_offset, 26))
x_offset += max( wins_timage.size[0], loss_timage.size[0], draw_timage.size[0])
#img.paste(points_timage, (x_offset, 14))
img.paste(standing_timage, (x_offset, 22))
#x_offset += max(points_timage.size[0], standing_timage.size[0]) + buff_size
x_offset += standing_timage.size[0] + buff_size
img = img.crop((0,0,x_offset ,32))
imgs.append(img)
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logf.write(str(e))
self.logf.write('. file: ' + fname)
self.logf.write('. line: ' + str(exc_tb.tb_lineno))
self.logf.write('. type: ' + str(exc_type))
self.logf.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))
return self.stitchImage(imgs)
def getTodayWeatherImage(self):
all_settings = json.load(open('csv/current_weather.json', 'r'))
if all_settings['title']:
title_img = self.openImage('feature_titles/weather.png')
imgs = [title_img, self.blank]
else:
imgs = []
current_weathers = all_settings['locations']
locations = list(current_weathers.keys())
for i, location in enumerate(locations):
try:
current_weather = current_weathers[location]
small_font = ImageFont.load("./fonts/5x7.pil")
large_font = ImageFont.load("./fonts/10x20.pil")
location_img = self.textImage(location.upper(), small_font, r = 255, g = 255, b = 0)
main = current_weather['main_weather']
if main == 'Clouds':
main = current_weather['description']
weather_ids = {'Clear': '01', 'few clouds': '02', 'scattered clouds': '03', 'broken clouds':'04', 'overcast clouds':'04', 'Drizzle':'09',
'Rain':'10', 'Thunderstorm':'11', 'Snow':'13', 'Mist': '50', 'Smoke': '50', 'Haze': '50', 'Dust': '50', 'Fog': '50',
'Sand': '50', 'Ash': '50', 'Squall': '50', 'Tornado': '50'}
weather_dir = './logos/weather_icons'
weather_img = Image.open(weather_dir + '/weather_type_icons/' + weather_ids[main] + '.png')
temp = current_weather['temp']
feels_temp = current_weather['feels_like']
if all_settings['temp'] == 'kelvin':
temp = current_weather['temp'] + 273.15
elif all_settings['temp'] == 'fahrenheit':
feels_temp = current_weather['feels_like']*9/5 + 32
temp = current_weather['temp']*9/5 + 32
temp_img = self.textImage(str("{0:.0f}".format(temp)), large_font)
deg_img = self.textImage('o', small_font)
main = current_weather['main_weather']
main_img = self.textImage(main.upper(), small_font)
feels_img = self.textImage('Feels like:'.upper() + str("{0:.0f}".format(feels_temp)), small_font)
min_img = self.textImage( "{0:.0f}".format(current_weather['min_temp']), small_font, r=0, g=0, b=255)
max_img = self.textImage( "{0:.0f}".format(current_weather['max_temp']), small_font, r=255, g=0, b=0)
hum_img = Image.open(weather_dir + '/humidity.png')
htext_img = self.textImage(str(current_weather['humidity']) + '%', small_font)
uv_img = Image.open(weather_dir + '/uv.png')
utext_img = self.textImage(str(round(current_weather['uv'], 1)) , small_font)
weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
months =['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
month = months[int(datetime.now().strftime('%m'))-1]
date = str(int(datetime.now().strftime('%d')))
weekday = weekdays[datetime.today().weekday()]
date_img = self.textImage((month + ' ' + date + ',' + weekday).upper(), small_font)
rain_img = Image.open(weather_dir + '/rain-chance.png')
rtext_img = self.textImage(str(int(current_weather['rain_chance']*100)) + '%', small_font)
cloud_img = Image.open(weather_dir + '/clouds.png')
ctext_img = self.textImage(str(current_weather['clouds']) + '%', small_font)
wind_img = Image.open(weather_dir + '/wind.png')
w_speed = current_weather['wind_speed']*3.6
w_unit = 'K/H'
if all_settings["wind_speed"] == "miles/hour":
w_speed = current_weather['wind_speed']*2.236936
w_unit = 'M/H'
wtext_img = self.textImage("{0:.0f}".format(w_speed) + w_unit, small_font)
wdir_img = self.textImage(self.degreesToCompass(current_weather['wind_direction']).upper(), small_font)
vis_img = Image.open(weather_dir + '/visibility.png')
vtext_img = self.textImage(str(round(current_weather['visibility']/1000, 1)) + 'km'.upper(), small_font)
'------------------------------------------'
img = Image.new('RGB', (1000, 32))
img.paste(weather_img, (5,9))
x_offset = 5 + weather_img.size[0] + 1
img.paste(main_img, (x_offset, 26))
img.paste(temp_img, (x_offset + main_img.size[0]//2 - temp_img.size[0]//2,9))
img.paste(deg_img, (x_offset + main_img.size[0]//2 - temp_img.size[0]//2 + temp_img.size[0], 8))
x_offset += max( main_img.size[0], temp_img.size[0] + deg_img.size[0])
img.paste(min_img, (x_offset - 1, 12))
img.paste(max_img, (x_offset - 1, 21))
x_offset += max(min_img.size[0], max_img.size[0]) + 2
img.paste(hum_img, ( x_offset, 8))
img.paste(uv_img, ( x_offset, 22))
img.paste(htext_img, (x_offset + hum_img.size[0], 10))
img.paste(utext_img, (x_offset + uv_img.size[0], 23))
x_offset += max(hum_img.size[0], uv_img.size[0]+2)
x_offset += max(htext_img.size[0], utext_img.size[0]) + 6
img.paste(rain_img, (x_offset,8))
img.paste(cloud_img, (x_offset,20))
img.paste(ctext_img, (x_offset + cloud_img.size[0] + 2, 22))
img.paste(rtext_img, (x_offset + rain_img.size[0]+ 2, 10))
x_offset += max(cloud_img.size[0], rain_img.size[0])+6
x_offset += max(ctext_img.size[0], rtext_img.size[0])+6
img.paste(wind_img, (x_offset,8))
img.paste(vis_img, (x_offset,20))
img.paste(wtext_img, (x_offset + wind_img.size[0] + 2, 10))
img.paste(vtext_img, (x_offset + vis_img.size[0] + 2, 22))
x_offset += wind_img.size[0] + wtext_img.size[0] + 4
img.paste(wdir_img, (x_offset, 10))
img.paste(location_img, (5,0))
img.paste(feels_img, (location_img.size[0] + 10, 0))
img.paste(date_img, (location_img.size[0] + feels_img.size[0] + 15, 0))
img = img.crop((0,0,max(x_offset +wdir_img.size[0] + 4, location_img.size[0] + feels_img.size[0] + 15 + date_img.size[0]) ,32))
imgs.append(img)
imgs.append(self.blank)
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logf.write(str(e))
self.logf.write('. file: ' + fname)
self.logf.write('. line: ' + str(exc_tb.tb_lineno))
self.logf.write('. type: ' + str(exc_type))
self.logf.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))
return self.stitchImage(imgs)
def getTodayWeatherProfessional(self):
all_settings = json.load(open('csv/current_weather.json', 'r'))
if all_settings['title']:
title_img = self.openImage('feature_titles/small_feature_titles/weather.png')
image_list = [title_img, Image.new('RGB', (3, 16))]
else:
image_list = []
current_weathers = all_settings['locations']
locations = list(current_weathers.keys())
weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
months =['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
month = months[int(datetime.now().strftime('%m'))-1]
date = str(int(datetime.now().strftime('%d')))
weekday = weekdays[datetime.today().weekday()]
for i, location in enumerate(locations):
try:
img = Image.new('RGB', (1000, 32))
current_weather = current_weathers[location]
small_font = ImageFont.load("./fonts/4x6.pil")
font = ImageFont.load("./fonts/6x10.pil")
large_font = ImageFont.load("./fonts/10x20.pil")
main = current_weather['main_weather']
if main == 'Clouds':
main = current_weather['description']
weather_ids = {'Clear': '01', 'few clouds': '02', 'scattered clouds': '03', 'broken clouds':'04', 'overcast clouds':'04', 'Drizzle':'09',
'Rain':'10', 'Thunderstorm':'11', 'Snow':'13', 'Mist': '50', 'Smoke': '50', 'Haze': '50', 'Dust': '50', 'Fog': '50',
'Sand': '50', 'Ash': '50', 'Squall': '50', 'Tornado': '50'}
weather_dir = './logos/weather_icons'
location_img = self.textImage(location.upper(), font, r = 255, g = 255, b = 0)
img.paste(location_img, (5,3))
x_offset = location_img.size[0] + 8
date_img = self.textImage((month + ' ' + date + ',' + weekday).upper(), font)
img.paste(date_img, (x_offset, 3))
x_offset += date_img.size[0] + 2
weather_img = Image.open(weather_dir + '/weather_type_icons/' + weather_ids[main] + '.png')
w, h = weather_img.size
weather_img = weather_img.resize((int(w/2), int(h/2)))
main = current_weather['main_weather']
main_img = self.textImage(main.upper(), font)
img.paste(main_img, (x_offset, 3))
x_offset += main_img.size[0] + 2
img.paste(weather_img, (x_offset,3))
x_offset += weather_img.size[0] + 2
temp = current_weather['temp']
if all_settings['temp'] == 'kelvin':
temp = current_weather['temp'] + 273.15
elif all_settings['temp'] == 'fahrenheit':
temp = current_weather['temp']*9/5 + 32
temp_img = self.textImage(str("{0:.0f}".format(temp)), font)
img.paste(temp_img, (x_offset,3))
x_offset += temp_img.size[0]-3
deg_img = self.textImage('o', small_font)
img.paste(deg_img, (x_offset+1, 1))
x_offset += deg_img.size[0] -2
min_img = self.textImage( "{0:.0f}".format(current_weather['min_temp']), small_font, r=0, g=0, b=255)
img.paste(min_img, (x_offset+2, 2))
max_img = self.textImage( "{0:.0f}".format(current_weather['max_temp']), small_font, r=255, g=0, b=0)
img.paste(max_img, (x_offset+2, 8))
x_offset += max_img.size[0] + 2
hum_img = Image.open(weather_dir + '/humidity.png')
htext_img = self.textImage(str(current_weather['humidity']) + '%', font)
uv_img = Image.open(weather_dir + '/uv.png')
utext_img = self.textImage(str(round(current_weather['uv'], 1)), font)
rain_img = Image.open(weather_dir + '/rain-chance.png')
rtext_img = self.textImage(str(int(current_weather['rain_chance']*100)) + '%', font)
cloud_img = Image.open(weather_dir + '/clouds.png')
ctext_img = self.textImage(str(current_weather['clouds']) + '%', font)
wind_img = Image.open(weather_dir + '/wind.png')
w_speed = current_weather['wind_speed']*3.6
w_unit = 'K/H'
if all_settings["wind_speed"] == "miles/hour":
w_speed = current_weather['wind_speed']*2.236936
w_unit = 'M/H'
wtext_img = self.textImage("{0:.0f}".format(wind_speed) + wind_unit, font)
wdir_img = self.textImage(self.degreesToCompass(current_weather['wind_direction']).upper(), font)
vis_img = Image.open(weather_dir + '/visibility.png')
vtext_img = self.textImage(str(current_weather['visibility']/1000) + 'km', font)
for image in [hum_img, htext_img, uv_img, utext_img, rain_img, rtext_img, cloud_img, ctext_img, wind_img, wtext_img, wdir_img, vis_img, vtext_img]:
img.paste(image, (x_offset, 3))
x_offset += image.size[0] + 2
img = img.crop((0,0,x_offset +image.size[0] ,16))
image_list.append(img)
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logf.write(str(e))
self.logf.write('. file: ' + fname)
self.logf.write('. line: ' + str(exc_tb.tb_lineno))
self.logf.write('. type: ' + str(exc_type))
self.logf.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))
return self.stitchImage(image_list)
def getDailyWeatherImageAlt(self):
f = open( "csv/weather_location.txt", 'r' )
location = f.read()
f.close()
img = Image.new('RGB', (128, 32))
current_weather = json.load(open('csv/current_weather.json', 'r'))
small_font = ImageFont.load("./fonts/5x7.pil")
extra_small_font = ImageFont.load("./fonts/4x6.pil")
large_font = ImageFont.load("./fonts/10x20.pil")
location_img = self.textImage(location, extra_small_font, r = 255, g = 255, b = 0)
main = current_weather['main_weather']
if main == 'Clouds':
main = current_weather['description']
weather_ids = {'Clear': '01', 'few clouds': '02', 'scattered clouds': '03', 'broken clouds':'04', 'overcast clouds':'04', 'Drizzle':'09',
'Rain':'10', 'Thunderstorm':'11', 'Snow':'13', 'Mist': '50', 'Smoke': '50', 'Haze': '50', 'Dust': '50', 'Fog': '50',
'Sand': '50', 'Ash': '50', 'Squall': '50', 'Tornado': '50'}
weather_dir = './logos/weather_icons'
weather_img = Image.open(weather_dir + '/weather_type_icons/' + weather_ids[main] + '.png')
temp_img = self.textImage(str("{0:.0f}".format(current_weather['temp'])), large_font)
deg_img = self.textImage('o', small_font)
min_img = self.textImage( "{0:.0f}".format(current_weather['min_temp']), small_font, r=0, g=0, b=255)
max_img = self.textImage( "{0:.0f}".format(current_weather['max_temp']), small_font, r=255, g=0, b=0)
main = current_weather['main_weather']
main_img = self.textImage(main, small_font)
weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
months =['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
month = months[int(datetime.now().strftime('%m'))]
date = str(int(datetime.now().strftime('%d')))
weekday = weekdays[datetime.today().weekday()]
date_img = self.textImage(month + ' ' + date + ',' + weekday, extra_small_font)
rain_img = Image.open(weather_dir + '/rain-chance.png')
rtext_img = self.textImage(str(int(current_weather['rain_chance']*100)) + '%', extra_small_font)
hum_img = Image.open(weather_dir + '/humidity.png')
htext_img = self.textImage(str(current_weather['humidity']) + '%', extra_small_font)
uv_img = Image.open(weather_dir + '/uv.png')
utext_img = self.textImage(str(current_weather['uv']) , extra_small_font)
wind_img = Image.open(weather_dir + '/wind.png')
wtext_img = self.textImage(str(current_weather['wind_speed']) + 'm/s', extra_small_font)
img.paste(location_img, (0,0))
img.paste(weather_img, (0,12))
img.paste(temp_img, (30,9))
img.paste(deg_img, (50, 8))
img.paste(min_img, (55, 10))
img.paste(main_img, (30, 26))
img.paste(max_img, (55, 19))
img.paste(date_img, (location_img.size[0], 1))
img.paste(rain_img, (75,0))
img.paste(rtext_img, (88, 1))
img.paste(hum_img, (102, 0))
img.paste(htext_img, (113, 1))
#img.paste(uv_img, ( 96, 0))
#img.paste(utext_img, (109, 0))
#img.paste(wind_img, (96,0))
#img.paste(wtext_img, (109,0))
img0 = img
img = Image.new('RGB', (1000, 32))
daily_weather = json.load(open('csv/daily_weather.json', 'r'))
#img.paste(date_img, (70, 0))
x_offset = 64
for i in range(0,len(daily_weather)-1):
weekday = weekdays[(datetime.today().weekday() + i)%7]
day_img = self.textImage( weekday, small_font)
weather = daily_weather[i]
main = weather['main_weather']
if main == 'Clouds':
main = weather['description']
weather_img = Image.open(weather_dir + '/small_icons/' + weather_ids[main] + '.png')
min_img = self.textImage( "{0:.0f}".format(weather['min_temp']), small_font, r=0, g=0, b=255)
max_img = self.textImage( "{0:.0f}".format(weather['max_temp']), small_font, r=255, g=0, b=0)
img.paste(day_img, (x_offset +5, 9))
img.paste(weather_img, (x_offset +5, 16))
img.paste(min_img, (x_offset + 25, 10))
img.paste(max_img, (x_offset + 25, 20))
x_offset += 35
img1 = img.crop((64,0,x_offset ,32))
img1.save('display_images/weather.ppm')
return img0, img1
def getDailyWeatherImage(self):
all_settings = json.load(open('csv/daily_weather.json', 'r'))
if all_settings['title']:
title_img = self.openImage('feature_titles/forecast.png')
imgs = [title_img, self.blank]
else:
imgs = []
daily_weathers = json.load(open('csv/daily_weather.json', 'r'))
locations = list(daily_weathers['locations'].keys())
for i, location in enumerate(locations):
print(location)
try:
img = Image.new('RGB', (1000, 32))
daily_weather = daily_weathers['locations'][location]
small_font = ImageFont.load("./fonts/5x7.pil")
extra_small_font = ImageFont.load("./fonts/4x6.pil")
large_font = ImageFont.load("./fonts/10x20.pil")
location_img = self.textImage(location.upper(), extra_small_font, r = 255, g = 255, b = 0)
main = daily_weather[0]['main_weather']
if main == 'Clouds':
main = daily_weather[0]['description']
weather_ids = {'Clear': '01', 'few clouds': '02', 'scattered clouds': '03', 'broken clouds':'04', 'overcast clouds':'04', 'Drizzle':'09',
'Rain':'10', 'Thunderstorm':'11', 'Snow':'13', 'Mist': '50', 'Smoke': '50', 'Haze': '50', 'Dust': '50', 'Fog': '50',
'Sand': '50', 'Ash': '50', 'Squall': '50', 'Tornado': '50'}
weather_dir = './logos/weather_icons'
weather_img = Image.open(weather_dir + '/weather_type_icons/' + weather_ids[main] + '.png')
temp = daily_weather[0]['temp']
min_temp = daily_weather[0]['min_temp']
max_temp = daily_weather[0]['max_temp']
if daily_weathers['temp'] == 'kelvin':
temp = daily_weather[0]['temp'] + 273.15
min_temp = daily_weather[0]['min_temp'] + 273.15
max_temp = daily_weather[0]['max_temp'] + 273.15
elif daily_weathers['temp'] == 'fahrenheit':
temp = daily_weather[0]['temp']*9/5 + 32
min_temp = daily_weather[0]['min_temp']*9/5 + 32
max_temp = daily_weather[0]['max_temp']*9/5 + 32
temp_img = self.textImage(str("{0:.0f}".format(temp)), large_font)
deg_img = self.textImage('o', small_font)
min_img = self.textImage( "{0:.0f}".format(min_temp), small_font, r=0, g=0, b=255)
max_img = self.textImage( "{0:.0f}".format(max_temp), small_font, r=255, g=0, b=0)
main = daily_weather[0]['main_weather']
main_img = self.textImage(main.upper(), small_font)
weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
months =['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
month = months[int(datetime.now().strftime('%m'))-1]
date = str(int(datetime.now().strftime('%d')))
weekday = weekdays[datetime.today().weekday()]
date_img = self.textImage((month + ' ' + date + ',' + weekday).upper(), extra_small_font)
rain_img = Image.open(weather_dir + '/rain-chance.png')
rtext_img = self.textImage(str(int(daily_weather[0]['rain_chance']*100)) + '%', extra_small_font)
hum_img = Image.open(weather_dir + '/humidity.png')
htext_img = self.textImage(str(daily_weather[0]['humidity']) + '%', extra_small_font)
wind_img = Image.open(weather_dir + '/wind.png')
wtext_img = self.textImage(str(daily_weather[0]['wind_speed']) + 'm/s'.upper(), extra_small_font)
uv_img = Image.open(weather_dir + '/uv.png')
utext_img = self.textImage(str(round(daily_weather[0]['uv'], 1)) , small_font)
cloud_img = Image.open(weather_dir + '/clouds.png')
ctext_img = self.textImage(str(daily_weather[0]['clouds']) + '%', small_font)
wind_img = Image.open(weather_dir + '/wind.png')
w_speed = daily_weather[0]['wind_speed']*3.6
w_unit = 'K/H'
if daily_weathers['wind_speed'] == "miles/hour":
w_speed = daily_weather[0]['wind_speed']*2.236936
w_unit = 'M/H'
wtext_img = self.textImage("{0:.0f}".format(w_speed) + w_unit, small_font)
wdir_img = self.textImage(self.degreesToCompass(daily_weather[0]['wind_direction']), small_font)
vis_img = Image.open(weather_dir + '/visibility.png')
vtext_img = self.textImage(str(round(daily_weather[0]['visibility']/1000, 1)) + 'km'.upper(), small_font)
img.paste(location_img, (0,0))
x_offset = location_img.size[0]+2
img.paste(weather_img, (5,9))
x_offset = 5 + weather_img.size[0] + 1
img.paste(main_img, (x_offset, 26))
img.paste(temp_img, (x_offset + main_img.size[0]//2 - temp_img.size[0]//2,9))
img.paste(deg_img, (x_offset + main_img.size[0]//2 - temp_img.size[0]//2 + temp_img.size[0], 8))
x_offset += max( main_img.size[0], temp_img.size[0] + deg_img.size[0])
img.paste(min_img, (x_offset - 1, 12))
img.paste(max_img, (x_offset - 1, 21))
x_offset += max(min_img.size[0], max_img.size[0]) + 2
img.paste(date_img, (x_offset, 1))
x_offset += date_img.size[0]+2
img.paste(rain_img, (x_offset,0))
x_offset += rain_img.size[0]+2
img.paste(rtext_img, (x_offset, 1))
x_offset += rtext_img.size[0]+2
img.paste(hum_img, (x_offset, 0))
x_offset += hum_img.size[0]+2
img.paste(htext_img, (x_offset, 1))
x_offset+= htext_img.size[0]+2
img.paste(uv_img, ( x_offset, 0))
x_offset += uv_img.size[0]+2
img.paste(utext_img, (x_offset, 1))
x_offset += utext_img.size[0]+2
img.paste(cloud_img, (x_offset,0))
x_offset += cloud_img.size[0]+2
img.paste(ctext_img, (x_offset, 1))
x_offset += ctext_img.size[0]+2
img.paste(wind_img, (x_offset,0))
x_offset += wind_img.size[0]+2
img.paste(wtext_img, (x_offset, 1))
x_offset += wtext_img.size[0]+2
img.paste(wdir_img, (x_offset, 1))
x_offset+= wdir_img.size[0]+2
img.paste(vis_img, (x_offset,0))
x_offset+= vis_img.size[0]+2
img.paste(vtext_img, (x_offset, 1))
x_offset += vtext_img.size[0] +2
crop_x = x_offset
#img.paste(uv_img, ( 96, 0))
#img.paste(utext_img, (109, 0))
#img.paste(wind_img, (96,0))
#img.paste(wtext_img, (109,0))
#img.paste(date_img, (70, 0))
x_offset = 70
for i in range(1,len(daily_weather)-1):
weekday = weekdays[(datetime.today().weekday() + i)%7]
day_img = self.textImage( weekday.upper(), small_font)
weather = daily_weather[i]
main = weather['main_weather']
if main == 'Clouds':
main = weather['description']
min_temp = weather['min_temp']
max_temp = weather['max_temp']
if daily_weathers['temp'] == 'kelvin':
min_temp = weather['min_temp'] + 273.15
max_temp = weather['max_temp'] + 273.15
elif daily_weathers['temp'] == 'fahrenheit':
min_temp = weather['min_temp']*9/5 + 32
max_temp = weather['max_temp']*9/5 + 32
weather_img = Image.open(weather_dir + '/small_icons/' + weather_ids[main] + '.png')
min_img = self.textImage( "{0:.0f}".format(min_temp), small_font, r=0, g=0, b=255)
max_img = self.textImage( "{0:.0f}".format(max_temp), small_font, r=255, g=0, b=0)
img.paste(day_img, (x_offset +5, 9))
img.paste(weather_img, (x_offset +5, 16))
img.paste(min_img, (x_offset + 25, 10))
img.paste(max_img, (x_offset + 25, 18))
x_offset += 43
img1 = img.crop((0,0,max(x_offset, crop_x) ,32))
imgs.append(img1)
imgs.append(self.blank)
# add the image text
except Exception as e:
print(str(e))
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logf.write(str(e))
self.logf.write('. file: ' + fname)
self.logf.write('. line: ' + str(exc_tb.tb_lineno))
self.logf.write('. type: ' + str(exc_type))
self.logf.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))
return self.stitchImage(imgs)
def readSportsCSV(self, league):
team_info = {}
f = open('csv/sports/{}/team_info.csv'.format(league), 'r')
CSV = csv.reader(f)
next(CSV)
for row in CSV:
team_info[row[0]] = {}
team_info[row[0]]['id'] = row[1]
team_info[row[0]]['code'] = row[2]
team_info[row[0]]['logo'] = row[4]
team_info[row[0]]['colour'] = row[3]
f.close()
return team_info
def displayDailyWeatherAlt(self):
img0, img1 = self.getDailyWeatherImageAlt()
#img = stock_ticker.getTodayWeatherImage()
while True:
self.setImage(img0, offset_x = 0, offset_y = 0)
image = img1
img_width, img_height = image.size
offset_x = 64
offset_y = 0
while offset_x > 64-img_width:
offset_x -= 1
self.setImage(image, offset_x = offset_x, offset_y = offset_y, min_x = 64, min_y = 9)
if offset_x + img_width < self.matrix.width: # if the image is ending
self.setImage(image, offset_x = offset_x + img_width, offset_y = offset_y, min_x = 64, min_y = 9)
try:
msg = getInput()
if msg == 'K':
self.resetMatrix()
return True
self.process_msg(msg)
except KeyboardInterrupt:
sys.stdout.flush()
pass
time.sleep(self.delay*1.1)
def getUserImages(self):
f = open('csv/image_settings.json', 'r')
all_settings = json.load(f)
f.close()
imgs = []
for ind,image in enumerate(all_settings['images']):
try:
img = self.openImage(os.path.join(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'user_uploads'), image))
print(img)
img.thumbnail((99999, 32))
print(img)
if all_settings['title'] and ind == 0:
title_img = self.openImage('feature_titles/images.png')
imgs.append(self.stitchImage([title_img, img]))
else:
imgs.append(img)
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logf.write(str(e))
self.logf.write('. file: ' + fname)
self.logf.write('. line: ' + str(exc_tb.tb_lineno))
self.logf.write('. type: ' + str(exc_type))
self.logf.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))
return imgs
def getUserGIFs(self):
f = open('csv/GIF_settings.json', 'r')
all_settings = json.load(f)
f.close()
GIFs = []
for ind,fle in enumerate(all_settings['images']):
try:
GIF = Image.open(os.path.join(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'user_uploads'), fle))
frames = []
if ind == 0 and all_settings['title']:
title_img = self.openImage('feature_titles/gifs.png')
for i, frame in enumerate(ImageSequence.Iterator(GIF)):
frame = frame.convert('RGB')
frame.thumbnail((128, 32))
f = self.stitchImage([title_img, frame])
frames.append(f)
else:
for i, frame in enumerate(ImageSequence.Iterator(GIF)):
frame = frame.convert('RGB')
frame.thumbnail((128, 32))
#frame = frame.resize((99999, 32))
f = self.stitchImage([frame])
frames.append(f)
frames[0].save('./display_images/working_gif{}.gif'.format(str(ind)), save_all=True, append_images=frames[1:], loop=0, optimize = False)
GIF = Image.open('./display_images/working_gif{}.gif'.format(str(ind)))
GIFs.append(GIF)
except Exception as e:
print(str(e))
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
self.logf.write(str(e))
self.logf.write('. file: ' + fname)
self.logf.write('. line: ' + str(exc_tb.tb_lineno))
self.logf.write('. type: ' + str(exc_type))
self.logf.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))
#below code stitches title and GIF together
'''
frames = []
for i, frame in enumerate(ImageSequence.Iterator(gif)):
if all_settings['title']:
f = self.stitchImage([title_img, frame])
else:
f = self.stitchImage([frame])
frames.append(f)
frames[0].save('./display_images/Custom GIFs.gif', save_all=True, append_images=frames[1:], loop=0, optimize = False)
'''
return GIFs
def displayStocks(self):
self.scrollImageTransition(['final.ppm', 'final.ppm'], offset_x = 0, offset_y = 0)
def displayProfessional(self):
forex = self.getForexProfessional()
crypto = self.getCryptoProfessional()
news = self.getNewsProfessional()
stock = self.getStockProfessional()
weather = self.getTodayWeatherProfessional()
x_offset = 0
news.paste(weather, (x_offset, 16))
x_offset += weather.size[0]
news.paste(crypto, (x_offset, 16))
x_offset += crypto.size[0]
news.paste(stock, (x_offset, 16))
x_offset += stock.size[0]
news.paste(forex, (x_offset, 16))
x_offset += forex.size[0]
self.double_buffer = self.matrix.CreateFrameCanvas()
while True:
kill = stock_ticker.scrollImage(news, offset_x = 128)
if kill:
break
def process_msg(self, msg):
if msg == 'S': # stocks
self.scrollFunctionsAnimated(['stocks', 'stocks'], animation = 'traditional')
elif msg == 'C': # crypto
self.scrollFunctionsAnimated(['crypto', 'crypto'], animation = 'traditional')
elif msg == 'F': # forex
self.scrollFunctionsAnimated(['forex', 'forex'], animation = 'traditional')
elif msg == 'N': #news
self.scrollFunctionsAnimated(['news', 'news'], animation = 'traditional')
# speed settings
elif msg == 's':
self.delay = 0.03
elif msg == 'm':
self.delay = 0.02
elif msg == 'f':
self.delay = 0.01
elif msg in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']: # birghtness ettings
self.brightness = (float(msg)+1)*10
self.matrix.brightness = self.brightness
elif msg == 'T':# text
self.scrollFunctionsAnimated(['text', 'text'], animation = 'traditional')
elif msg == 'I': # image
self.scrollFunctionsAnimated(['display_image', 'display_image'], animation = 'traditional')
elif msg == 'G': # gif
self.scrollFunctionsAnimated(['display_gif', 'display_gif'], animation = 'traditional')
elif msg == 'W': # weather
self.scrollFunctionsAnimated(['today_weather', 'today_weather'], animation = 'traditional')
elif msg == 'D': # daily weather
self.scrollFunctionsAnimated(['daily_weather', 'daily_weather'],animation = 'traditional')
elif msg == 'P': # past league
self.scrollFunctionsAnimated(['past_games', 'past_games'],animation = 'traditional')
elif msg == 'l': # future league
self.scrollFunctionsAnimated(['future_games', 'future_games'],animation = 'traditional')
elif msg == 'L': # live game
self.scrollFunctionsAnimated(['live_games', 'live_games'],animation = 'traditional')
elif msg == 't': #legue tble
self.scrollFunctionsAnimated(['league_table', 'league_table'],animation = 'traditional')
elif msg == 'A': #everything
#userSettings = ['display_gif', 'text', 'display_image', 'stocks', 'crypto', 'forex', 'today_weather', 'daily_weather', 'league_table', 'league_games', 'news'] # these wil be read from csv, just for demo
#userSettings = [ 'daily_weather']
#userSettings = ['crypto', 'stocks'] # these wil be read from csv, just for demo
#userSettings = [ 'display_image', 'news'] # these wil be read from csv, just for demo
userSettings = json.load(open('csv/display_settings.json'))
if 'Professional'==userSettings[0] and len(userSettings[1][0])>0 and len(userSettings[1][1])>0: #if professional display
self.scrollProfessionalAnimated(userSettings[1])
elif len(userSettings[1][0])>0 and 'Standard'==userSettings[0]:
self.scrollFunctionsAnimated(userSettings[1][0], animation = 'down')
elif msg == 'b':
userSettings = json.load(open('csv/display_settings.json'))
self.scrollProfessionalAnimated(userSettings)
#self.displayProfessional()
elif msg == '+':
stock_ticker.scrollMultiple()
elif msg == 'K': # kill
self.resetMatrix()
elif msg =='-':
self.run_intro_screen()
elif msg == '*':
#
#
start_GIF = Image.open('./logos/startup_logo1.gif')
self.displayGIF(start_GIF, delay = 0.02, repeat = False)
#stock_ticker.setImage(start_image)
time.sleep(2)
self.resetMatrix()
def run_intro_screen(self):
dct = {"feature": "Custom Messages", "speed": "Medium", "animation": "Down", "title": False, "messages": [{"name": "welcome", "text": "Welcome to Fintic!", "text_colour": "White", "size": "Large", "background_colour": "Black"}, {"name": "get_started", "text": "To get started, connect your device to the \"Fintic Hotspot\" and access \"fintic.local:1024\" on your web browser. You can connect your ticker to Wi-Fi there.", "text_colour": "White", "size": "Small", "background_colour": "Black"}]}
json.dump(dct, open('csv/message_settings.json', 'w'))
self.scrollFunctionsAnimated(['Custom Messages'], repeat = True)
if __name__ == '__main__':
with open('log.txt', "a") as log:
try:
stock_ticker = StockTicker()
stock_ticker.logf = log
#stock_ticker.getLeagueImage('NHL', 'future')
#stock_ticker.getCryptoImage()
#
#stock_ticker.process_msg('*')
#time.sleep(8)
#stock_ticker.process_msg('-')
#stock_ticker.process_msg('W')
#stock_ticker.process_msg('A')
while True:
msg = getInput()
stock_ticker.process_msg(msg)
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
log.write(str(e))
log.write('. file: ' + fname)
log.write('. line: ' + str(exc_tb.tb_lineno))
log.write('. type: ' + str(exc_type))
log.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))