Slik legger du til et webgrensesnitt til RGB-LCD-boksen

Hva du skal skape

Denne opplæringen utvider den forrige opplæringen, Hvordan bygge en Tweet kontrollert RGB LCD, ved å legge til nettsidekontroll. Med dette kan du endre konfigurasjonen av Tweetbox i fly fra din bærbare datamaskin, nettbrett eller telefon. 

Du lærer nyttige teknikker i denne opplæringen, slik at du kan legge til nettsidekontroll til dine egne Raspberry Pi-prosjekter. 

Setup

  1. Først fullfør den forrige opplæringen Hvordan bygge en Tweet kontrollert RGB LCD
  2. Installer Tornado:

sudo pip installasjon tornado

Alle koden for dette prosjektet er tilgjengelig her:

https://github.com/jerbly/tutorials/tree/master/tweetbox

Fase 1: Grunnleggende form

For å samle på, ved slutten av den forrige opplæringen hadde du en Raspberry Pi med RGB LCD koblet til Twitter som mottok offentlige tweets som matchet et filter. RGB-bakgrunnslyset vil endre farge avhengig av andre matchende ord i tweetet. For å konfigurere filteret og fargekartet måtte du endre koden og starte programmet på nytt.

I denne første fasen legger jeg til en webserver til programmet. Deretter kan du gå til en nettside og oppdatere konfigurasjonen live. Jeg skal bruke Tornado, det er mange forskjellige nettrammer for Python, og jeg har brukt mange av dem gjennom årene, men dette er nå min gå til rammeverk. Den merker mange bokser for mange forskjellige prosjekter.

Ta en titt på Hei Verden Eksempel på Tornado-siden, slik at du kan se hvordan du konfigurerer en handler og starter en tornado-servertråd. Jeg bruker dette nøyaktig samme prinsippet her.

Jeg tar tweetbox.py kode fra den forrige opplæringen og legg til webrammen i. Til å begynne med vil jeg bare ha en enkel skjema som tillater oss å endre hva jeg sporer på Twitter. Først legger du til noen importer til toppen av skriptet:

importer tornado.ioloop import tornado.web

Deretter trenger jeg to håndtere: en for å vise HTML-skjemaet og et sekund for å motta skjemainnsendelsen:

klasse MainHandler (tornado.web.RequestHandler): def get (selv): self.render ("maler / form1.html") klasse ConfigHandler (tornado.web.RequestHandler): def post (selv): config_track = self.get_argument "config_track") restart (config_track) self.write ("Nå sporing% s"% config_track) application = tornado.web.Application ([(r "/" MainHandler), (r "/ config", ConfigHandler),] )

Noter det MainHandler bruker og ConfigHandler bruker post, HTML-skjemaet bruker innleggsmetoden til å sende skjemadataene tilbake til webserveren. Å betjene skjemaet MainHandler kaller bare gjengivelsesfunksjonen for å få en mal gjengitt og sendt til nettleseren. Mer om dette i et øyeblikk.

Når skjemadataene kommer tilbake ConfigHandler trekker ut et argument, config_track. Dette sendes til a omstart funksjon for å endre innstillingene med tweepy før du returnerer en enkel streng som viser hva som spores.

Lag malen ved å legge til en katalog som heter maler til kildekatalogen og opprett form1.html filen der:

   Raspberry Pi Tweetbox   

Dette er en veldig enkel form med en tekstinnmatingsboks og en sende-knapp. Det er alt som trengs på dette stadiet. Neste opprett omstart funksjon:

def restart (track_text): stream.disconnect () time.sleep (5) #Alle tiden for tråden for å koble fra ... stream.filter (track = [track_text], async = True) 

Dette kobler fra Twitter-strømmen og kobler den til igjen med det nye filteret, track_text, som er hva som ble sendt fra skjemaet. En viktig endring her, fra den forrige opplæringen, er at Twitter stream-tråden går i asynkron modus, Async = True. Dette kjører strømforbindelsen i en bakgrunnstråd, slik at webserveren kjører som hovedtråd.

Legg til et par linjer til slutten for å starte strømmen i asynkron modus og deretter starte webserveren:

stream.filter (spor = ['jeremy'], async = True) application.listen (8888) tornado.ioloop.IOLoop.instance (). start ()

Dette starter nettleserens lytte på port 8888. Pek på en nettleser på http: // din-raspi-ipaddress: 8888 / og du vil se skjemaet:

Tweetbox nettside skjema

Skriv inn noe annet å spore som bringebær og klikk på send inn. Etter fem sekunder vil det bytte til å spore disse tweets i stedet.

Fase 2: Fargekart og lagringskonfigurasjon

I dette stadiet legger jeg fargekartet til konfigurasjonen slik at du kan angi ordene som utløser RGB-bakgrunnsbelysningen for å endre. Siden det er syv innstillinger, ønsker jeg ikke å skrive inn disse hver gang jeg kjører programmet, så jeg lagrer disse til en fil.

Programmet bruker pickle for å lagre og laste konfigurasjonsfilen, pluss det er en opprinnelig Filen eksisterer sjekk så legg til denne importen til toppen:

importere pickle fra genericpath import eksisterer

De DisplayLoop Klassen er allerede ansvarlig for å administrere backlight_map så jeg vil forlenge dette slik at det tar vare på det jeg sporer nå, track_text. Les og skriv konfigureringsmetoder er også lagt til her:

klasse DisplayLoop (StreamListener): PICKLE_FILE = '/home/pi/py/tweetbox.pkl' def __init __ (selv): self.lcd = Adafruit_CharLCDPlate () self.lcd.backlight (self.lcd.RED) self.lcd.clear () self.track_text = 'jeremy' self.backlight_map = 'rød': self.lcd.RED, 'green': self.lcd.GREEN, 'blue': self.lcd.BLUE, 'yellow': selv. lcd.YELLOW, 'teal': self.lcd.TEAL, 'violet': self.lcd.VIOLET self.msglist = [] self.pos = 0 self.tweet = 'Ingenting ennå' def write_config (selv): data = "track_text": self.track_text, "backlight_map": self.backlight_map output = åpen (selv.PICKLE_FILE, 'wb') pickle.dump (data, output) output.close () def read_config eksisterer (selv.PICKLE_FILE): pkl_file = åpen (selv.PICKLE_FILE, 'rb') data = pickle.load (pkl_file) pkl_file.close () self.track_text = data ["track_text"] self.backlight_map = data ["backlight_map "] 

Endre forespørselshåndtererne for å ta vare på fargene. Også under vil du se at når jeg gjør hovedsiden jeg passerer i gjeldende konfigurasjon. Dette betyr at jeg kan fylle ut konfigureringsskjemaet med gjeldende innstillinger når det blir bedt om det.

klasse MainHandler (tornado.web.RequestHandler): def get (selv): inverted_map = v: k for k, v i display_loop_instance.backlight_map.items () self.render ("maler / form3.html", config_track = display_loop_instance .Configure_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]) klasse ConfigHandler (tornado.web.RequestHandler): def post (selv): config_track = self.get_argument ("config_track") colour_map = self.get_argument ("config_red"): Adafruit_CharLCDPlate.RED, selv .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_ argument ("config_violet"): Adafruit_CharLCDPlate.VIOLET set_config (config_track, colour_map) self.write ("Nå sporing% s"% config_track)

En teknikk for å merke seg her er hvordan jeg omverter fargekartet. Når jeg behandler det, vil jeg at kartet skal være ord> farge men når du konfigurerer det i det skjemaet jeg vil ha farge> ord. En Python Dictionary-forståelse kan brukes til å invertere kartet i en enkelt setning: v: k for k, v i display_loop_instance.backlight_map.items ()

En ny HTML-skjema er nødvendig for å støtte fargeinnstillingene. Også jeg trenger å fylle ut skjemainngangene med de nåværende innstillingene ved å bruke Tornados malingsystem. Dette er veldig grunnleggende, jeg tar bare verdiene som er overført til gjengi funksjon og trekk dem ut her i malen for eksempel config_track.

   Raspberry Pi Tweetbox   







Nå som jeg kan lagre og laste konfigurasjonen, den tidligere omstart rutinen må være litt mer sofistikert:

def set_config (track_text, colour_map): display_loop_instance.set_text ("Oppdaterer konfigurasjon") stream.disconnect () display_loop_instance.track_text = track_text display_loop_instance.backlight_map = colour_map display_loop_instance.write_config () time.sleep (5) #Alle tiden for tråden til koble fra ... stream.filter (spor = [display_loop_instance.track_text], async = True) display_loop_instance.set_text ("Oppdatert konfigurasjon") 

Siden det er mer enn en omstart, er navnet nå set_config. Det er her hvor jeg nå ringer write_config for å lagre endringene i filen.

Alt som er igjen er et par endringer for å lese i konfigurasjonen ved oppstart:

display_loop_instance = DisplayLoop () display_loop_instance.read_config ()

Og for å starte strømmen fra denne innstillingen i stedet for  'Jeremy':

stream = Stream (auth, display_loop_instance) stream.filter (spor = [display_loop_instance.track_text], async = True) 

Start programmet, pek på en nettleser på http: // din-raspi-ipaddress: 8888 / og du vil se skjemaet:

Nettformular

Fase 3: Etterbehandling

Det er noen ting som ikke er veldig slanke om dette programmet:

  • Forsink mens du oppdaterer konfigurasjonen
  • De Nå sporer ... svar etter å ha sendt skjemaet
  • Ugly form styling

Forsinkelsen mens konfigurasjonen endres, skyldes programets asynkrone karakter. Det er en tråd som styrer Twitter-strømmen, en tråd som ruller på skjermen og hovedtråden som kjører webserveren. 

Når jeg vil endre innstillingene på strømmen, må jeg koble den fra og deretter koble til igjen med de nye alternativene. Dessverre er det ingen hendelse fra tweepy å fortelle meg når jeg har koblet fra og så har jeg nettopp forsinket i fem sekunder mellom koble fra og koble til igjen. 

For å fjerne denne forsinkelsen, hva jeg skal gjøre, er å starte en ny tilkobling mens den gamle kobles fra, slik at jeg ikke må vente. Selvfølgelig betyr det at det på et tidspunkt kan være to bekker som mottar tweets. Dette ville være forvirrende på displayet siden du ville se den gamle sporen og den nye sporen kombinert. 

Derfor, før jeg kobler fra, kobler jeg den gamle strømmen til en lytter som ikke gjør noe med de innkommende tweets. Her er definisjonen av NullListener og endringene til set_config rutine:

klasse NullListener (StreamListener): def on_data (selvdata): pass def set_config (track_text, colour_map): skriv ut "start" display_loop_instance.set_text ("Oppdaterer konfigurasjon") #Kjør den gamle streamen asynkront global strøm stream.listener = NullListener ) stream.disconnect () display_loop_instance.track_text = track_text display_loop_instance.backlight_map = colour_map display_loop_instance.write_config () #Gjør en ny stream stream = Stream (auth, display_loop_instance) stream.filter (spor = [display_loop_instance.track_text], async = True) display_loop_instance.set_text ("Oppdatert konfigurasjon")

Angående Nå sporer ...  svar, er den nåværende versjonen av skjemaet sendt til ConfigHandler som endrer innstillingene og returnerer denne stygge responsen. Egentlig hva jeg vil ha er at skjemaet skal vises med de nye innstillingene på plass. 

Jeg kan oppnå dette ved å omdirigere brukeren tilbake til / URL. Også, det er virkelig ikke behov for ConfigHandler Uansett, kan jeg definere og post metoder på MainHandler og send inn skjemaet der i stedet:

klasse MainHandler (tornado.web.RequestHandler): def get (selv): inverted_map = v: k for k, v i display_loop_instance.backlight_map.items () self.render ("maler / form4.html", config_track = display_loop_instance .Configure_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 (selv): 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_argument ("config_violet"): Adafruit_CharLCDPlate.V IOLET set_config (config_track, colour_map) # Bruk en omdirigering for å unngå problemer med oppdateringer i nettleseren fra et skjema etter self.redirect ("/") application = tornado.web.Application ([(r "/" MainHandler) ])

Endelig styling. Gjør dette utseendet veldig vakkert kan være en helt ny opplæring i seg selv, men en veldig god start er å introdusere et rammeverk for å ta vare på mye styling for deg. 

Jeg er Bootstrap for styling og JQuery for scripting. Begge disse er tilgjengelige på CDN, slik at du ikke trenger å laste ned noe, bare ta med dem i hovedenheten på siden:

 Raspberry Pi Tweetbox       

For å få skjemaet til å se bedre ut, bruker vi Bootstraps Horisontale Form-stil:

Til slutt legger du litt polsk på brukergrensesnittet, vi vil indikere for brukeren at Raspberry Pi oppdateres når de klikker på sende inn knapp. Dette innebærer litt Javascript for å fange skjemainnleveringshendelsen, endre knappeteksten til Oppdatering ... og deaktiver knappen:

Og her er det ferdige nettbrukergrensesnittet:

Det ferdige webskjemaet

Konklusjon

Denne opplæringen har utvidet seg på den forrige for å legge til en web-brukergrensesnitt til RGB-LCD-boksen. Du kan nå kontrollere hva du følger på skjermen og bakgrunnslysene du vil ha fra telefonen, nettbrettet eller stasjonærmaskinen.