Comment ajouter une interface utilisateur Web à la zone de Tweet de l'écran LCD RVB

Ce que vous allez créer

Ce tutoriel prolonge le tutoriel précédent, Comment construire un écran LCD RVB contrôlé par Tweet, en ajoutant le contrôle de page Web. Avec cela, vous pouvez changer la configuration de la Tweetbox à la volée depuis votre ordinateur portable, votre tablette ou votre téléphone.. 

Vous apprendrez des techniques utiles dans ce tutoriel pour pouvoir ajouter le contrôle de page Web à vos propres projets Raspberry Pi.. 

Installer

  1. D'abord compléter le tutoriel précédent Comment construire un écran LCD RVB contrôlé par Tweet
  2. Installez Tornado:

sudo pip installer tornade

Tout le code de ce projet est disponible ici:

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

Étape 1: Forme de base

Pour récapituler, à la fin du didacticiel précédent, vous aviez un Raspberry Pi avec un écran LCD RVB connecté à Twitter qui recevait des tweets publics correspondant à un filtre. Le rétroéclairage RVB changerait de couleur en fonction des mots correspondants dans le tweet. Pour configurer le filtre et la palette de couleurs, vous avez dû changer le code et redémarrer le programme..

Dans cette première étape, je vais ajouter un serveur Web au programme. Ensuite, vous pouvez accéder à une page Web et mettre à jour la configuration en direct. Je vais utiliser Tornado, il existe de nombreux frameworks Web pour Python et j'en ai utilisé plusieurs au fil des ans, mais c’est maintenant mon aller à cadre. Il coche beaucoup de cases pour beaucoup de projets différents.

Regardez le Bonjour le monde exemple sur la page Tornado afin que vous puissiez voir comment configurer un gestionnaire et démarrer un thread de serveur Tornado. Je vais utiliser ce même principe exact ici.

Je prendrai le tweetbox.py code du tutoriel précédent et ajoutez le framework web. Pour commencer, je n'aurai qu'un simple formulaire nous permettant de changer ce que je suis en train de suivre sur Twitter. Tout d’abord, ajoutez quelques importations en haut du script:

importer tornado.ioloop importer tornado.web

Ensuite, j'ai besoin de deux gestionnaires: un pour afficher le formulaire HTML et un second pour recevoir la soumission du formulaire:

classe 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") redémarrer (config_track) self.write ("Suivi maintenant% s"% config_track) application = tornado.web.Application ([(r "/", MainHandler), (r "/ config", ConfigHandler),] )

Notez que MainHandler les usages obtenir et ConfigHandler les usages poster, Le formulaire HTML utilise la méthode de publication pour renvoyer les données du formulaire au serveur Web. Servir le formulaire le MainHandler appelle simplement la fonction de rendu pour obtenir un modèle rendu et envoyé au navigateur. Plus à ce sujet dans un instant.

Quand les données du formulaire reviennent ConfigHandler extrait un argument, config_track. Ceci est envoyé à un redémarrer fonction permettant de modifier les paramètres avec tweepy avant de renvoyer une simple chaîne indiquant ce qui est suivi.

Créez le modèle en ajoutant un répertoire appelé des modèles dans le répertoire source et créez le form1.html déposer ici:

   Raspberry Pi Tweetbox   

Ceci est un formulaire très simple avec une zone de saisie de texte et un bouton d'envoi. C'est tout ce qui est nécessaire à ce stade. Ensuite, créez le redémarrer une fonction:

def restart (track_text): stream.disconnect () time.sleep (5) #Laissez le temps au thread de se déconnecter… stream.filter (track = [track_text], async = True) 

Cela déconnecte le flux Twitter, puis le reconnecte avec le nouveau filtre., track_text, qui est ce qui a été soumis à partir du formulaire. Un changement important ici, par rapport au tutoriel précédent, est que le thread de flux Twitter s'exécute en mode asynchrone., async = True. Ceci exécute la connexion de flux dans un thread d'arrière-plan afin que le serveur Web s'exécute en tant que thread principal..

Ajoutez quelques lignes à la fin pour démarrer le flux en mode asynchrone, puis pour démarrer le serveur Web:

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

Le serveur Web commence alors à écouter sur le port 8888. Pointez un navigateur Web sur http: // your-raspi-ipaddress: 8888 / et vous verrez le formulaire:

Formulaire de page Web Tweetbox

Entrez quelque chose d'autre à suivre comme framboise et cliquez sur soumettre. Après cinq secondes, il passera au suivi de ces tweets.

Étape 2: Carte de couleurs et enregistrement de la configuration

Dans cette étape, j'ajouterai la carte de couleurs à la configuration afin que vous puissiez définir les mots qui déclenchent le changement de rétroéclairage RVB. Puisqu'il y a sept paramètres, je ne veux pas vraiment les ressaisir à chaque fois que je lance l'application, je vais donc les sauvegarder dans un fichier..

Le programme utilise pickle pour enregistrer et charger le fichier de configuration. le fichier existe Vérifiez donc ajoutez ces importations en haut:

importer pickle de genericpath import existe

le DisplayLoop classe est déjà responsable de la gestion de la backlight_map donc je vais étendre cela afin qu'il prenne soin de ce que je suis en train de suivre, track_text. Les méthodes de configuration en lecture et en écriture sont également ajoutées ici:

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, 'jaune': self. lcd.YELLOW, 'sarcelle': self.lcd.TEAL, 'violet': self.lcd.VIOLET self.msglist = [] self.pos = 0 self.tweet = 'Rien encore' par def write_config (self): data = "track_text": self.track_text, "backlight_map": self.backlight_map output = open (self.PICKLE_FILE, 'wb') pickle.dump (données, sortie) output.close () def read_config (self): if existe (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" "] 

Modifiez les gestionnaires de demandes pour qu’ils s’occupent des couleurs. Vous verrez également ci-dessous que lors du rendu de la page principale, je passe dans la configuration actuelle. Cela signifie que je peux remplir le formulaire de configuration avec les paramètres actuels à la demande.

classe MainHandler (tornado.web.RequestHandler): def get (self): inverted_map = v: k pour k, v dans display_loop_instance.backlight_map.items () self.render ("templates / form3.html", config_track = display_loop_instance Equipez-vous de la musique inverted_map [Adafruit_CharLCDPlate.VIOLET]) classe ConfigHandler (tornado.web.RequestHandler): def post (self): config_track = self.get_argument ("config_track") .get_argument ("config_green"): Adafruit_CLCLCDPlate, self.get_get , self.get_ argument ("config_violet"): Adafruit_CharLCDPlate.VIOLET set_config (config_track, colour_map) self.write ("Suivi du% s"% config_track)

Une technique à noter ici est la façon dont j'inverse la carte de couleurs. Lors du traitement, je souhaite que la carte soit mot> couleur mais lors de la configuration sous la forme que je veux couleur> mot. Une compréhension du dictionnaire Python peut être utilisée pour inverser la carte en une seule déclaration: v: k pour k, v dans display_loop_instance.backlight_map.items ()

Un nouveau formulaire HTML est requis pour prendre en charge les paramètres de couleur. De plus, je dois remplir les zones de saisie du formulaire avec les paramètres actuels en utilisant le système de modèles de Tornado. Ceci est très basique, je prends juste les valeurs transmises au rendre fonction et les tirer ici dans le modèle par exemple config_track.

   Raspberry Pi Tweetbox   







Maintenant que je peux sauvegarder et charger la configuration, l'ancien redémarrer la routine doit être un peu plus sophistiquée:

def set_config (track_text, colour_map): display_loop_instance.set_text ("Mise à jour de la configuration") stream.disconnect () display_loop_instance.track_text = track_text display_loop_instance.backlight_map = colour_map display_loop_instance.write_config () disconnect… stream.filter (track = [display_loop_instance.track_text], async = True) display_loop_instance.set_text ("Configuration mise à jour") 

Comme c'est plus qu'un redémarrage, son nom est maintenant set_config. C'est ici que j'appelle maintenant write_config enregistrer les modifications dans le fichier.

Il ne reste plus que quelques modifications à lire dans la configuration au démarrage:

display_loop_instance = DisplayLoop () display_loop_instance.read_config ()

Et pour démarrer le flux à partir de ce paramètre plutôt que  'jeremy':

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

Lancez le programme, pointez un navigateur Web à l'adresse http: // your-raspi-ipaddress: 8888 / et vous verrez le formulaire:

Formulaire web

Étape 3: Touches finales

Il y a quelques choses qui ne sont pas très faciles avec ce programme:

  • Retarder lors de la mise à jour de la configuration
  • le Maintenant suivi… réponse après soumission du formulaire
  • Style laide

Le délai de modification de la configuration est dû à la nature asynchrone du programme. Il existe un fil gérant le flux Twitter, un fil faisant défiler l'affichage et le fil principal exécutant le serveur Web.. 

Lorsque je souhaite modifier les paramètres du flux, je dois le déconnecter puis me reconnecter avec les nouvelles options. Il n'y a malheureusement aucun événement de tweepy à me dire quand j'ai réussi à me déconnecter et jusqu'à présent, je viens de retarder de cinq secondes la connexion et la reconnexion.. 

Pour supprimer ce délai, je vais commencer par établir une nouvelle connexion pendant que l’ancienne est en train de se déconnecter afin que je n’aie pas à attendre. Bien entendu, cela signifie qu’à un moment donné, deux flux peuvent recevoir des tweets. Cela serait déroutant à l’écran puisque vous verriez l’ancien suivi et le nouveau suivi combinés.. 

Par conséquent, juste avant de vous déconnecter, je vais connecter l'ancien flux à un écouteur qui ne fait rien avec les tweets entrants. Voici la définition de la NullListener et les changements à la set_config routine:

class NullListener (StreamListener): def on_data (self, data): pass def set_config (track_text, colour_map): print "restarting" display_loop_instance.set_text ("Mise à jour de la configuration") #Kill l'ancien flux de manière asynchrone global stream stream.listener = NullListener ( ) stream.disconnect () display_loop_instance.track_text = track_text display_loop_instance.backlight_map = colour_map display_loop_instance.write_config () #Make un nouveau flux stream = Stream (auth, display_loop_instance) stream.filter (track = [display_loop_instance.ackack)) display_loop_instance.set_text ("Configuration mise à jour")

En ce qui concerne la Maintenant suivi…  réponse, la version actuelle du formulaire est soumise au ConfigHandler qui modifie les paramètres et renvoie cette réponse laide. Ce que je veux vraiment, c’est que le formulaire réapparaisse avec les nouveaux paramètres en place.. 

Je peux y parvenir en redirigeant l’utilisateur vers le / URL En outre, il n'y a vraiment pas besoin de la ConfigHandler de toute façon, je peux définir le obtenir et poster méthodes sur le MainHandler et soumettez simplement le formulaire à la place:

classe MainHandler (tornado.web.RequestHandler): def get (self): inverted_map = v: k pour k, v dans display_loop_instance.backlight_map.items () self.render ("templates / form4.html", config_track = display_loop_instance Equipez-vous de la musique inverted_map [Adafruit_CharLCDPlate.VIOLET]) def post (self): config_track = self.get_argument ("config_track") colour_map = self.get_argument ("config_red"): Adafruit_CharLCDPlate.READ, un élément de base, à savoir: GREEN, self.get_argument ("config_blue"): Adafruit_CharLCDPlate.BLUE, self.get_argument ("config_yellow"): Adafruit_CharLCDPlate.YELLOW, self.get_argument ("config_yellow"): Adafruit_CharLCDPlate.YELLOW, self.get_argument ("config_teal"): Adafruit_CharLCDPlate.Yallow, sans nom. Adafruit_CharLCDPlate.V IOLET set_config (config_track, colour_map) #Utilisez une redirection pour éviter les problèmes d'actualisation dans le navigateur à partir d'un formulaire post self.redirect ("/") application = tornado.web.Application ([(r "/", MainHandler), ])

Enfin, le style. Rendre ce look vraiment magnifique pourrait être un tout nouveau didacticiel en soi, mais un très bon début consiste à introduire un cadre pour prendre en charge une grande partie du style pour vous.. 

Je suis Bootstrap pour le style et JQuery pour le script. Ces deux éléments sont disponibles sur les CDN. Vous n'avez donc pas besoin de télécharger quoi que ce soit. Il vous suffit de les inclure dans la section head de la page:

 Raspberry Pi Tweetbox       

Pour améliorer l'apparence du formulaire, nous allons utiliser le style de formulaire horizontal de Bootstrap:

Enfin, pour mettre un peu d’astuce à l’interface utilisateur, nous indiquerons à l’utilisateur que le Raspberry Pi est mis à jour lorsqu’il clique sur le bouton soumettre bouton. Cela implique un peu de Javascript pour capturer l’événement de soumission du formulaire, changer le texte du bouton en Mise à jour… et désactivez le bouton:

Et voici l'interface utilisateur Web terminée:

Le formulaire web fini

Conclusion

Ce didacticiel s’est développé sur le précédent pour ajouter une interface utilisateur Web à la zone de Tweet LCD RVB. Vous pouvez maintenant contrôler ce que vous suivez à l'écran et les couleurs de rétroéclairage de votre téléphone, de votre tablette ou de votre ordinateur de bureau..