diff --git a/csv/GIF_settings.json b/csv/GIF_settings.json index 1386e94..09ecce7 100644 --- a/csv/GIF_settings.json +++ b/csv/GIF_settings.json @@ -1 +1 @@ -{"speed": "medium", "animation": "continuous", "title": true, "pause": "", "images": ["open.gif"]} \ No newline at end of file +{"speed": "medium", "animation": "continuous", "title": true, "pause": "", "images": ["open.gif", "close.gif"]} \ No newline at end of file diff --git a/csv/display_settings.json b/csv/display_settings.json index 1ed1427..43da6fc 100755 --- a/csv/display_settings.json +++ b/csv/display_settings.json @@ -1 +1 @@ -["Custom Images"] \ No newline at end of file +["Custom Messages"] \ No newline at end of file diff --git a/csv/message_settings.json b/csv/message_settings.json new file mode 100644 index 0000000..03906d3 --- /dev/null +++ b/csv/message_settings.json @@ -0,0 +1 @@ +{"feature": "Custom Messages", "speed": "Medium", "animation": "Continuous", "title": true, "messages": [{"name": "1", "text": "123", "text_colour": "White", "size": "Medium", "background_colour": "Black"}, {"name": "13", "text": "123", "text_colour": "Red", "size": "Medium", "background_colour": "Purple"}]} \ No newline at end of file diff --git a/display_images/Current Weather.ppm b/display_images/Current Weather.ppm index 4dacfbc..eaa060e 100755 Binary files a/display_images/Current Weather.ppm and b/display_images/Current Weather.ppm differ diff --git a/display_images/Daily Forecast.ppm b/display_images/Daily Forecast.ppm index 9f04418..77ae5be 100755 Binary files a/display_images/Daily Forecast.ppm and b/display_images/Daily Forecast.ppm differ diff --git a/log.txt b/log.txt index f74d4c2..e69de29 100755 --- a/log.txt +++ b/log.txt @@ -1,17 +0,0 @@ -[Errno 2] No such file or directory: '/home/pi/Desktop/stock_ticker/XOM.png'. file: stockTicker.py. line: 2230. type: - Traceback (most recent call last): - File "stockTicker.py", line 2230, in - stock_ticker.process_msg(msg) - File "stockTicker.py", line 2194, in process_msg - self.scrollFunctionsAnimated(userSettings, animation = 'down') - File "stockTicker.py", line 309, in scrollFunctionsAnimated - self.updateMultiple([options[0]]) - File "stockTicker.py", line 276, in updateMultiple - img = self.functions[option]() - File "stockTicker.py", line 1953, in getUserImage - image = self.openImage(os.path.join(os.path.dirname(os.path.abspath(__file__)), image)) - File "stockTicker.py", line 76, in openImage - image = Image.open(image_file) - File "/usr/lib/python3/dist-packages/PIL/Image.py", line 2634, in open - fp = builtins.open(filename, "rb") -FileNotFoundError: [Errno 2] No such file or directory: '/home/pi/Desktop/stock_ticker/XOM.png' diff --git a/server.py b/server.py index 5fd3e68..e639fe4 100644 --- a/server.py +++ b/server.py @@ -365,6 +365,9 @@ def feature_settings(): elif feature in ['Custom GIFs', 'Custom Images']: save_image_settings(input_settings) + elif feature == 'Custom Messages': + save_message_settings(input_settings) + return index() # saves files uploaded to the webpage for images and GIFs @@ -503,7 +506,10 @@ def save_image_settings(input_settings): del current_settings['feature'] json.dump(current_settings, open('csv/' + filename, 'w+')) - +def save_message_settings(input_settings): + + json.dump(input_settings, open('csv/message_settings.json', 'w+')) + @app.route("/stop") def stop(): print('stop') diff --git a/static/app.js b/static/app.js index ac3347a..a40cd4e 100644 --- a/static/app.js +++ b/static/app.js @@ -489,26 +489,7 @@ var allFeaturesFileAddBtn = [ -var uploaded_images = []; -var uploaded_GIFs = []; -allFeaturesFileAddBtn.map((value, index) => { - if (value !== null) { - value.addEventListener("click", () => { - var tag = document.createElement("li"); - tag.innerHTML = allFeaturesFile[index].files[0].name; - if (index == 10) { - uploaded_images.push(allFeaturesFile[index].files[0]); - } else if (index == 11) { - uploaded_GIFs.push(allFeaturesFile[index].files[0]); - } - - allFeatures[index].appendChild(tag); - changeVarValue(); - addEventOnFeaturesList(); - }); - } -}); // features input text var stocksText = document.getElementById("inputText3"); @@ -724,7 +705,7 @@ function saveSettings() { method:"POST", body:data }); - } + } } let saveSettingsButtons = document.querySelectorAll(".save-btn-div").forEach(button => @@ -801,6 +782,29 @@ function getSportsSettings(page){ return settings; } + +var uploaded_images = []; +var uploaded_GIFs = []; + +allFeaturesFileAddBtn.map((value, index) => { + if (value !== null) { + value.addEventListener("click", () => { + var tag = document.createElement("li"); + tag.innerHTML = allFeaturesFile[index].files[0].name; + if (index == 10) { + uploaded_images.push(allFeaturesFile[index].files[0]); + } else if (index == 11) { + uploaded_GIFs.push(allFeaturesFile[index].files[0]); + } + + allFeatures[index].appendChild(tag); + changeVarValue(); + addEventOnFeaturesList(); + }); + } +}); + + //images and GIFs function getImageSettings(page){ let pause = page.querySelectorAll(".pause-select")[0].value; @@ -814,8 +818,48 @@ function getImageSettings(page){ return settings; } -function getMessageSettings(page) { + +var messages = []; + + +messagesTextAddBtn.addEventListener("click", () => { + let pageSelector = "Page13"; + let page = document.getElementById(pageSelector); + + + let msg_name = messagesText.value; + //let speed = getSelected(page.querySelectorAll(".speed-select")[0]); + //let animation = getSelected(page.querySelectorAll(".animation-select")[0]); + + let message_text = page.querySelectorAll(".message-input")[0].value; + let text_colour = getSelected(page.querySelectorAll(".text-colour")[0]); + let text_size = getSelected(page.querySelectorAll(".text-size")[0]); + let background_colour = getSelected(page.querySelectorAll(".back-colour")[0]); + + let message = {'name':msg_name, 'text':message_text, 'text_colour':text_colour, 'size':text_size, 'background_colour':background_colour}; + messages.push(message); + + +}); + + + +function getMessageSettings(page) { + + let messages_el = page.querySelectorAll(".message-list")[0]; + let message_names = getListItems(messages_el); + + //remove any messages that arent in the list + let new_messages = []; + + for (let i = 0; i < messages.length; i++){ + if (message_names.includes(messages[i]['name'])) { + new_messages.push(messages[i]); + } + } + let title = page.querySelectorAll(".title-select")[0].checked; + return {'title':title, 'messages':new_messages}; } diff --git a/stockTicker.py b/stockTicker.py index 5a8a9da..bdb175e 100644 --- a/stockTicker.py +++ b/stockTicker.py @@ -45,7 +45,7 @@ class StockTicker(): self.blank = Image.new('RGB', (10, 32)) self.running = True self.brightness = 1.0 - self.delay = 0.02 + # Configuration for the matrix options = RGBMatrixOptions() @@ -62,7 +62,7 @@ class StockTicker(): '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.getUserText, 'Custom Images': self.getUserImage, 'Custom GIFs':self.getUserGIF, + 'News':self.getNewsImage, 'Custom Messages': self.getUserMessages, 'Stocks Prof': self.getStockProfessional, 'Crypto Prof': self.getCryptoProfessional, 'Forex Prof': self.getForexProfessional, @@ -74,6 +74,7 @@ class StockTicker(): 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) @@ -273,9 +274,10 @@ class StockTicker(): def updateMultiple(self, options): for option in options: - img = self.functions[option]() - if option not in ['Custom GIFs']: # aving the gif like this kills the animation + + 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') @@ -317,69 +319,84 @@ class StockTicker(): update_process = Process(target = self.updateMultiple, args = ([options[(i+1) % len(options)]],)) update_process.start() + self.delay = 0.02 + 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() + - if options[i % len(options)] != 'Custom GIFs': + else: #these options just have a single ppm image image = self.openImage('./display_images/' + options[i % len(options)] +'.ppm') - image = image.convert('RGB') - else: - image = self.openImage('./display_images/Custom GIFs.gif') + + images = [image] + - img_width, img_height = image.size - - offset_x = 0 - if animation == 'traditional': - offset_x = 128 - elif animation == 'continuous': + for image in images: + img_width, img_height = image.size + 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(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 animation == 'traditional': + offset_x = 128 + elif animation == 'continuous': + offset_x = 0 + elif animation in ['up', 'down']: + offset_x = max(0, 128-img_width) - 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) + offset_y = 0 + #first scroll image in from bottom - self.double_buffer = self.matrix.SwapOnVSync(self.double_buffer) + + + 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 + - time.sleep(self.delay) - kill = self.checkKilled() if kill: break - - + + if kill: break - - if kill: break - - kill = self.scrollImage(image, offset_x = offset_x, offset_y = offset_y, frame_skip = frame_skip, gif = options[i % len(options)] == 'Custom GIFs') - - if kill: break + kill = self.scrollImage(image, offset_x = offset_x, offset_y = offset_y, frame_skip = frame_skip, gif = options[i % len(options)] == 'Custom GIFs') + + if kill: break + if kill:break update_process.join() i+=1 @@ -458,7 +475,7 @@ class StockTicker(): 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): + def textImage(self, text, font, r = 255, g = 255, b = 255, matrix_height = False, w_buff = 3, h_buff = 3, background = False): ''' creates and returns a ppm image containing the text in the supplied font and colour ''' @@ -469,29 +486,55 @@ class StockTicker(): 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 d.text((0, 0), text, fill=(r, g, b), font=font) return img - def getUserText(self): + def getUserMessages(self): ''' displays the text entered in the webpage by the user. ''' - f = open('csv/scroll_text.csv', 'r') - CSV = csv.reader(f) - text, r, g, b = next(CSV) + f = open('csv/message_settings.json', 'r') + all_settings = json.load(f) f.close() - title_img = self.openImage('feature_titles/message.png') - - font = ImageFont.load("./fonts/texgyre-27.pil") + if all_settings['title']: + title_img = self.openImage('feature_titles/message.png') + imgs = [title_img] + else: + imgs = [] - img = self.textImage(text, font, int(r), int(g), int(b), True, w_buff = 50) - return self.stitchImage([title_img, img]) + 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)} + + for message in all_settings['messages']: + font = ImageFont.load("./fonts/texgyre-27.pil") + 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 = 50, background = background) + + imgs.append(img) + + + return imgs def displayGIF(self, gif): # To iterate through the entire gif @@ -1937,7 +1980,7 @@ class StockTicker(): time.sleep(self.delay*1.1) - def getUserImage(self): + def getUserImages(self): title_img = self.openImage('feature_titles/images.png') @@ -1950,21 +1993,30 @@ class StockTicker(): imgs = [] for image in all_settings['images']: - image = self.openImage(os.path.join(os.path.dirname(os.path.abspath(__file__)), image)) + img = self.openImage(os.path.join(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'user_uploads'), image)) + imgs.append(img) - return self.stitchImage(imgs) - - def getUserGIF(self): - title_img = self.openImage('feature_titles/gifs.png') - - gif = Image.open(os.path.join(os.path.dirname(os.path.abspath(__file__)), all_settings['images'][0])) + return imgs + def getUserGIFs(self): f = open('csv/GIF_settings.json', 'r') all_settings = json.load(f) f.close() + if all_settings['title']: + title_img = self.openImage('feature_titles/gifs.png') + GIFs = [title_img] + else: + GIFs = [] + + for f in all_settings['images']: + GIF = Image.open(os.path.join(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'user_uploads'), f)) + GIFs.append(GIF) + + #below code stitches title and GIF together + ''' frames = [] for i, frame in enumerate(ImageSequence.Iterator(gif)): @@ -1977,9 +2029,9 @@ class StockTicker(): frames[0].save('./display_images/Custom GIFs.gif', save_all=True, append_images=frames[1:], loop=0, optimize = False) - + ''' - return None + return GIFs def displayStocks(self): diff --git a/templates/index.html b/templates/index.html index 809f067..930cd2d 100644 --- a/templates/index.html +++ b/templates/index.html @@ -2301,12 +2301,13 @@ - + +
@@ -2360,10 +2364,15 @@
- + + + + + + + +
@@ -2375,14 +2384,16 @@
-
- + + +
@@ -2405,10 +2417,15 @@
- + + + - - + + + +
@@ -2421,7 +2438,7 @@
    -
  • Custom Message 1
  • -
  • Custom Message 1
  • -
  • Custom Message 1
  • - -
  • Custom Message 1
  • -
  • Custom Message 1
  • -
  • Custom Message 1
  • - -
  • Custom Message 1
  • -
  • Custom Message 1
  • -
  • Custom Message 1
  • - -
  • Custom Message 1
  • -
  • Custom Message 1
  • -
  • Custom Message 1
  • + +
diff --git a/user_uploads/close.gif b/user_uploads/close.gif new file mode 100644 index 0000000..1eadae4 Binary files /dev/null and b/user_uploads/close.gif differ