Ready to go?

Twitterbot

12. Dezember 2018

Anfang dieses Jahres habe ich die Idee gehabt mit dem Raspberry Pi LED Matrix Anzeigen anzusteuern und auf denen Tweets vom SCBern anzuzeigen. Es stellte sich aber sehr schnell heraus, dass ich dazu einige Pythonskills gebraucht hätte, welche ich zu diesem Zeitpunkt nicht hatte.

Durch meine Ausbildung habe ich nun aber einge Pythonskills erlangt um einge Dinge zu programmieren. So habe ich mich also mit voller Motivation erneut an dieses Projekt gewagt und soviel sei schon verraten, es hat funktioniert :).

Ich bin kein Python Profi und alles was du gerade lesen wirst stammt aus dem Internet. Wenn du denkst du bist ein Pythonprofi dann empfehle ich dir direkt mit den eigentlichen Anleitungen zu arbeiten. Ich habe mich aber dazu entschieden hier meine Erfahrungen mit den Anleitungen zu teilen, da Anleitungen meistens nicht zu 100% auf Anhieb funktionieren.

Für mein Projekt habe ich folgende Links verwendet:

- https://luma-led-matrix.readthedocs.io/en/latest/

- https://opensource.com/article/17/8/raspberry-pi-twitter-bot

- http://www.corvinelabs.com/make-a-simple-twitter-iot-application-using-raspberry-pi/

- https://www.raspberrypi.org/forums/viewtopic.php?p=568516

Hardware

Bevor ich anfange mit erklären was ich gemacht habe hier eine kleine Übersicht meiner Komponenten:

- Raspberry Pi Model 3B

- Netzteil 5v 2.5A (Für dieses Projekt ist ein so starkes Netzteil von Vorteil, ausser du betreibst die Matrix mit einer externen Stromquelle)

- SD Karte

- Raspbian Lite

- LED Matrix

- Tastatur & Maus

- Monitor

- HDMI Kabel

- LAN Anschluss

Tastatur, Maus und Monitor mit Kabel brauchst du nur wenn du nicht von Anfang an per SSH auf den pi zugreifen willst. Da es aber mühsam ist alle Befehle aus den Anleitungen abzutippen empfehle ich dir dich per SSH auf dem pi einzuloggen. Wie das funktioniert ist hier beschrieben.

 

Hardware 2.JPG

Installation

Wie bei vielen Dinge die man mit dem Raspberry Pi macht muss man zuerst mal das Betriebsystem auf die SD Karte flashen. Wer nicht weiss wie das geht, soll das doch schnell googlen oder er schaut in meinem Beitrag "Install Raspbian on the Raspberry Pi" nach, dort habe ich beschrieben wie es funktioniert. Ich empfehle euch die Lite Version des Raspbian zu nehmen, denn die Kommandozeile reicht euch vollkommen aus und ihr braucht nicht lange auf das Image zu warten. Es spricht aber nichts dagegen die Desktopvariante zu nehmen, dann könnt ihr eigentlich auch direkt auf dem pi arbeiten und die Anleitungen von dort aus aufrufen. Empfehle ich euch aber nicht, da es manchmal nicht ganz so flüssig läuft auf dem pi per GUI etwas zu machen.

Bevor ich nun aber irgendwie anfange auf der Kommandozeile herumzuhacken schliesse ich zuerst meine Matrixdinger an. Ich habe gleich zwei Stück bestellt und diese in der Mitte mehr oder weniger schön zusammengelötet. Angeschlossen werden die Dinger dann so:

 

Installation der Matrix

Als erstes fange ich nun damit an die Anleitung zu den LED Matrix durchzugehen und diese anzusprechen. Die oben verlinkte Anleitung ist eine sehr gute Anleitung von einem der auch gleich eine Github Bibliothek veröffentlicht hat. Ich habe mehrmals die Erfahrung gemacht dass es mit Python 3.x irgendwie nicht funktioniert weshalb ich es bei Python 2.7 belassen habe. Ist im Grunde genommen nicht wirklich ein Problem, die Syntax ist z.T dann halt anders.

Laut der Anleitung müsst ihr zuerst checken ob SPI auf dem pi überhaupt läuft. Das tut ihr mit

lsmod | grep -i spi

Diese Zeile sind im Grunde genommen zwei Befehle. Zum einten ist da "lsmod" was euch eine Liste aller laufenden "Module" gibt, zum anderen wird die Ausgabe dieses Befehls mit dem | an den grep Befehl weitergeleitet was mehr oder weniger einfach ein Filtern nach dem Stichwort "spi" ist.

Wenn du als Ausgabe etwas siehst, dann weisst du das das Modul richtig läuft. Wenn nicht dann musst du mit

sudo raspi-config

Im Punkt 5 SPI enablen gehen.

Danach musst du deinem user pi zuerst mal die Rechte geben damit er die GPIO's und spi überhaupt nutzen darf.

sudo usermod -a -G spi,gpio pi

Danach musst du Python und diverse andere Packete installieren. Wenn du mit Python 3.x schaffen willst so musst du hier nun anstatt python-pip python3-pip eingeben und aus python-dev python3-dev machen, jedoch hat dies bei mir mit mehreren Anläufen nicht geklappt.

sudo apt-get install build-essential python-dev python-pip libfreetype6-dev libjpeg-dev

Und noch ein weitere Packet zum installieren:

sudo -H pip install --upgrade luma.led_matrix

Nun musst/darfst du die Github Bibliothek herunterladen. Dazu musst du aber zuerst git auf dem pi installieren.

sudo apt install git

Danach kannst du dir die Bibliothek auf den pi klonen

git clone https://github.com/rm-hull/luma.led_matrix.git

Und wenn alles richtig geklappt hat dann solltest du mit folgendem Befehl etwas auf deiner Matrix sehen:

python examples/matrix_demo.py

Wenn nun irgendetwas nicht geklappt hat, dann schaue ob du die Matrix richtig verkabelt hast. Dies war bei mir schon oft der Fehler. Wenn es immer noch nicht geht dann schaue mal im Github Forum zur Bibliothek nach, dort gibt es z.t noch hilfreiche Tipps. (Du findest dort mehr Einträge wenn du nach geschlossenen Einträgen suchst).

Nun ist es sehr gut möglich dass das was auf der Matrix angezeigt wird ein Haufen wirwar ist und keinen richtigen Sinn ergibt. Das liegt daran dass der pi 1. nicht weiss wieviele Quadrate du überhaupt angeschlossen hast, 2. In welcher Orientierung er das ganze über die Matrix laufen lassen soll und 3. Wie die einzelnen Blöcke orientiert sind.

Um dies zu beheben müssen wir in den Code und an gewisser Stelle einiges abändern gehen.

cd luma.led_matrix/examples (Wenn du nicht bereits im Verzeichnis drin bist)
nano matrix_demo.py

Es öffnet sich der Editor nano mit der Demo Datei die du vorhin versucht hast zu starten. Dies ist ein gewöhnliches Pythonskript.

Ganz am Ende des Scripts findest du drei Zeilen die so aussehen:

parser.add_argument('--cascaded', '-n', type=int, default=1, 
help='Number of cascaded MAX7219 LED matrices')
parser.add_argument('--block-orientation', 
type=int, default=0, choices=[0, 90, -90], 
help='Corrects block orientation when wired vertically')
parser.add_argument('--rotate', type=int, 
default=0, choices=[0, 1, 2, 3], help='Rotate display 0=0°, 1=90°, 2=180°, 3=270°')

Bei den drei Defaults kannst du nun deine Werte angeben. Das erste bezieht sich auf die Anzahl Quadrate die du angeschlossen hast. In meine Fall wären das nun 8. Das zweite bezieht sich auf die Ortientierung. Wenn du wie ich gleich 4 Quadrate aneinandergesschlossen hast, musst du hier -90 eingeben. Beim dritten Default habe ich es so belassen. Wenn es nicht richtig funktioniert dann ändere den Wert dort mal ab und schaue ob es funktioniert.

Wenn alles geklappt hat läuft deine Laufschrift nun schön von rechts nach links durch.

Nun hast du in der Theorie diverse möglichkeiten mit der Anzeige herumzuspielen. Was ich nun behandel möchte ist wie man Tweets von Twitter holt und diese anzeigt. Dazu braucht es vom Code her nur die Zeilen die etwas ausgeben. Ich habe mir zum testen die Demodatei mal kopiert:

cp matrix_demo.py anzeige.py

Dann die Datei geöffnet:

nano anzeige.py

Und nun angefangen den Code zu löschen. Wenn wir nur eine scrollende Zeile ausgeben wollen dann braucht es den grössten Teil des Codes nicht. Heraus kommt bei mir folgender Code:

 

Schauen wir uns den Code mal an:

1.Zeile: Hier wird festgehalten dass es sich um ein ausführbares Pythonfile handelt.

2. Zeile: Die Codierung wird festgelegt. Gerade im Bezug auf die  Anzeige welche keine ö,ä,ü sowie Emojiys anzeigen kann ist dies wichtig.

4.-10. Zeile: Hier werden die diversen Module und Klassen importiert

12.-16. Zeile: Nun wird das Matrixdevice generiert. Dabei werden ihm die Paratmeter gleich mitgeben in welcher Orientierung und wiviele Quadrate angeschlossen sind.

18.-23. Zeile: Nun geben wir etwas aus. Wir definieren zuerst die Variable msg und geben diese anschliessend zuerst auf der Konsole und nachher auf der Anzeige aus. Dabei können wir mit scroll_delay festlegen wie schnell der Text fliessen soll. Bei 0 wirst du ihn gar nicht sehen da er viel zu schnell ist und bei 1 schläfst du ein. Ich brauche hier jetzt 0.03 und das ist schön angenehm, 0.1 würde auch noch gehen.

Twitter implementieren

Nun da wir es geschafft haben ein einfaches String auf der Anzeige zu printen brauchen wir nur noch Tweets als Strings. Dies machen wir mit der API von Twitter. Damit du aber eine API erstellen kannst und mit Twitter kommunizieren kannst brauchst du einen Twitter Devoloper Account. Erstell dir diesen unter hier. Ich warne dich schonmal vor, dies geht nicht ganz so einfach, du musst einige Zeilen schreiben über was du machst und weshalb du einen Devoloperaccount brauchst. Ausserdem brauchst du eine gültige Handynummer damit sie dir eine Bestätigungscode senden können sowie eine Mail Adressse.

Wenn du dir diesen Account erstellt hast, klickst du auf dein Konto und dann auf „Apps“. Dort kannst du nun eine App erstellen. Mache das und wenn du sie erstellt hast gehe unter „Keys and tokens“. Dort musst du dir nun eine Schlüssel (besser gesagt zwei) generieren lassen. Diese ingesamt 4 Schlüssel die du auf dieser Seite siehst brauchst du später noch, also speichere sie dir irgend in ein Textfile. Stelle aber sicher dass du sie an niemanden weitergibst oder postetst. Diese Schlüssel sind für dein Programm die Authentifizierung bei Twitter. Also dein Programm kommt über diese Schlüssel auf deinen Devoloperaccount.

Ist das alles klar installieren wir uns das twython Package mit:

sudo pip install twython

Wenn dieses Packet installiert ist haben wir eigentlich schon alle Dinge zusammen die wir brauchen um unser "Masterprogramm" zu schreiben. Nun kommt also das File in dem die gane Magie geschieht. Dazu mache ich mir im Homeverzeichnis von pi einen neuen Ordner "twitter". Das ist natürlich überhaupt nicht nötig, aber ich habe gerne Ordnung.

mkdir twitter

cd twitter

In diesem Ordner brauche ich nun ein neues Pythonscript. Dieses nenne ich nun mal "timeline.py". Es spielt komplett keine Rolle was ihr für einen Namen ihr da nehmt.

touch timeline.py

nano timeline.py

In diesem File steht bei mir nun folgendes:


Ja gut dies ist nun eine Menge Code und der kann einem fast erschlagen, es ist aber nicht mal so schwer. Aber fangen wir vorne an.

Die ersten 25. Zeilen bis time.sleep(1) solltet ihr wahrscheinlich aus dem vorherigen Beispiel noch kennen. Lediglich die Zeile "from twython import Twython" ist relevant und neu. Hier wird nämlich die Klasse "Twython" aus dem Packet welches wir vorher installiert haben importiert. Dies werden wir später brauchen.

Doch zuerst definieren wir uns noch vier Variabeln und zwar die vier Keys, welche du dir hast generieren lassen auf der Devoloper Seite von Twitter. Diese musst du nun hier einfügen. Wie bereits erwähnt berechtigen und ermöglichen diese Keys es der Anwendung per Devoloper Account mit Twitter zu kommunizieren, also falls du dein File irgendwie teilst oder veröffentlichst schaue doch, dass du deine Keys so wie ich vorher raus nimmst.

Nun da wir diese Keys auch definiert haben kreieren wir uns eine neue Instanz der Klasse Twython und geben ihm dabei die vier Schlüssel mit. Dies passiert auf der Zeile wo steht "twitter = Twython(...)".

Weiter definiere ich auch gleich noch die Variable Start mit der aktuellen Zeit (also die Zeit die gerade war als das Programm an diese Stelle kam), einen Counter und den "old_tweet" welches eine Variable ist die ich brauche um zu überprüfen ob der neue Tweet dem vorherigen entspricht.

Danach gehe ich in eine Whileschlaufe hinein welche Zeitgesteuert ist. Ich sage ihm er soll mein Ding so lange machen bis die aktuelle Zeit minus die Startzeit grösser ist als das von mir vorgegebene Zeitdelta. Auf Deutsch gesagt macht er etwas für eine bestimmte Zeit. In meinem Fall sind das nun 999999999999 Sekunden. Ich wollte zuerst 3 Stunden einstellen denn länger geht ein Match mit ein bisschen Zeit vor und nachher auch nicht aber dann hat er mir irgendwie sehr bald abgebrochen und ich habe mich dann mal dazu entschieden eine riesige Zahl anzugeben damit er es ja genug lange macht.

Nun die Frage was macht er denn überhaupt in dieser Whileschleife?

Auf der ersten Zeile holt er sich den neusten Tweet von meinem User. Dies ist nun aber ein Array (oder eine Liste) mit diversen Metadaten etc. Ich will daraus eigentlich nur den Tweet. Deshalb mache ich eine Forschleife und hole mir so den Tweet aus dem Array welchen ich in einer Variable "tweet" speichere. Dann nehme ich alle ä,ö,ü sowie é und è weg damit es zu keinen Problemen kommt wenn ich das String auf der Anzeige ausgeben will. Was nun folgt ist meine Kontrolle. Ich habe mir gedacht es macht keinen Sinn den Tweet immer und immer wieder auszugeben und wenn ein neuer kommt dann mache ich dies erneut. Ich habe mir eine Bedingung geschrieben die überprüft ob der aktuelle Tweet welchen er gerade geholt hat der gleiche ist wie den vorherigen. Das erstemal wird dies nicht der Fall sein und er wird direkt ins Else gehen. Dort setzt er dann meinen Counter zurück und gibt den Tweet aus. Das print danach ist mehr für mich gedacht damit ich falls ich ihn auf der Konsole überwache sehe was er macht. Danach wartet er noch 15 Sekunden damit er von der Twitter API nicht geblockt wird. Es hat sich nämlich herausgestellt das permanentes Abfragen bei Twitter nach ca 2 Minuten geblockt wird da es zu viele Anfragen in 15 Minuten sind. Wenn ich aber immer noch 15s warte, geht es gut auf. Und seien wir mal ehrlich, das reicht längstens um die Tweets möglichst zeitnahe auszugeben.

Wenn es nun aber so ist dass der aktuelle Tweet der gleiche ist wie der vorherige, dann geht er in mein if rein und  trift direkt nochmals auf ein if. Und zwar wird überprüft wie hoch der Counter bereits ist und ob er das ganze überhaupt noch ausgeben darf. Wenn ja macht er das und sonst schreibt er mir zur Kontrolle ein "Warten..." auf die Konsole. Ganz am Schluss der Schlaufe speichere ich den Tweet den er gerade geholt hat in der Variable old_tweet ab damit ich das beim nächsten mal vergleichen kann.

Autostart

Nun wo mein file steht und läuft möchte ich es nicht jedesmal von Hand starten gehen wenn ein Match läuft. Ich möchte einfach Stromstecker rein und los gehts. Deshalb muss ich noch WiFi konfigurieren und in einer Datei mein Befehl zum ausführen der Datei einfügen damit mein Skript beim starten automatisch gelauncht wird.

Dazu muss die rc.local Datei bearbeitet werden:

sudo nano /etc/rc.local

Dort drin vor dem exit 0 euren Befehl zum ausführen des Skript reinpacken. Bei mir sieht dieser so aus:

sudo python /home/pi/twitter/timeline.py &

Wenn ich mich richtig erinnere steht das & am Schluss dafür, dass er diesen Befehl im Hintergrund ausführt. Wenn du also per ssh auf den pi gehts wirst du nichts merken. Um das Skript vorzeitig zu beenden musst du entweder herunterfahren oder mit top nachschauen welche ProzessID das Ding hat und dann mit kill ProzessID abschiessen gehen.

WLAN Einrichten

Wie das geht findest du hier.

 

So nun habe ich genug geschrieben, ich hoffe du hast erfolg mit meiner Anleitung und falls nicht dann poste einen Kommentar unten dran.

:)

Anmelden