Le projet consiste à mettre en place un écran pour afficher des données venant d’autres périphériques (thermomètre, station météo, etc..), le flux twitter de l’IMERIR ainsi qu’un comptage du nombre de personnes au sein du FabLab.
Nous utiliserons un Raspberry Pi 3 pour traiter et afficher ces données.
Lien du GitLab : https://gitlab.imerir.com/vini.praion/screen-project
Étapes du projet
-
Étape 1
Démontage et conception du nouveau châssis de l'écran
Après avoir récupéré un moniteur d'ordinateur, nous l'avons démonté.
Une fois débarrassés de son châssis, nous avons poncé sa partie métallique afin de la peindre, cette plaque nous servira de support pour notre électronique.
Nous avons ensuite prototypé un nouveau châssis pour accueillir l'écran, qui sera composé des 2 plaques en plexiglass et 2 équerres.
On peut voir sur les images situées plus haut :
1) Le moniteur
2) Le support où seront fixés les parties électroniques (Raspberry Pi 3, interface vidéo avec alimentation..)
3) Conception du châssis sur Solidworks
4) Equerre qui maintiendra en position 2 plaques de plexiglass
5) Le résultat de la conception Solidworks
-
Étape 2
Initialisation du Raspberry Pi 3
Dès que le Raspberry Pi 3 est allumé, il va exécuter son script de communication MQTT que nous allons voir plus bas, ainsi qu'un script toutes les 60 secondes qui va générer des graphiques à l'aide des données récupérées via cette communication MQTT.
import loggingimport threadingimport timeimport scheduleimport osimport mosquittosubdef mosqui():mosquittosub.run()def rune():while True:print("Run Hydro Graph")print("Run Pression Graph")time.sleep(60)threading.Thread(target=rune).start()mosqui() -
Étape 3
Communication par protocole MQTT
Afin d'intéragir avec les autres périphériques (station météo, thermomètre, etc..) de façon sans-fil, nous utilisons le protocole MQTT (Message Queuing Telemetry Transport). C'est un protocole réseau conçu pour les connexions avec une bande passante limitée, et le choix ici est justifié vu le peu d'informations que nous souhaitons récupérer (valeur du capteur et date/heure).
Nous stockons ensuite les valeurs récupérées au sein d'un fichier CSV (Coma Separated Values).
# coding: utf-8""" Souscription au topic "fablab/#" sur le broker Eclipse Mosquitto.Utilise une autenthification login/mot-de-passe sur le broker"""import paho.mqtt.client as mqtt_clientfrom datetime import datetimeimport time# ConfigurationMQTT_BROKER = "IP"MQTT_PORT = "port"KEEP_ALIVE = 20 # intervale en secondedef on_log( client, userdata, level, buf ):print( "log: ",buf)def on_connect( client, userdata, flags, rc ):print( "Connexion: code retour = %d" % rc )print( "Connexion: Statut = %s" % ("OK" if rc==0 else "échec") )def on_message( client, userdata, message ):print( "Reception message MQTT..." )print( "Topic : %s" % message.topic )print( "Data : %s" % message.payload )now = datetime.now() # current date and timets = time.time()date_time = now.strftime("%Y/%m/%d, %H:%M:%S")date_time_csv = now.strftime("%Y%m%d%H%M%S")file1 = open('/var/www/html/data/data-' + message.topic.replace('/', '-') + '.txt',"a")file1.write( 'date: ' + str(ts) + '{ ' + 'topic: ' + message.topic + ' , ' + 'message: ' + message.payload + ' } \n' )file1.close()file2 = open('/var/www/html/data-csv/data-' + message.topic.replace('/', '-') + '.csv', "a")file2.write(str(ts) + ',' + message.payload + '\n')file2.close()def run():# Client(client_id=””, clean_session=True, userdata=None, protocol=MQTTv311, transport=”tcp”)client = mqtt_client.Client( client_id="client007" )# Assignation des fonctions de rappelclient.on_message = on_messageclient.on_connect = on_connect#client.on_log = on_log# Connexion brokerclient.connect( host=MQTT_BROKER, port=MQTT_PORT, keepalive=KEEP_ALIVE )client.subscribe( "fablab/#" )# Envoi des messagesclient.loop_forever() -
Étape 4
Génération de graphiques
Nous souhaitons mettre en place des graphiques qui montrent l'évolution des valeurs pour chaque capteur, afin de suivre un historique sur une certaine intervalle, plutôt qu'avoir uniquement à disposition la valeur du capteur sur l'instant T.
Pour se faire, nous générons un fichier image à l'aide de matplotlib. Nous lui donnons les dates sur l'axes des abscisses, et les valeurs sur l'axe des ordonnées.
Voici un exemple pour la génération du graphique de taux d'humidité dans l'air.
# coding: utf-8import matplotlibmatplotlib.use('Agg')import matplotlib.pyplot as pltfrom matplotlib.ticker import NullFormatter, FixedLocator, MultipleLocatorimport matplotlib.dates as mdatesimport numpy as npimport datetime as dtfrom datetime import datetimeimport csvimport timefrom statistics import meanpath = '/var/www/html/'#path = ''font1 = {'family':'serif','color':'blue','size':20}font2 = {'family':'serif','color':'darkred','size':15}x = []y = []with open(path + 'data-csv/data-fablab-weather-hydro.csv','r') as file:graph = file.read().replace("\0","")contents_split = graph.splitlines()for i in range(len(contents_split)):xety = contents_split[i].split(",")x.append(int(float(xety[0])))y.append(int(round(float(xety[1]),1)))timestamp = time.time()moyenne = mean(y)now = datetime.fromtimestamp(timestamp)then = now + dt.timedelta(seconds=len(x))hours = mdates.drange(now,then,dt.timedelta(seconds=1))plt.show(block=True)plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%H:%M'))plt.gca().xaxis.set_major_locator(mdates.SecondLocator(interval=60))plt.ylim([0, 100])plt.plot(hours[:len(y)],y)plt.gcf().autofmt_xdate()plt.ylabel('Humidite (%)', fontdict = font2)plt.xlabel('Heure', fontdict = font2)plt.title('Variation de l\'humidite dans l\'air (%)', fontdict = font1)plt.text(0.5,0.5,'Moyenne: ' + str(round(moyenne, 1)) + " (%) ",horizontalalignment='center',verticalalignment='center', transform = plt.gca().transAxes)plt.savefig(path + 'graph/hydro-graph.png')print("Ok SAVE HYDRO") -
Étape 5
Développement de l'interface graphique
Finalement, pour mettre en forme ces graphiques et ces valeurs, nous le faisons via un navigateur internet. La mise en place d'un serveur web a été indispensable, car par HTML/Javascript, pas possible de lire localement des fichiers. On a alors opté pour du PHP.
Pour la mise en page, nous avons utilisé "metroui" qui reprend l'interface des tuiles de Windows 8/Windows 10, des exemples sont disponibles à l'adresse suivante : https://metroui.org.ua
Cette page s'actualisera d'elle même toutes les minutes, afin de mettre à jour les dernières données récupérées.
<?phpfunction csvLastValue($path, $unitType){$dateTimeFormat = 'Y-m-d H:i:s';$handle = fopen($path, "r");$data = fgetcsv($handle);$value = $data[count($data) - 1];echo ($value . $unitType);fclose($handle);};?><!DOCTYPE html><html lang="fr"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"><meta name="twitter:site" content="@metroui"><meta name="twitter:creator" content="@pimenov_sergey"><meta name="twitter:card" content="summary"><meta name="twitter:title" content="Metro 4 Components Library"><meta name="twitter:description" content="Metro 4 is an open source toolkit for developing with HTML,CSS, and JS. Quickly prototype your ideas or build your entire app with responsive grid system,extensive prebuilt components, and powerful plugins."><meta property="og:title" content="Metro 4 Components Library"><meta property="og:description" content="Metro 4 is an open source toolkit for developing with HTML, CSS, and JS.Quickly prototype your ideas or build your entire app with responsive grid system,extensive prebuilt components, and powerful plugins ."><meta property="og:type" content="website"><meta property="og:image:type" content="image/png"><meta property="og:image:width" content="968"><meta property="og:image:height" content="504"><meta name="author" content="Sergey Pimenov"><meta name="description" content="The most popular HTML, CSS, and JS library in Metro style."><meta name="keywords" content="HTML, CSS, JS, Metro, CSS3, Javascript, HTML5, UI, Library,Web, Development, Framework"><link href="start.css" rel="stylesheet"><title>FABLAB IMERIR</title></head><body class="bg-dark fg-white h-vh-100 m4-cloak"><div class="container-fluid start-screen h-100"><h1 class="start-screen-title">FabLab</h1><div class="tiles-area clear"><div class="tiles-grid tiles-group size-2 fg-white" data-group-title="Télémétrie"><div data-role="tile" class="bg-cyan fg-white" data-size="medium"><span>//Todo Température ext</span><span class="branding-bar">Température Ext</span></div><div data-role="tile" class="bg-orange fg-white" data-size="medium"><span><?phpcsvLastValue("data-csv/data-fablab-thermo-int.csv", "°C");?></span><span class="branding-bar">Température Int</span></div><div data-role="tile" class="bg-cyan fg-white" data-size="medium"><span><?phpcsvLastValue("data-csv/data-fablab-wind.csv", "km/h");?></span><span class="branding-bar">Vitesse du vent</span></div><div data-role="tile" class="bg-orange fg-white" data-size="medium"><span><?phpcsvLastValue("data-csv/data-fablab-weather-hydro.csv", "% d'humidité");?></span><span class="branding-bar">Humidité Ext</span></div><div data-role="tile" class="bg-orange fg-white" data-size="medium"><span><?phpcsvLastValue("data-csv/data-fablab-weather-pression.csv", "hPa");?></span><span class="branding-bar">Pression Atmo</span></div><div data-role="tile" class="bg-orange fg-white" data-size="medium"><span><?php//csvLastValue("data-csv/data-fablab-weather-pression.csv", "hPa");?></span><span class="branding-bar">Personnes FabLab</span></div></div><div class="tiles-grid tiles-group size-2 fg-white" data-group-title="Graphiques Télémétrie"><a data-role="tile" data-cover="graph/thermo-ext.png" data-size="wide"href="graph/thermo-ext.png"><span class="branding-bar">Température Extérieure 24H</span></a><a data-role="tile" data-cover="graph/thermo-int.png" data-size="wide"href="graph/thermo-int.png"><span class="branding-bar">Température Intérieure 24H</span></a><a data-role="tile" data-cover="graph/wind-graph.png" data-size="wide"href="graph/wind-graph.png"><span class="branding-bar">Vitesse du vent 24H</span></a><a data-role="tile" data-cover="graph/hydro-graph.png" data-size="wide"href="graph/hydro-graph.png"><span class="branding-bar">Taux d'humidité</span></span></a><a data-role="tile" data-cover="graph/pression-graph.png" data-size="wide"href="graph/pression-graph.png"><span class="branding-bar">Pression </span></span></a><a data-role="tile" data-cover="graph/personnes-graph.png" data-size="wide"href="graph/personnes-graph.png"><span class="branding-bar">Personnes au sein du FabLab</span></a></div><div class="tiles-grid tiles-group size-2 fg-white" data-group-title="Twitter"data-size="wide"><a class="twitter-timeline" data-lang="fr" data-width="500" data-height="800"</div></div></div><script src="start.js"></script><script>setInterval(function(){window.location.reload()}, 60000);</script></body></html>
Commentaires (0)
Aucun commentaire pour le moment.