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..
sudo pip installer tornade
Tout le code de ce projet est disponible ici:
https://github.com/jerbly/tutorials/tree/master/tweetbox
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 TweetboxEntrez quelque chose d'autre à suivre comme framboise et cliquez sur soumettre. Après cinq secondes, il passera au suivi de ces tweets.
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 webIl y a quelques choses qui ne sont pas très faciles avec ce programme:
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 finiCe 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..