Questo tutorial estende il tutorial precedente, Come costruire un LCD RGB controllato da Tweet, aggiungendo il controllo della pagina web. Con questo è possibile modificare la configurazione del Tweetbox al volo da laptop, tablet o telefono.
Imparerai tecniche utili in questo tutorial in modo da poter aggiungere il controllo della pagina web ai tuoi progetti Raspberry Pi.
sudo pip installa il tornado
Tutto il codice per questo progetto è disponibile qui:
https://github.com/jerbly/tutorials/tree/master/tweetbox
Per riassumere, alla fine del tutorial precedente hai avuto un Raspberry Pi con LCD RGB collegato a Twitter che riceve tweet pubblici corrispondenti a un filtro. La retroilluminazione RGB cambierebbe colore a seconda di altre parole corrispondenti nel tweet. Per configurare il filtro e la mappa dei colori è necessario modificare il codice e riavviare il programma.
In questa prima fase aggiungerò un server web al programma. Quindi puoi andare su una pagina web e aggiornare la configurazione dal vivo. Userò Tornado, ci sono molti diversi framework web per Python e ne ho usati molti nel corso degli anni, ma ora è il mio vai a struttura. Spunta molte scatole per molti progetti diversi.
Dai un'occhiata al Ciao mondo esempio sulla pagina Tornado in modo da poter vedere come impostare un gestore e avviare un thread del server tornado. Userò esattamente questo stesso principio qui.
Prenderò il tweetbox.py
codice dal tutorial precedente e aggiungere il framework web in. Per cominciare, avrò un semplice modulo che ci permetterà di cambiare ciò che sto monitorando su Twitter. Innanzitutto, aggiungi alcune importazioni all'inizio dello script:
importare tornado.ioloop import tornado.web
Successivamente ho bisogno di due gestori: uno per mostrare il modulo HTML e un secondo per ricevere l'invio del modulo:
class MainHandler (tornado.web.RequestHandler): def get (self): self.render ("templates / form1.html") classe ConfigHandler (tornado.web.RequestHandler): def post (self): config_track = self.get_argument ( "config_track") restart (config_track) self.write ("Now tracking% s"% config_track) application = tornado.web.Application ([(r "/", MainHandler), (r "/ config", ConfigHandler),] )
Nota che MainHandler
usi ottenere
e ConfigHandler
usi inviare
, il modulo HTML utilizza il metodo post per inviare nuovamente i dati del modulo al server web. Per servire la forma il MainHandler
chiama semplicemente la funzione di rendering per avere un modello reso e inviato al browser. Maggiori informazioni su questo in un momento.
Quando i dati del modulo ritorna ConfigHandler
estrae un argomento, config_track
. Questo è inviato a ricomincia
funzione per modificare le impostazioni con tweepy prima di restituire una semplice stringa che mostra ciò che viene monitorato.
Crea il modello aggiungendo una directory chiamata modelli alla directory di origine e creare il form1.html
file lì:
Tweetbox Raspberry Pi
Questo è un modulo molto semplice con una casella di inserimento del testo e un pulsante di invio. È tutto ciò che è necessario in questa fase. Quindi crea il ricomincia
funzione:
def restart (track_text): stream.disconnect () time.sleep (5) #Tempo in cui il thread si disconnette ... stream.filter (track = [track_text], async = True)
Questo disconnette il flusso Twitter e quindi ricollega il nuovo filtro, track_text
, che è qualsiasi cosa è stata inviata dal modulo. Un cambiamento importante qui, dal tutorial precedente, è che il thread del flusso Twitter viene eseguito in modalità asincrona, async = True
. Questo esegue la connessione di flusso in un thread in background in modo che il server Web venga eseguito come thread principale.
Aggiungi un paio di righe alla fine per avviare il flusso in modalità asincrona e quindi avviare il server web:
stream.filter (track = ['jeremy'], async = True) application.listen (8888) tornado.ioloop.IOLoop.instance (). start ()
Questo avvia il server Web in ascolto sulla porta 8888. Puntare un browser Web all'indirizzo http: // your-raspi-ipaddress: 8888 / e vedrete il modulo:
Modulo per la pagina web di TweetboxInserisci qualcos'altro per tracciare come lampone e fare clic su Invia. Dopo cinque secondi, passerà al rilevamento di questi tweet.
In questa fase aggiungerò la mappa dei colori alla configurazione in modo da poter impostare le parole che attivano la retroilluminazione RGB da modificare. Dato che ci sono sette impostazioni, non voglio davvero reinserirle ogni volta che eseguo l'applicazione, quindi le salverò su un file.
Il programma utilizza pickle per salvare e caricare il file di configurazione, oltre a un iniziale il file esiste controlla quindi aggiungi queste importazioni all'inizio:
esiste l'importazione sottaceto dall'importazione genericpath
Il DisplayLoop
la classe è già responsabile della gestione di backlight_map
quindi lo estenderò in modo che si occupi di ciò che sto attualmente monitorando, track_text
. Qui sono anche aggiunti i metodi di lettura e scrittura della configurazione:
class DisplayLoop (StreamListener): PICKLE_FILE = '/home/pi/py/tweetbox.pkl' def __init __ (self): self.lcd = Adafruit_CharLCDPlate () self.lcd.backlight (self.lcd.RED) self.lcd.clear () self.track_text = 'jeremy' self.backlight_map = 'red': self.lcd.RED, 'green': self.lcd.GREEN, 'blue': self.lcd.BLUE, 'yellow': self. lcd.YELLOW, 'teal': self.lcd.TEAL, 'violet': self.lcd.VIOLET self.msglist = [] self.pos = 0 self.tweet = 'Ancora niente' def write_config (self): data = "track_text": self.track_text, "backlight_map": self.backlight_map output = open (self.PICKLE_FILE, 'wb') pickle.dump (dati, output) output.close () def read_config (self): if esiste (self.PICKLE_FILE): pkl_file = open (self.PICKLE_FILE, 'rb') data = pickle.load (pkl_file) pkl_file.close () self.track_text = data ["track_text"] self.backlight_map = data ["backlight_map "]
Cambia i gestori delle richieste per prendersi cura dei colori. Anche qui sotto vedrai che quando eseguo il rendering della pagina principale sto passando alla configurazione corrente. Ciò significa che posso compilare il modulo di configurazione con le impostazioni correnti quando richiesto.
class MainHandler (tornado.web.RequestHandler): def get (self): inverted_map = v: k per k, v in display_loop_instance.backlight_map.items () self.render ("templates / form3.html", config_track = display_loop_instance .track_text, config_red = inverted_map [Adafruit_CharLCDPlate.RED], config_green = inverted_map [Adafruit_CharLCDPlate.GREEN], config_blue = inverted_map [Adafruit_CharLCDPlate.BLUE], config_yellow = inverted_map [Adafruit_CharLCDPlate.YELLOW], config_teal = inverted_map [Adafruit_CharLCDPlate.TEAL], config_violet = inverted_map [Adafruit_CharLCDPlate.VIOLET]) classe ConfigHandler (tornado.web.RequestHandler): def post (self): config_track = self.get_argument ("config_track") colour_map = self.get_argument ("config_red"): Adafruit_CharLCDPlate.RED, self .get_argument ("config_green"): Adafruit_CharLCDPlate.GREEN, self.get_argument ("config_blue"): Adafruit_CharLCDPlate.BLUE, self.get_argument ("config_yellow"): Adafruit_CharLCDPlate.YELLOW, self.get_argument ("config_teal"): Adafruit_CharLCDPlate.TEAL , self.get_ argomento ("config_violet"): Adafruit_CharLCDPlate.VIOLET set_config (config_track, colour_map) self.write ("Ora traccia% s"% config_track)
Una tecnica da notare qui è come invertire la mappa dei colori. Durante l'elaborazione voglio che la mappa sia parola> colore ma quando lo si configura nel formato che voglio colore> parola. Una comprensione del dizionario Python può essere utilizzata per invertire la mappa in una singola istruzione: v: k per k, v in display_loop_instance.backlight_map.items ()
È richiesto un nuovo modulo HTML per supportare le impostazioni del colore. Inoltre ho bisogno di compilare le caselle di immissione del modulo con le impostazioni correnti facendo uso del sistema di template di Tornado. Questo è molto semplice, sto solo prendendo i valori passati al rendere
funzione e tirandoli fuori qui nel modello per esempio config_track
.
Tweetbox Raspberry Pi
Ora che posso salvare e caricare la configurazione, la prima ricomincia
la routine deve essere un po 'più sofisticata:
def set_config (track_text, colour_map): display_loop_instance.set_text ("Aggiornamento della configurazione") stream.disconnect () display_loop_instance.track_text = track_text display_loop_instance.backlight_map = colour_map display_loop_instance.write_config () time.sleep (5) #Facora il thread per disconnect ... stream.filter (track = [display_loop_instance.track_text], async = True) display_loop_instance.set_text ("Configurazione aggiornata")
Dal momento che è più di un riavvio è il nome è ora set_config
. È qui che ora chiamo write_config
per salvare le modifiche al file.
Tutto ciò che rimane sono un paio di modifiche da leggere nella configurazione all'avvio:
display_loop_instance = DisplayLoop () display_loop_instance.read_config ()
E per avviare il flusso da questa impostazione piuttosto che 'Jeremy'
:
stream = Stream (auth, display_loop_instance) stream.filter (track = [display_loop_instance.track_text], async = True)
Avvia il programma, punta un browser web all'indirizzo http: // your-raspi-ipaddress: 8888 / e vedrai il modulo:
Modulo webCi sono alcune cose che non sono molto chiare su questo programma:
Il ritardo durante la modifica della configurazione è dovuto alla natura asincrona del programma. C'è un thread che gestisce lo stream di Twitter, un thread che scorre sul display e il thread principale che esegue il web server.
Quando voglio modificare le impostazioni sullo streaming, devo disconnetterlo e quindi riconnetterti con le nuove opzioni. Sfortunatamente non c'è nessun evento da tweepy da dirmi quando ho disconnesso con successo e così fino ad ora ho appena ritardato di cinque secondi tra la disconnessione e la riconnessione.
Per rimuovere questo ritardo, quello che farò è avviare una nuova connessione mentre quella precedente si sta disconnettendo, quindi non devo aspettare. Ovviamente questo significa che a un certo punto ci possono essere due stream che ricevono tweet. Questo sarebbe confuso sul display poiché vedresti il vecchio tracciamento e il nuovo tracciamento combinati.
Pertanto, appena prima della disconnessione collegherò il vecchio stream ad un listener che non fa nulla con i tweet in arrivo. Ecco la definizione di NullListener
e le modifiche al set_config
routine:
class NullListener (StreamListener): def on_data (self, data): passa def set_config (track_text, colour_map): stampa "restarting" display_loop_instance.set_text ("Aggiornamento configurazione") # Elimina il vecchio flusso in modo asincrono globale stream.listener = NullListener ( ) stream.disconnect () display_loop_instance.track_text = track_text display_loop_instance.backlight_map = colour_map display_loop_instance.write_config () # Crea un nuovo stream stream = Stream (auth, display_loop_instance) stream.filter (track = [display_loop_instance.track_text], async = True) display_loop_instance.set_text ("Configurazione aggiornata")
Per quanto riguarda la Ora il monitoraggio ... risposta, la versione corrente del modulo viene inviata al ConfigHandler
che cambia le impostazioni e restituisce questa brutta risposta. In realtà quello che voglio è che il modulo riappaia con le nuove impostazioni sul posto.
Posso ottenere questo reindirizzando l'utente al /
URL. Inoltre, non c'è davvero bisogno per il ConfigHandler
comunque, posso definire il ottenere
e inviare
metodi sul MainHandler
e semplicemente inviare il modulo lì invece:
class MainHandler (tornado.web.RequestHandler): def get (self): inverted_map = v: k per k, v in display_loop_instance.backlight_map.items () self.render ("templates / form4.html", config_track = display_loop_instance .track_text, config_red = inverted_map [Adafruit_CharLCDPlate.RED], config_green = inverted_map [Adafruit_CharLCDPlate.GREEN], config_blue = inverted_map [Adafruit_CharLCDPlate.BLUE], config_yellow = inverted_map [Adafruit_CharLCDPlate.YELLOW], config_teal = inverted_map [Adafruit_CharLCDPlate.TEAL], config_violet = inverted_map [Adafruit_CharLCDPlate.VIOLET]) def post (self): config_track = self.get_argument ("config_track") colour_map = self.get_argument ("config_red"): Adafruit_CharLCDPlate.RED, self.get_argument ("config_green"): Adafruit_CharLCDPlate. VERDE, self.get_argument ("config_blue"): Adafruit_CharLCDPlate.BLUE, self.get_argument ("config_yellow"): Adafruit_CharLCDPlate.YELLOW, self.get_argument ("config_teal"): Adafruit_CharLCDPlate.TEAL, self.get_argument ("config_violet"): Adafruit_CharLCDPlate.V IOLET set_config (config_track, colour_map) #Usare un reindirizzamento per evitare problemi con gli aggiornamenti nel browser da un modulo post self.redirect ("/") application = tornado.web.Application ([(r "/", MainHandler), ])
Infine, lo styling. Rendere questo look davvero bello potrebbe essere un tutorial completamente nuovo di per sé, ma un buon inizio è quello di introdurre un framework per occuparsi di molto dello stile per te.
Sono Bootstrap per lo styling e JQuery per lo scripting. Entrambi sono disponibili su CDN, quindi non è necessario scaricare nulla, basta includerli nella sezione principale della pagina:
Tweetbox Raspberry Pi
Per migliorare la forma, utilizzeremo lo stile Form orizzontale di Bootstrap:
Infine, per mettere un po 'di lucido sull'interfaccia utente, indicheremo all'utente che il Raspberry Pi si sta aggiornando quando fa clic su Sottoscrivi pulsante. Ciò comporta un po 'di Javascript per catturare l'evento di invio del modulo, cambiare il testo del pulsante in In aggiornamento… e disabilita il pulsante:
Ed ecco l'interfaccia web completa:
Il modulo web finitoQuesto tutorial è stato ampliato con quello precedente per aggiungere un'interfaccia utente Web al riquadro Tweet LCD RGB. Ora puoi controllare ciò che stai seguendo sullo schermo e i colori di retroilluminazione che desideri dal tuo telefono, tablet o computer desktop.