Skip to content

Instantly share code, notes, and snippets.

@chubbyemu
Last active October 11, 2023 15:31
Show Gist options
  • Save chubbyemu/4ca0c68878c6d978d067da4a36bcc71d to your computer and use it in GitHub Desktop.
Save chubbyemu/4ca0c68878c6d978d067da4a36bcc71d to your computer and use it in GitHub Desktop.
# THIS SCRIPT USES THE LIBRARY AT:
# https://github.com/hzeller/rpi-rgb-led-matrix
# BE SURE TO CLONE IT AND READ THE README, as highlighted in the video :)
import os, time, threading, random
import feedparser
from PIL import Image, ImageFont, ImageDraw
from random import shuffle
BITLY_ACCESS_TOKEN="BITLY_ACCESS_TOKEN"
items=[]
displayItems=[]
feeds=[
#enter all news feeds you want here
"http://www.fda.gov/AboutFDA/ContactFDA/StayInformed/RSSFeeds/PressReleases/rss.xml",
"http://www.fiercepharma.com/feed",
"http://www.fiercebiotech.com/feed",
]
def colorRed():
return (255, 0, 0)
def colorGreen():
return (0, 255, 0)
def colorBlue():
return (0, 0, 255)
def colorRandom():
return (random.randint(0,255), random.randint(0,255), random.randint(0,255))
def populateItems():
#first clear out everything
del items[:]
del displayItems[:]
#delete all the image files
os.system("find . -name \*.ppm -delete")
for url in feeds:
feed=feedparser.parse(url)
posts=feed["items"]
for post in posts:
items.append(post)
shuffle(items)
def createLinks():
try:
populateItems()
for idx, item in enumerate(items):
writeImage(unicode(item["title"]), idx)
except ValueError:
print("Bummer :( I couldn't make you 'dem links :(")
finally:
print("\nWill get more news next half hour!\n\n")
def writeImage(url, count):
bitIndex=0
link, headLine="", url[:]
def randCol(index = -1):
if index % 3 == 0:
return colorRed()
elif index % 3 == 1:
return colorGreen()
elif index % 3 == 2:
return colorBlue()
else:
return colorRandom()
text = ((headLine, randCol(count)), (link, colorRandom()))
font = ImageFont.truetype("/usr/share/fonts/truetype/freefont/FreeSans.ttf", 16)
all_text = ""
for text_color_pair in text:
t = text_color_pair[0]
all_text = all_text + t
width, ignore = font.getsize(all_text)
im = Image.new("RGB", (width + 30, 16), "black")
draw = ImageDraw.Draw(im)
x = 0;
for text_color_pair in text:
t = text_color_pair[0]
c = text_color_pair[1]
draw.text((x, 0), t, c, font=font)
x = x + font.getsize(t)[0]
filename=str(count)+".ppm"
displayItems.append(filename)
im.save(filename)
def run():
print("News Fetched at {}\n".format(time.ctime()))
createLinks()
threading.Timer(len(items) * 60, run).start()
showOnLEDDisplay()
def showOnLEDDisplay():
for disp in displayItems[:60]:
os.system("sudo ./led-matrix -r 16 -c 3 -t 60 -m 25 -D 1 "+disp)
if __name__ == '__main__':
run()
@ahostn
Copy link

ahostn commented Sep 7, 2016

There's something wrong with the code... it only runs fine for the first time and then eventually freezes,

`News Fetched at Wed Sep 7 15:12:24 2016

Will get more news next half hour!

Read image '0.ppm' with 843x32
Read image '1.ppm' with 1275x32
Read image '2.ppm' with 825x32
Read image '3.ppm' with 1119x32
Read image '4.ppm' with 1481x32
Read image '5.ppm' with 1009x32
Read image '6.ppm' with 1717x32
Read image '7.ppm' with 1223x32
Read image '8.ppm' with 1065x32
Read image '9.ppm' with 1265x32
Read image '10.ppm' with 835x32
Read image '11.ppm' with 714x32
Read image '12.ppm' with 1183x32
Read image '13.ppm' with 832x32
Read image '14.ppm' with 1404x32
Read image '15.ppm' with 892x32
Read image '16.ppm' with 859x32
Read image '17.ppm' with 1196x32
Read image '18.ppm' with 1042x32
Read image '19.ppm' with 733x32
News Fetched at Wed Sep 7 15:32:26 2016

Will get more news next half hour!

Read image '0.ppm' with 1196x32
Read image '1.ppm' with 1223x32
Read image '2.ppm' with 1183x32
Read image '3.ppm' with 1009x32
Read image '4.ppm' with 548x32
Read image '5.ppm' with 733x32
Read image '6.ppm' with 1404x32
Read image '7.ppm' with 1042x32
Read image '8.ppm' with 1481x32
Read image '9.ppm' with 835x32
Read image '10.ppm' with 1275x32
Read image '11.ppm' with 714x32
Read image '12.ppm' with 832x32
Read image '13.ppm' with 1065x32
Read image '14.ppm' with 725x32
Read image '15.ppm' with 843x32
Read image '16.ppm' with 1265x32
Read image '17.ppm' with 892x32
Read image '18.ppm' with 1552x32
Read image '19.ppm' with 825x32
News Fetched at Wed Sep 7 15:52:28 2016

Will get more news next half hour!

Read image '0.ppm' with 1065x32
Read image '1.ppm' with 1183x32
Read image '2.ppm' with 1481x32
Read image '3.ppm' with 832x32
Read image '4.ppm' with 843x32
Read image '5.ppm' with 1009x32
Read image '6.ppm' with 1196x32
Read image '7.ppm' with 1223x32
Read image '8.ppm' with 1275x32
Read image '9.ppm' with 725x32
Read image '10.ppm' with 1404x32
Read image '11.ppm' with 835x32
Read image '12.ppm' with 714x32
Read image '13.ppm' with 548x32
Read image '14.ppm' with 892x32
Read image '15.ppm' with 1042x32
Read image '16.ppm' with 1552x32
Read image '17.ppm' with 1265x32
Read image '18.ppm' with 1047x32
Read image '19.ppm' with 825x32
News Fetched at Wed Sep 7 16:12:30 2016

Will get more news next half hour!

Read image '0.ppm' with 1275x32
Read image '1.ppm' with 1481x32
Read image '2.ppm' with 714x32
Read image '3.ppm' with 825x32
Read image '4.ppm' with 1065x32
Read image '5.ppm' with 1042x32
Read image '6.ppm' with 843x32
Read image '7.ppm' with 1009x32
Read image '8.ppm' with 835x32
Read image '9.ppm' with 1047x32
Read image '10.ppm' with 1196x32
Read image '11.ppm' with 1782x32
Read image '12.ppm' with 1183x32
Read image '13.ppm' with 892x32
Read image '14.ppm' with 725x32
Read image '15.ppm' with 1404x32
Read image '16.ppm' with 832x32
Read image '17.ppm' with 548x32
Read image '18.ppm' with 1223x32
Read image '19.ppm' with 1552x32
News Fetched at Wed Sep 7 16:32:32 2016

Will get more news next half hour!

Read image '0.ppm' with 1275x32
Read image '1.ppm' with 843x32
Read image '2.ppm' with 1552x32
Read image '3.ppm' with 1042x32
Read image '4.ppm' with 832x32
Read image '5.ppm' with 1782x32
Read image '6.ppm' with 892x32
Read image '7.ppm' with 714x32
Read image '8.ppm' with 1223x32
Read image '9.ppm' with 1404x32
Read image '10.ppm' with 825x32
Read image '11.ppm' with 1065x32
Read image '12.ppm' with 1196x32
Read image '13.ppm' with 1411x32
Read image '14.ppm' with 548x32
Read image '15.ppm' with 1009x32
Read image '16.ppm' with 1039x32
Read image '17.ppm' with 1047x32
Read image '18.ppm' with 725x32
Read image '19.ppm' with 835x32
News Fetched at Wed Sep 7 16:52:34 2016

Will get more news next half hour!

Read image '0.ppm' with 1411x32
Read image '1.ppm' with 1837x32
Read image '2.ppm' with 1042x32
Read image '3.ppm' with 835x32
Read image '4.ppm' with 1009x32
Read image '5.ppm' with 1065x32
Read image '6.ppm' with 1017x32
Read image '7.ppm' with 1047x32
Read image '8.ppm' with 725x32
Read image '9.ppm' with 1039x32
Read image '10.ppm' with 1223x32
Read image '11.ppm' with 832x32
Read image '12.ppm' with 1374x32
Read image '13.ppm' with 892x32
Read image '14.ppm' with 825x32
Read image '15.ppm' with 1257x32
Read image '16.ppm' with 1275x32
Read image '17.ppm' with 1196x32
Read image '18.ppm' with 1552x32
Read image '19.ppm' with 548x32
News Fetched at Wed Sep 7 17:12:36 2016

Will get more news next half hour!

Read image '0.ppm' with 832x32
News Fetched at Wed Sep 7 17:32:38 2016

Will get more news next half hour!

Read image '0.ppm' with 697x32
News Fetched at Wed Sep 7 17:52:39 2016

Will get more news next half hour!

Read image '0.ppm' with 835x32
News Fetched at Wed Sep 7 18:12:41 2016

Will get more news next half hour!

Read image '0.ppm' with 1344x32
News Fetched at Wed Sep 7 18:32:42 2016

Will get more news next half hour!

Read image '0.ppm' with 1275x32
News Fetched at Wed Sep 7 18:52:44 2016

Will get more news next half hour!

Read image '0.ppm' with 739x32
News Fetched at Wed Sep 7 19:12:51 2016

Will get more news next half hour!

Read image '0.ppm' with 814x32
`
The time now is 21:14 and the script is completely blocked. All called led-matrix processes are still active, so the quick fix would be to killall led-matrix processes before running new one. I don't know why these processes don't quit by themselves, I guess there's some glitch in the matrix :)

@moefarah
Copy link

Hello, I was wondering if I were to use the 32 X 32 adafruit panel, Would I only need to modify line #77 im = Image.new("RGB", (width + 30, 16), "black") with the correct dimentions? (say 30x30)?

Thanks in advance. I think this project is amazing!

@glennh65
Copy link

glennh65 commented Jun 5, 2017

Hey there. I am so excited about this project. Need help please. When I run the revision dated Aug 6, 2016 it returns the following:

News Fetched at Mon Jun 5 19:47:38 2017

Will get more news next half hour!

Traceback (most recent call last):
File "rssparse.py", line 96, in
run()
File "rssparse.py", line 87, in run
createLinks()
File "rssparse.py", line 48, in createLinks
writeImage(unicode(item["title"]), idx)
File "rssparse.py", line 67, in writeImage
font = ImageFont.truetype("/usr/share/fonts/truetype/freefont/FreeSans.ttf",16)
File "/usr/local/lib/python2.7/dist-packages/PIL/ImageFont.py", line 238, in truetype
return FreeTypeFont(font, size, index, encoding)
File "/usr/local/lib/python2.7/dist-packages/PIL/ImageFont.py", line 127, in __init__self.font = core.getfont(font, size, index, encoding)
IOError: cannot open resource

@Spazmic
Copy link

Spazmic commented Jun 27, 2017

@glennh65

Hey Glenn I had the same issue as you but I think I found the reason! It is in this line

font = ImageFont.truetype("/usr/share/fonts/truetype/freefont/FreeSans.ttf",16)

You will see that this path doesn't exist so it doesn't find the font. I think this is due to the fact that PIL is deprecated and was replaced by pillow. So I simply downloaded that font, put it in the font folder of the rpi-rgb-led-matrix and I changed the path in the code. I do not have this error anymore. Hope I helped you...

@charlie-gray
Copy link

How would I do this with a 16 x 24 red LED panel?

@hzeller
Copy link

hzeller commented Jan 9, 2018

Instead of taking the detour of first creating images and then invoking the ./demo program with it, I suggest to adapt the code in bindings/python/samples/runtext.py which allows to directly write text natively from Python.

@Dougybutt
Copy link

How would I adapt this for 3 64x16 dot Matrix LEDs so a width of 192 by 16 high. Are you available to tutor somebody with bigger ambitions than ability - how much would you charge per hour.

@sleep-sort
Copy link

sleep-sort commented Dec 7, 2020

I have been working to implement this in python 3 since feedparser no longer supports python 2 and have been running into a few issues.

  1. We have to update line 51 from using the old 'unicode' to 'str' - this solves the issue
  2. the LED matrix api throws an error (currently working to sort this out now). The error is: "This program moved to directory examples-api-use/ and is called 'demo'" which I'm having trouble sorting out where in the code it's invoking "Demo" but I haven't looked very long.. - this is something I'm still trying to fix, see below line break
  3. I'm anticipating running into the font issue shortly after I get through issue number 2, but will hopefully be able to solve that by downloading the missing PIL fonts - this did not end up being an issue for me!
    Anyways, thanks for the video, it has been incredibly helpful to follow as my first raspberry pi project!

Coming back to this a little later, I've found the line that's giving me the issues in problem number 2. /lex-matrix appears to no longer be supported by the led matrix project. it has been moved to /demo. so I changed the line:
os.system("sudo ./led-matrix -r 16 -c 3 -t 60 -m 25 -D 1 "+disp) to
os.system("sudo ./demo -r 16 -c 3 -t 60 -m 25 -D 1 "+disp) and then to
os.system("sudo ./demo -D 1 "+disp) [this last line works finally, although creates new issues summarized below]

I also moved the rssparser.py into the /examples-api-use

Unfortunately it appears '-r 16 -c 3 -t 60 -m 25' are no longer valid parameters. So it "works" but is obviously half printing off the screen..


on a side note, hzeller's comment is now making more sense to me. generating all the images and then looping through seems more inefficient than just using runtext.py although i'm nowhere near proficient enough in python to write this modified script yet -

@jax200
Copy link

jax200 commented Dec 20, 2020

I was able to get this to work, albeit it is not automatically changing feeds (and colors). Curiously, it will change feeds if I invoke Ctrl-C. So don't know how to fix this just yet. I am using 3 horizontally chained 16x32 panels. I am also still using python 2.7.16 with the following changes:

  1. Changed line 51 from 'unicode' to 'str' as suggested above.
  2. Changed line 70 '16' to '10' to resize font to a smaller size. I also changed the font type here to DejaVuSerif.ttf.
  3. Changed line 96 to os.system("sudo ./demo -D 1 --led-cols=96 --led-rows=16 --led-brightness=75 --led-chain=3 "+disp)
  4. Invoking code from /home/pi/rpi-rgb-led-matrix/examples-api-use

Lingering issues:

  1. Feed doesn't automatically update.
  2. Scroll speed too fast
  3. Sometimes on start it fails and have to re-start.

I will try to figure it out using runtext. This did not work:
os.system("sudo ./runtext.py --led-cols 96 -r 16 -b 50 -c 3 --text"+disp)

@sleep-sort
Copy link

ooh looks like you found out how to size this properly, this should solve my issue. I'll give it a shot and let you know if I have the same feed changing issue. Might be something up with the loop I'd guess?

Yeah i think to use runtext we need to refactor a bit more than just the system call because it i think needs to be text instead of images, but im really not sure. maybe if I run into some free time in the next week or two i'll take a look at doing that but honestly if your resizing work fixes it for me i'll be very happy!

@jax200
Copy link

jax200 commented Dec 21, 2020

I found if I leave it alone as it keeps scrolling, it eventually freaks out to display what looks like xmas lights! (but not in a good way)

And this was going to be a xmas gift for a buddy of mine - but looks like it will have to wait.

I did find some cool business feeds from here:
https://feeds.a.dj.com/rss/RSSMarketsMain.xml
https://feeds.a.dj.com/rss/RSSWorldNews.xml
https://feeds.a.dj.com/rss/RSSWSJD.xml
https://feeds.a.dj.com/rss/WSJcomUSBusiness.xml

Still haven't found the holy grail, ie, stock ticker feed.

@sleep-sort
Copy link

Oh awesome, thank you! yep your fix got me to exactly where you are. It will run, just one at a time (jumping to the next on control+c). Also noticed the weird light bug. Strange... - i'll pop back to this thread if I find some fixes!

@Jani73
Copy link

Jani73 commented Dec 25, 2020

jax200, about too fast scroll speed, are you checked from here about GPIO speed?
https://github.com/hzeller/rpi-rgb-led-matrix/blob/master/README.md
I have some Raspberry Pi 3b+ if I remember right and it has good speed.

My panels collected dust some time, and I also have files from somewhere like 2 years ago, and it does change feed and when feed changes, changes also the colour, feed changes maybe after 60 seconds.
But after some time, maybe hour or something, the panel goes dark.

Could it be something related to feedparser that it doesn’t change feed itself?

edit:I tried older files of feedparser.pyc and demo, but without success with all these other new files.

@jax200
Copy link

jax200 commented Dec 25, 2020

@Jani73 Thx I will check GPIO speed, but now I think it's ok.

@jax200
Copy link

jax200 commented Dec 25, 2020

I am walking through the program line-by-line as an exercise in learning python. Maybe someone is willing to help? I am first stuck here, ie, specifically don't understand what this is doing: posts=feed["items"]

for url in feeds:
        feed=feedparser.parse(url)
        posts=feed["items"]
        for post in posts:
            items.append(post)

then unclear about enumerate(items).

Where is the actual loop? The Timer object?

From the execution standpoint, I think I understand this:
run() > prints > parses the url(s) into a matrix? > grabs the feed somehow > creates images from each > starts a threading.Timer and uses LED library to display ??
Over my head...

That's a start but don't want to ask too much ; ).

@jax200
Copy link

jax200 commented Dec 26, 2020

I think DEMO just takes what it is fed and rolls text until Ctrl-C is selected. So in rssparse.py, when Ctrl-C is selected indeed it goes to the next feed. But rssparse.py should be doing this automatically, which is the crux of the problem?

@jax200
Copy link

jax200 commented Dec 26, 2020

I also take note of comment by @mattwbdv above "... have been working to implement this in python 3 since feedparser no longer supports python 2 ...". I don't have an issue with python 2.7, yet when I run python3 rssparse.py it chokes:

pi@raspberrypi:~/rpi-rgb-led-matrix/examples-api-use $ python3 rssparse4.py
Traceback (most recent call last):
  File "rssparse4.py", line 7, in <module>
    import feedparser
ModuleNotFoundError: No module named 'feedparser'

@sleep-sort
Copy link

@jax200 do you have python 3 installed? I think by default the pi runs everything with 2.7, right? so wouldn't be surprised if it could be solved by adding python 3. I actually tried fully deleting 2.7 which was a huge mistake because that breaks a whole bunch of things with the raspbian os - on a side note, did anyone figure out yet how to get it to switch between files without ctrl-c?

@Jani73
Copy link

Jani73 commented Dec 28, 2020

I tested again with my old files, where this original rssparse.py works. It looks like on line -r 16 -c 3 -t 60 -m 25 -D 1 -t 60 means time in seconds and after that feed changes. These parameters works with some year 2018 rpi-rgb-led-matrix-library.

On demo, there’s some modifications at the end, where time related code is removed. Those might be the missing link, but I don’t understand anything about it.

On demo there are on lines 1177-1178 these signal(SIGTERM, InterruptHandler); signal(SIGINT, InterruptHandler);. If I read right, those are codes for waiting CTRL+C? Could it be possible to add there some timer that interrupts program after 60 seconds and do what CTRL+C now does > changes the feed? Maybe that’s a workaround, but would be nice to get it working with newest library.

@sleep-sort
Copy link

I bet that would do it, let me dig around and see if I can get something working @Jani73 - my python skills are horrible though I do have to warn

@jax200
Copy link

jax200 commented Jan 1, 2021

@Jani73 "...I tested again with my old files, where this original rssparse.py works..." I originally tried this, but it didn't work for me, which I assumed was because the led-matrix command was missing?

os.system("sudo ./led-matrix -r 16 -c 3 -t 60 -m 25 -D 1 "+disp)

Hence moved on to the demo command.

os.system("sudo ./demo -D 1 --led-cols=96 --led-rows=16 --led-brightness=75 --led-chain=3"+disp)

Two days ago I was getting parsed rss feeds nicely showing (but still with the Ctrl-C issue). Then... things went downhill. I started getting error messages regarding import feedparser. I re-built from scratch but now

pi@raspberrypi:~/rpi-rgb-led-matrix/examples-api-use $ python  ./rssparse.py
Traceback (most recent call last):
  File "./rssparse.py", line 7, in <module>
    import feedparser
  File "/usr/local/lib/python2.7/dist-packages/feedparser/__init__.py", line 31, in <module>
    from .api import parse
  File "/usr/local/lib/python2.7/dist-packages/feedparser/api.py", line 56, in <module>
    from . import http
  File "/usr/local/lib/python2.7/dist-packages/feedparser/http.py", line 156
    new_pieces[1] = f'{url_pieces.hostname}:{url_pieces.port}'

I have now even hired a python tutor to help, but he is of the opinion to rebuild some of the components entirely. So stay tuned.

@jax200
Copy link

jax200 commented Jan 1, 2021

btw, I'm wondering if this conversation would be better on the discourse.group area than using chubbyemu's space? Might get other input as well. I posted two weeks ago there but no responses.

https://rpi-rgb-led-matrix.discourse.group

@mcwTexas
Copy link

Is anyone else having issues with quality of the scroll? I am getting readable display but it looks a little blurry no matter what font I've tried. And I've tried about 5. I've also tried changing the font size to 10 as suggested earlier in the thread. I'm not sure if there is some new setting to help with it or if it's due to the matrix library install choice of "convenient" vs. quality already coming back to haunt me. Thanks!

@Jani73
Copy link

Jani73 commented Jan 19, 2021

@mcwTexas, have you checked the readme?

The link in jax200’s message doesn’t work, but here is a straight link.

https://rpi-rgb-led-matrix.discourse.group/t/rssparse-py-needs-some-help/40/22

@mcwTexas
Copy link

@Jani73, thank you sooooo much for providing that link as it did answer my questions and solve my problems!!!!!! Very appreciative!!

@mcwTexas
Copy link

mcwTexas commented Jan 26, 2021

Hi @Jani73 You were so kind before in helping me, I thought I'd try my luck again. I've noticed a new problem and tried to troubleshoot for the past 2 days. I'm a newby so not much I know to do. The newsfeed matrix scroll looks good for x period of time, and then, for no reason I can tell, the data becomes garbled. It looks like multiple threads are trying to be written and display at the same time on the matrix. It happens at various points -sometimes a couple hours after I start the scroll. I can stop the program and restart it, and all works good again - for a while and then it happens again. Watching the code run in the bash window, everything appears to run normal. Here are the settings I'm using on the os.system line. Any thoughts?

os.system("sudo ./rpi-rgb-led-matrix/examples-api-use/scrolling-text-example -f ./rpi-rgb-led-matrix/fonts/7x13.bdf -y5 -s7 -l1 -C "+ randomColor +" -B 0,0,0 --led-cols=64 --led-rows=32 --led-chain=1 --led-slowdown-gpio=4 " +title)

After running the program all night and seeing the display issue again, I checked the task manager. It showed tons of Sh and scrolling-matrix-example processes. I'm now assuming each time through the loop it starts a new process then never kills the process before starting another. While almost all of the processed were using o CPU, a 2 or 3 of the instances were utilizing CPU. So going out on a limb here, is there a command to kill the process/instance at the end of each loop? I feel like that would solve my issue.

@Jani73
Copy link

Jani73 commented Jan 26, 2021

Hi @mcwTexas. I don’t know much about these things. Now I put it running and my task manager doesn’t show increasing number of scrolling-text-example processes. Only one Sh too.
Maybe asking from others, which knows about coding.

My line is
os.system(sudo ./scrolling-text-example -f ../fonts/9x15.bdf -y0 -s9 -l2 -C ”+ randomColor +” —led-cols=32 —led-rows=16 —led-brightness=75 —led-chain=3 ”+title)

feedparser.pyc is also on examples-api-use-folder as is rssparse.py.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment