lag fixed and stockTicker.py refactored into a class
This commit is contained in:
parent
086b22e776
commit
992251955d
Binary file not shown.
12
server.py
12
server.py
@ -6,12 +6,16 @@
|
|||||||
# permission of Daniel Richardson
|
# permission of Daniel Richardson
|
||||||
|
|
||||||
from flask import Flask, render_template, request
|
from flask import Flask, render_template, request
|
||||||
from stockTicker import runStockTicker, stopStockTicker
|
from stockTicker import StockTicker
|
||||||
from werkzeug.utils import secure_filename
|
from werkzeug.utils import secure_filename
|
||||||
import os
|
import os
|
||||||
import datetime
|
import datetime
|
||||||
import threading
|
import threading
|
||||||
import csv
|
import csv
|
||||||
|
|
||||||
|
|
||||||
|
stock_ticker = StockTicker()
|
||||||
|
|
||||||
command = 300
|
command = 300
|
||||||
tickerList = 0
|
tickerList = 0
|
||||||
DelayTime = 20
|
DelayTime = 20
|
||||||
@ -124,12 +128,12 @@ def matrix():
|
|||||||
global LastCommand
|
global LastCommand
|
||||||
if "Run Display" in request.form:
|
if "Run Display" in request.form:
|
||||||
pass
|
pass
|
||||||
runStockTicker(command, DelayTime, speedTime)
|
stock_ticker.runStockTicker(command, DelayTime, speedTime)
|
||||||
LastCommand = 'Run display'
|
LastCommand = 'Run display'
|
||||||
elif "Stop Display (at next refresh)" in request.form:
|
elif "Stop Display (at next refresh)" in request.form:
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
stopStockTicker()
|
stock_ticker.stopStockTicker()
|
||||||
LastCommand = 'Stop display at next checkpoint'
|
LastCommand = 'Stop display at next checkpoint'
|
||||||
except:
|
except:
|
||||||
print("none running")
|
print("none running")
|
||||||
@ -145,4 +149,4 @@ def matrix():
|
|||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app.run(host='0.0.0.0', port=1024, debug=True)
|
app.run(host='0.0.0.0', port=1024, debug=True)
|
||||||
|
|
||||||
#sudo ./demo -D1 final.ppm -t 50 -m 25 --led-gpio-mapping=adafruit-hat --led-rows=32 --led-cols=256
|
#sudo ./demo -D1 final.ppm -t 50 -m 25 --led-gpio-mapping=adafruit-hat --led-rows=32 --led-cols=256 --led-slowdown-gpio=4
|
||||||
|
389
stockTicker.py
389
stockTicker.py
@ -13,226 +13,219 @@ from PIL import Image, ImageDraw, ImageFont
|
|||||||
import time
|
import time
|
||||||
import csv
|
import csv
|
||||||
|
|
||||||
#Define global resources
|
class StockTicker():
|
||||||
symbols = []
|
def __init__(self):
|
||||||
ApiKeys = [["b1be6696d54342bdb5c8f59a052854fd","237d183faf984e7eba708a647c55153a","3012b3cb19784ed4be2b02e9907e53cb"],["f835e85df2a74df1904fe6dc53bcc17a","41ec268496744c34a96e3c408081300b","2d566fc71ade46d688713b13730c5219"]]
|
#Define global resources
|
||||||
#ApiKeys = [["6172b84d1f464ad88b95ed52e4391bce","979f9b8c9ee748fbbb57cb490ccaaf42","593fa818a44144699b75433aafd92d15"]
|
self.symbols = []
|
||||||
retrievedList = []
|
self.ApiKeys = [["b1be6696d54342bdb5c8f59a052854fd","237d183faf984e7eba708a647c55153a","3012b3cb19784ed4be2b02e9907e53cb"],["f835e85df2a74df1904fe6dc53bcc17a","41ec268496744c34a96e3c408081300b","2d566fc71ade46d688713b13730c5219"]]
|
||||||
greenORred = (255, 255, 255)
|
#self.ApiKeys = [["6172b84d1f464ad88b95ed52e4391bce","979f9b8c9ee748fbbb57cb490ccaaf42","593fa818a44144699b75433aafd92d15"]
|
||||||
ListStocks = []
|
self.retrievedList = []
|
||||||
blank = Image.open('logos/blank.png')
|
self.greenORred = (255, 255, 255)
|
||||||
ApiCalledError = False
|
self.ListStocks = []
|
||||||
keySwapper = 0
|
self.blank = Image.open('logos/blank.png')
|
||||||
displayTime = 60
|
self.ApiCalledError = False
|
||||||
speedDisplay = 25
|
self.keySwapper = 0
|
||||||
running = True
|
self.displayTime = 60
|
||||||
Delay = 20
|
self.speedDisplay = 25
|
||||||
parseCSV = 0
|
self.running = True
|
||||||
symbolLength = 0
|
self.Delay = 20
|
||||||
|
self.parseCSV = 0
|
||||||
|
self.symbolLength = 0
|
||||||
|
|
||||||
#Get the logo from file that is the same as ticker name
|
#Get the logo from file that is the same as ticker name
|
||||||
def getLogo(Ticker):
|
def getLogo(self, Ticker):
|
||||||
try:
|
try:
|
||||||
Logo = Image.open('logos/' + Ticker + '.png')
|
Logo = Image.open('logos/' + Ticker + '.png')
|
||||||
except:
|
except:
|
||||||
print('Could not find logo for: ' + Ticker + ' using default')
|
print('Could not find logo for: ' + Ticker + ' using default')
|
||||||
Logo = Image.open('logos/default.png')
|
Logo = Image.open('logos/default.png')
|
||||||
return Logo
|
return Logo
|
||||||
|
|
||||||
#Using change between min and day price give appropriate arrow
|
#Using change between min and day price give appropriate arrow
|
||||||
#and set the overall change colour
|
#and set the overall change colour
|
||||||
def getArrow(CHANGE):
|
def getArrow(self, CHANGE):
|
||||||
global greenORred
|
self.greenORred
|
||||||
if(CHANGE>0):
|
if(CHANGE>0):
|
||||||
Arrow = Image.open('logos/up.png')
|
Arrow = Image.open('logos/up.png')
|
||||||
greenORred = (0, 255, 0)
|
self.greenORred = (0, 255, 0)
|
||||||
|
return Arrow, CHANGE
|
||||||
|
Arrow = Image.open('logos/down.png')
|
||||||
|
self.greenORred = (255, 0, 0)
|
||||||
|
CHANGE = (CHANGE * -1)
|
||||||
return Arrow, CHANGE
|
return Arrow, CHANGE
|
||||||
Arrow = Image.open('logos/down.png')
|
|
||||||
greenORred = (255, 0, 0)
|
|
||||||
CHANGE = (CHANGE * -1)
|
|
||||||
return Arrow, CHANGE
|
|
||||||
|
|
||||||
def get_text_dimensions(text_string, font):
|
def get_text_dimensions(self, text_string, font):
|
||||||
canvas = Image.new('RGB', (100,100))
|
canvas = Image.new('RGB', (100,100))
|
||||||
|
|
||||||
draw = ImageDraw.Draw(canvas)
|
draw = ImageDraw.Draw(canvas)
|
||||||
monospace = font
|
monospace = font
|
||||||
|
|
||||||
text = text_string
|
text = text_string
|
||||||
white = (255,255,255)
|
white = (255,255,255)
|
||||||
draw.text((10, 10), text, font=monospace, fill=white)
|
draw.text((10, 10), text, font=monospace, fill=white)
|
||||||
|
|
||||||
bbox = canvas.getbbox()
|
bbox = canvas.getbbox()
|
||||||
width = bbox[2]-bbox[0]
|
width = bbox[2]-bbox[0]
|
||||||
height = bbox[3]-bbox[1]
|
height = bbox[3]-bbox[1]
|
||||||
|
|
||||||
return width,height
|
return width,height
|
||||||
|
|
||||||
#Draw Ticker, current and change onto one image
|
#Draw Ticker, current and change onto one image
|
||||||
def textToImage(TICKER, CURRENT, CHANGE, ARROW):
|
def textToImage(self, TICKER, CURRENT, CHANGE, ARROW):
|
||||||
font = ImageFont.truetype("EncodeSans.ttf", 18)
|
font = ImageFont.truetype("EncodeSans.ttf", 18)
|
||||||
img = Image.new('RGB', (150, 32))
|
img = Image.new('RGB', (150, 32))
|
||||||
d = ImageDraw.Draw(img)
|
d = ImageDraw.Draw(img)
|
||||||
|
|
||||||
d.text((4, -4), TICKER, fill=(255, 255, 255), font=font)
|
d.text((4, -4), TICKER, fill=(255, 255, 255), font=font)
|
||||||
d.text((4, 13), CURRENT, fill=greenORred, font=font)
|
d.text((4, 13), CURRENT, fill=self.greenORred, font=font)
|
||||||
|
|
||||||
text_width_current, text_height = get_text_dimensions(CURRENT, font)
|
text_width_current, text_height = self.get_text_dimensions(CURRENT, font)
|
||||||
|
|
||||||
img.paste(ARROW, ((text_width_current + 9),18))
|
img.paste(ARROW, ((text_width_current + 9),18))
|
||||||
d.text(((text_width_current+29), 13), CHANGE, fill=greenORred, font=font)
|
d.text(((text_width_current+29), 13), CHANGE, fill=self.greenORred, font=font)
|
||||||
|
|
||||||
text_width_change, text_height = get_text_dimensions(CHANGE, font)
|
text_width_change, text_height = self.get_text_dimensions(CHANGE, font)
|
||||||
|
|
||||||
newWidth = (text_width_current+29) + (text_width_change)
|
newWidth = (text_width_current+29) + (text_width_change)
|
||||||
|
|
||||||
img.crop((0,0,newWidth,32))
|
img.crop((0,0,newWidth,32))
|
||||||
return img
|
return img
|
||||||
|
|
||||||
#Stitch the logo & prices picture into one image
|
#Stitch the logo & prices picture into one image
|
||||||
def stitchImage(IMAGES):
|
def stitchImage(self, IMAGES):
|
||||||
widths, heights = zip(*(i.size for i in IMAGES))
|
widths, heights = zip(*(i.size for i in IMAGES))
|
||||||
total_width = sum(widths)
|
total_width = sum(widths)
|
||||||
max_height = max(heights)
|
max_height = max(heights)
|
||||||
new_im = Image.new('RGB', (total_width, max_height))
|
new_im = Image.new('RGB', (total_width, max_height))
|
||||||
x_offset = 0
|
x_offset = 0
|
||||||
for im in IMAGES[0:2]:
|
for im in IMAGES[0:2]:
|
||||||
new_im.paste(im, (x_offset,0))
|
new_im.paste(im, (x_offset,0))
|
||||||
x_offset += im.size[0]
|
x_offset += im.size[0]
|
||||||
return new_im
|
return new_im
|
||||||
|
|
||||||
#Display the image onto the matrix
|
#Display the image onto the matrix
|
||||||
def displayImage(IMAGE):
|
def displayImage(self, IMAGE):
|
||||||
print('k')
|
print('k')
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
#Get current prices and day prices for the ticker then format the response into an array
|
#Get current prices and day prices for the ticker then format the response into an array
|
||||||
def getStockPrices(APIKEY, SYMBOLS):
|
def getStockPrices(self, APIKEY, SYMBOLS):
|
||||||
global ApiCalledError
|
|
||||||
try:
|
try:
|
||||||
symbols_list = SYMBOLS.split(",")
|
symbols_list = SYMBOLS.split(",")
|
||||||
td = TDClient(apikey=APIKEY)
|
td = TDClient(apikey=APIKEY)
|
||||||
tmin = td.time_series(symbol=SYMBOLS, interval="1min", outputsize='1').as_json()
|
tmin = td.time_series(symbol=SYMBOLS, interval="1min", outputsize='1').as_json()
|
||||||
tday = td.time_series(symbol=SYMBOLS, interval="1day", outputsize='2').as_json()
|
tday = td.time_series(symbol=SYMBOLS, interval="1day", outputsize='2').as_json()
|
||||||
for i in range(len(symbols_list)):
|
for i in range(len(symbols_list)):
|
||||||
currentMinPriceList = tmin[symbols_list[i]]
|
currentMinPriceList = tmin[symbols_list[i]]
|
||||||
currentDayPriceList = list(tday[symbols_list[i]])
|
currentDayPriceList = list(tday[symbols_list[i]])
|
||||||
del currentDayPriceList[0]
|
del currentDayPriceList[0]
|
||||||
currentMinPriceClose = tmin[symbols_list[i]][0]['close']
|
currentMinPriceClose = tmin[symbols_list[i]][0]['close']
|
||||||
currentDayPriceClose = currentDayPriceList[0]['close']
|
currentDayPriceClose = currentDayPriceList[0]['close']
|
||||||
retrievedList.append([])
|
self.retrievedList.append([])
|
||||||
retrievedList[i].append(symbols_list[i])
|
self.retrievedList[i].append(symbols_list[i])
|
||||||
retrievedList[i].append(currentMinPriceClose)
|
self.retrievedList[i].append(currentMinPriceClose)
|
||||||
retrievedList[i].append(currentDayPriceClose)
|
self.retrievedList[i].append(currentDayPriceClose)
|
||||||
except:
|
except:
|
||||||
ApiCalledError = True
|
self.ApiCalledError = True
|
||||||
print("Could not fetch data - API CALLS REACHED? - Will display old image")
|
print("Could not fetch data - API CALLS REACHED? - Will display old image")
|
||||||
|
|
||||||
#Connect all the pieces togeather creating 1 long final stock image
|
#Connect all the pieces togeather creating 1 long final stock image
|
||||||
def GetfullStockImage():
|
def GetfullStockImage(self):
|
||||||
global ListStocks
|
|
||||||
global retrievedList
|
|
||||||
global ApiCalledError
|
|
||||||
ApiCalledError = False
|
|
||||||
ListStocks = []
|
|
||||||
retrievedList = []
|
|
||||||
start = time.time()
|
|
||||||
print('elapsed time: ' + str((time.time()-start)))
|
|
||||||
j=0
|
|
||||||
while (j<3):
|
|
||||||
print('API KEY: ' + str(ApiKeys[keySwapper][j]))
|
|
||||||
|
|
||||||
getStockPrices(ApiKeys[keySwapper][j], symbols[(j+parseCSV)][0])
|
self.ApiCalledError = False
|
||||||
|
self.ListStocks = []
|
||||||
|
self.retrievedList = []
|
||||||
|
start = time.time()
|
||||||
|
print('elapsed time: ' + str((time.time()-start)))
|
||||||
|
j=0
|
||||||
|
while (j<3):
|
||||||
|
print('API KEY: ' + str(self.ApiKeys[self.keySwapper][j]))
|
||||||
|
|
||||||
if (ApiCalledError == False):
|
self.getStockPrices(self.ApiKeys[self.keySwapper][j], self.symbols[(j+self.parseCSV)][0])
|
||||||
j+=1
|
|
||||||
print('elapsed time after api call: ' + str((time.time()-start)))
|
|
||||||
for i in range(len(retrievedList)):
|
|
||||||
print('elapsed timethrough loop: ' + str((time.time()-start)))
|
|
||||||
Change = float(retrievedList[i][1])-float(retrievedList[i][2]) #TEXT
|
|
||||||
Ticker = retrievedList[i][0] #TEXT
|
|
||||||
Current = '%.2f' % float(retrievedList[i][1]) #TEXT
|
|
||||||
|
|
||||||
Logo = getLogo(retrievedList[i][0])
|
if (self.ApiCalledError == False):
|
||||||
Arrow, Change = getArrow(Change)
|
j+=1
|
||||||
Change = '%.2f' % Change
|
print('elapsed time after api call: ' + str((time.time()-start)))
|
||||||
MidFrame = textToImage(Ticker, Current, Change, Arrow) #IMAGE THE TEXT
|
for i in range(len(self.retrievedList)):
|
||||||
|
print('elapsed timethrough loop: ' + str((time.time()-start)))
|
||||||
|
Change = float(self.retrievedList[i][1])-float(self.retrievedList[i][2]) #TEXT
|
||||||
|
Ticker = self.retrievedList[i][0] #TEXT
|
||||||
|
Current = '%.2f' % float(self.retrievedList[i][1]) #TEXT
|
||||||
|
|
||||||
StitchedStock = stitchImage([Logo,MidFrame])
|
Logo = self.getLogo(self.retrievedList[i][0])
|
||||||
ListStocks.append(blank)
|
Arrow, Change = self.getArrow(Change)
|
||||||
ListStocks.append(StitchedStock)
|
Change = '%.2f' % Change
|
||||||
retrievedList = []
|
MidFrame = self.textToImage(Ticker, Current, Change, Arrow) #IMAGE THE TEXT
|
||||||
else:
|
|
||||||
break
|
|
||||||
|
|
||||||
print('elapsed time loop ended: ' + str((time.time()-start)))
|
StitchedStock = self.stitchImage([Logo,MidFrame])
|
||||||
if (ApiCalledError == False):
|
self.ListStocks.append(self.blank)
|
||||||
FinalDisplayImage = stitchImage(ListStocks)
|
self.ListStocks.append(StitchedStock)
|
||||||
FinalDisplayImage.save('final.ppm')
|
self.retrievedList = []
|
||||||
print(retrievedList)
|
|
||||||
|
|
||||||
#Send the final stitched image to the display for set amount of time
|
|
||||||
def displayMatrix():
|
|
||||||
#os.system("sudo ./demo -D1 final.ppm -t " + str(displayTime) +" -m "+ str(speedDisplay) +" --led-gpio-mapping=adafruit-hat --led-rows=32 --led-cols=256")
|
|
||||||
os.system("sudo ./demo -D1 final.ppm -t " + str(displayTime) +" -m "+ str(speedDisplay) +" --led-gpio-mapping=adafruit-hat --led-rows=64 --led-cols=64")
|
|
||||||
|
|
||||||
#Retrieve symbols from the CSV file
|
|
||||||
def GetSymbols():
|
|
||||||
global symbols
|
|
||||||
symbols = []
|
|
||||||
CSV = csv.reader(open('csv/tickers.csv', 'r'))
|
|
||||||
z = 0
|
|
||||||
for row in CSV:
|
|
||||||
symbols.append([])
|
|
||||||
endLine = str(row[0]+','+row[1]+','+row[2]+','+row[3]+','+row[4]+','+row[5]+','+row[6]+','+row[7]+','+row[8]+','+row[9]+','+row[10])
|
|
||||||
symbols[z].append(endLine)
|
|
||||||
z+=1
|
|
||||||
print(symbols)
|
|
||||||
|
|
||||||
#Main run definition called by server
|
|
||||||
def runStockTicker(RUNTIME, DELAY, SPEEDTIME):
|
|
||||||
global keySwapper
|
|
||||||
global running
|
|
||||||
global displayTime
|
|
||||||
global symbolLength
|
|
||||||
global parseCSV
|
|
||||||
global Delay
|
|
||||||
global speedDisplay
|
|
||||||
|
|
||||||
parseCSV = 0
|
|
||||||
Delay = DELAY
|
|
||||||
displayTime = RUNTIME
|
|
||||||
speedDisplay = SPEEDTIME
|
|
||||||
GetSymbols()
|
|
||||||
symbolLength = (len(symbols) - 3)
|
|
||||||
GetfullStockImage()
|
|
||||||
keySwapper += 1
|
|
||||||
running = True
|
|
||||||
parseCSV += 3
|
|
||||||
|
|
||||||
while (True):
|
|
||||||
if (running == True):
|
|
||||||
if (keySwapper<=1):
|
|
||||||
if(parseCSV <= symbolLength):
|
|
||||||
th = threading.Thread(target=displayMatrix)
|
|
||||||
th.start()
|
|
||||||
#displayMatrix()
|
|
||||||
time.sleep((int(displayTime) - int(Delay)))
|
|
||||||
GetfullStockImage()
|
|
||||||
keySwapper += 1
|
|
||||||
th.join()
|
|
||||||
parseCSV += 3
|
|
||||||
else:
|
|
||||||
parseCSV = 0
|
|
||||||
else:
|
else:
|
||||||
keySwapper = 0
|
break
|
||||||
else:
|
|
||||||
break;
|
|
||||||
|
|
||||||
#Change running to false stopping refresh at next checkpoint
|
print('elapsed time loop ended: ' + str((time.time()-start)))
|
||||||
def stopStockTicker():
|
if (self.ApiCalledError == False):
|
||||||
global running
|
FinalDisplayImage = self.stitchImage(self.ListStocks)
|
||||||
global keySwapper
|
FinalDisplayImage.save('final.ppm')
|
||||||
keySwapper = 0
|
print(self.retrievedList)
|
||||||
running = False
|
|
||||||
print('MATRIX DISPLAY STOP CALLED')
|
#Send the final stitched image to the display for set amount of time
|
||||||
|
def displayMatrix(self):
|
||||||
|
#os.system("sudo ./demo -D1 final.ppm -t " + str(displayTime) +" -m "+ str(speedDisplay) +" --led-gpio-mapping=adafruit-hat --led-rows=32 --led-cols=256")
|
||||||
|
os.system("sudo ./demo -D1 final.ppm -t " + str(self.displayTime) +" -m "+ str(self.speedDisplay) +" --led-gpio-mapping=adafruit-hat --led-rows=64 --led-cols=64 --led-slowdown-gpio=4 ")
|
||||||
|
|
||||||
|
#Retrieve symbols from the CSV file
|
||||||
|
def GetSymbols(self):
|
||||||
|
|
||||||
|
self.symbols = []
|
||||||
|
CSV = csv.reader(open('csv/tickers.csv', 'r'))
|
||||||
|
z = 0
|
||||||
|
for row in CSV:
|
||||||
|
self.symbols.append([])
|
||||||
|
endLine = str(row[0]+','+row[1]+','+row[2]+','+row[3]+','+row[4]+','+row[5]+','+row[6]+','+row[7]+','+row[8]+','+row[9]+','+row[10])
|
||||||
|
self.symbols[z].append(endLine)
|
||||||
|
z+=1
|
||||||
|
|
||||||
|
print(self.symbols)
|
||||||
|
|
||||||
|
#Main run definition called by server
|
||||||
|
def runStockTicker(self, RUNTIME, DELAY, SPEEDTIME):
|
||||||
|
|
||||||
|
self.parseCSV = 0
|
||||||
|
self.Delay = DELAY
|
||||||
|
self.displayTime = RUNTIME
|
||||||
|
self.speedDisplay = SPEEDTIME
|
||||||
|
self.GetSymbols()
|
||||||
|
self.symbolLength = (len(self.symbols) - 3)
|
||||||
|
self.GetfullStockImage()
|
||||||
|
self.keySwapper += 1
|
||||||
|
self.running = True
|
||||||
|
self.parseCSV += 3
|
||||||
|
|
||||||
|
while (True):
|
||||||
|
if (self.running == True):
|
||||||
|
if (self.keySwapper<=1):
|
||||||
|
if(self.parseCSV <= self.symbolLength):
|
||||||
|
th = threading.Thread(target=self.displayMatrix)
|
||||||
|
th.start()
|
||||||
|
#displayMatrix()
|
||||||
|
time.sleep((int(self.displayTime) - int(self.Delay)))
|
||||||
|
self.GetfullStockImage()
|
||||||
|
self.keySwapper += 1
|
||||||
|
th.join()
|
||||||
|
self.parseCSV += 3
|
||||||
|
else:
|
||||||
|
self.parseCSV = 0
|
||||||
|
else:
|
||||||
|
self.keySwapper = 0
|
||||||
|
else:
|
||||||
|
break;
|
||||||
|
|
||||||
|
#Change running to false stopping refresh at next checkpoint
|
||||||
|
def stopStockTicker(self):
|
||||||
|
|
||||||
|
self.keySwapper = 0
|
||||||
|
self.running = False
|
||||||
|
print('MATRIX DISPLAY STOP CALLED')
|
||||||
|
BIN
stockTicker.pyc
BIN
stockTicker.pyc
Binary file not shown.
Loading…
Reference in New Issue
Block a user