import sys import time from math import ceil import numpy as np import requests from bdfparse import Font from keys import IEX_TOKEN from rgbmatrix import RGBMatrix, RGBMatrixOptions, graphics font_file = "matrix\\fonts\\9x15.bdf" font = Font(font_file) matrix_shape = (16, 32) # rows, cols symbols = ["tsla", "psec", "aapl"] options = RGBMatrixOptions() options.chain_length = 1 options.parallel = 1 options.hardware_mapping = "regular" options.rows, options.cols = matrix_shape red = (255, 51, 51) green = (51, 255, 51) white = (255, 255, 255) blank = np.zeros((matrix_shape[0], matrix_shape[1], 3)) def stockMatrix(symbols: list, matrix=blank): array = blank for symbol in symbols: message, color = symbolData(symbol) mess_arr = matrix_message(message, color, matrix_shape[0]) array = np.concatenate((array, mess_arr), axis=1) return array def symbolData(symbol: str): """ Takes a list of symbol and returns a dictionary of strings with information about the symbol. """ IEXurl = "https://cloud.iexapis.com/stable/stock/{symbol}/quote?token={IEX}".format( symbol=symbol, IEX=IEX_TOKEN ) response = requests.get(IEXurl) if response.status_code is 200: IEXData = response.json() message = "The current stock price of {name} is {price}".format( name=IEXData["companyName"], price=IEXData["latestPrice"] ) # Determine wording of change text change = round(IEXData["changePercent"] * 100, 2) if change > 0: message += ", the stock is currently up {change}% ".format(change=change) color = green elif change < 0: message += ", the stock is currently down {change}% ".format(change=change) color = red else: message += ", the stock hasn't shown any movement today." color = white else: message = "The symbol: {symbol} was not found. ".format(symbol=symbol) color = white return (message, color) def matrix_message(message, color, rows): message_arr = fit_array(font.word(message), rows) r = np.multiply(np.full(message_arr.shape, color[0]), message_arr) g = np.multiply(np.full(message_arr.shape, color[1]), message_arr) b = np.multiply(np.full(message_arr.shape, color[2]), message_arr) array = np.zeros((message_arr.shape[0], message_arr.shape[1], 3), dtype=int) array[:, :, 0] = np.add(array[:, :, 0], r) array[:, :, 1] = np.add(array[:, :, 1], g) array[:, :, 2] = np.add(array[:, :, 2], b) return array def fit_array(array, rows, operation="centered", fill_value=0): rows = rows - array.shape[0] cols = array.shape[1] offset = (rows, cols) if operation is "centered": top = ceil(rows / 2) top_fill = np.full((top, cols), fill_value) bottom = rows // 2 bottom_fill = np.full((bottom, cols), fill_value) return np.concatenate((top_fill, array, bottom_fill), axis=0) elif operation is "top": fill = np.full(offset, fill_value) return np.concatenate((fill, array), axis=0) elif operation is "bottom": fill = np.full(offset, fill_value) return np.concatenate((array, fill), axis=0) else: raise Exception("Invalid Operation. Must be either centered, top, or bottom.") def run(matrix_message): matrix = RGBMatrix(options=options) canvas = matrix.CreateFrameCanvas() for row in range(matrix_shape[0]): for col in range(matrix_shape[1]): r = matrix_message[row, col, 0] g = matrix_message[row, col, 1] b = matrix_message[row, col, 2] canvas.SetPixel(row, col, r, g, b) canvas = matrix.SwapOnVSync(canvas) time.sleep(1) try: print("Press CTRL-C to stop.") matrix = stockMatrix(symbols) while True: run(matrix) matrix = matrix[:, 1:, :] if matrix.shape[1] < matrix_shape[1]: new_matrix = stockMatrix(symbols) matrix = np.concatenate((matrix, new_matrix), axis=1) except KeyboardInterrupt: sys.exit(0)