=====Application serveur de données capteurs===== #!/usr/bin/python3 # Bertrand Vandeportaele 2019 # https://pymotw.com/2/socket/udp.html import socket import sys import fcntl, errno, os #pour threads from threading import Thread, Lock #à cause de la GIL, ce n'est pas du vrai multithread, lire https://stackoverflow.com/questions/3310049/proper-use-of-mutexes-in-python #il faudrait utiliser multiprocessing au lieu de threading #from multiprocessing import Process, Lock # https://stackoverflow.com/questions/22885775/what-is-the-difference-between-lock-and-rlock import _thread import time # https://docs.python.org/fr/3/library/time.html #création d'une thread par connexion TCP #https://www.geeksforgeeks.org/socket-programming-multi-threading-python/ '''idée pour identification des messages: chaque capteur envoie dans le message son adresse mac (et les simulateurs en génère une par capteur simulé) si la trame passe par un routeur, il n'est pas possible d'avoir l'adresse mac du capteur autrement... plusieurs messages différents possible par capteur en ajoutant 16 bits en suffixe à l'adresse mac (equivalent numero de port) requete au serveur de capteur de 2 types possibles par annuaire de fonctionnalité par numero d'adresse mac requete pour récupérer les infos capteur requete pour récupérer les infos d'identification d'un capteur TODO: au démarage (et régulièrement) une carte capteur s'identifie dans l'annuaire en indiquant son @MAC + une chaine de caractère qui décrit ce que fournit le capteur champs, unité date et heure de compilation du programme auteur du code l'annuaire est sauvé dans un fichier texte en local et se reconstruit au fûr et a mesure on y stocke notamment la date et l'heure de dernière reception du capteur gérer les changements de formats de données capteur ou le remplacement d'une fonctionnalité @mac carte joystick: bc:dd:c2:fe:6f:f0 ''' '''todo: identifier si une donnée capteur est -seule la dernière est utile -peut elle être consommée plusieurs fois la même ou pas? -est au client de vérifier si la donnée a déjà été lue? (auquel cas il faudrait un indice) -toutes sont utiles en séquence, auquel cas il faut mettre en place une gestion de fifo pour les données qui ne tolèrent pas de pertes (encore que l'UDP entre le capteur et le serveur ne soit pas forcement adapté pour ca... timestamper les données recues depuis les capteurs lors d'une requette ''' ######################################################################################################################## class DataBuffer: def __init__(self,nbinit): self.mutex = Lock() self.nb=nbinit; self.dataBuffer=[] self.nbdata=0 #initialisation avec des valeurs en "rampe" de 0 à 1 with self.mutex: for ix in range(1, self.nb+ 1): self.dataBuffer.append([ ix/self.nb]) def setData(self,i,val): #print("tentative d'écriture à indice %s de la valeur %s" % (i , val)) if (i>=self.nb): print("tentative d'écriture à indice %s trop grand" % (i)) return 0 else: with self.mutex: self.nbdata+=1 self.dataBuffer[i]=val def getData(self,i): if (i>=self.nb): print("tentative de lecture à indice %s trop grand" % (i)) return 0 else: with self.mutex: return self.dataBuffer[i] # question: est ce que c'est bien la valeur qui est copiée lors du return, et non pas une référence, auquel cas hors # du mutex, la valeur référencée pourrait devenir incohérente ######################################################################################################################## #réception des données depuis les différents capteurs en UDP sur port 10000 #https://riptutorial.com/fr/python/example/4985/recevoir-des-donnees-via-udp class CommSensor(Thread): def __init__(self, sharedDataInit): Thread.__init__(self) self.sharedData=sharedDataInit; self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.sock.bind(('', 10000)) # premier champ vide pour recevoir depuis n'importe quelle adresse,sinon IP en chaine de caractères #self.sock.setblocking(0) self.oldti=0 #self.displayIncommingFromSensor=False self.displayIncommingFromSensor=True def run(self): while True: #print('thread CommSensor '); msg, addr = self.sock.recvfrom(8192) # This is the amount of bytes to read at maximum if self.displayIncommingFromSensor: print("Got message from %s: %s" % (addr, msg )) change=1; #pour un seul champ # self.sharedData.dataBuffer[0]=int(msg) # print("valeur recue: " + str(self.sharedData.dataBuffer[0])) #pour plusieurs champs ti=time.time() chaine=str(self.sharedData.nbdata) + " valeurs recues: "; chaine+=str(ti)+ " " +str(ti-self.oldti) + " " listfields=msg.split() if (len(listfields)>1): # if False: #pour plus tard quand je gérerai l'identification des messages if True: adresseMAC=listfields[0] chaine += " @MAC: "+ adresseMAC.decode('utf-8') + " " try: numero_data=int(listfields[1]) chaine += "num: " + str(numero_data) +" " for i in range(0, len(listfields)-2): # self.sharedData.dataBuffer[0+i]=int(listfields[i]) self.sharedData.setData(numero_data+i,float(listfields[i+2])) chaine+=str(numero_data+i) + " -> " + str(self.sharedData.getData(numero_data+i)) + " , " ; if self.displayIncommingFromSensor: print(chaine) except ValueError: if self.displayIncommingFromSensor: print("erreur parsing") continue self.oldti=ti #TODO tuer ce thread lorsque la fenêtre principale ferme ######################################################################################################################## #chaque client voulant lire des données capteurs se connecte en TCP, ce qui crée une thread à chaque connexion #https://riptutorial.com/fr/python/example/4985/recevoir-des-donnees-via-udp class CommServer(Thread): ##########################################################"" def __init__(self, sharedDataInit): Thread.__init__(self) self.sharedData=sharedDataInit; #self.displayIncommingFromClient=False #self.displayResponseToClient=False self.displayIncommingFromClient=True self.displayResponseToClient=True ##########################################################"" def run(self): print("New Thread server") # http://sametmax.com/les-context-managers-et-le-mot-cle-with-en-python/ #utilisation du context manager pour libérer les ressources socket quand on quitte l'appli #https://stackoverflow.com/questions/16772465/how-to-use-socket-in-python-as-a-context-manager #https://hg.python.org/cpython/file/e57c8a90b2df/Lib/socket.py#l87 #oui la methode __exit__( de socket ferme bien la socket! with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: host = "" port = 30000 s.bind((host, port)) # premier champ vide pour recevoir depuis n'importe quelle adresse,sinon IP en chaine de caractères print("socket binded to port", port) # put the socket into listening mode s.listen(5) print("socket is listening") # a forever loop until client wants to exit while True: # establish connection with client c, addr = s.accept() # lock acquired by client # print_lock.acquire() print('Connected to :', addr[0], ':', addr[1]) # Start a new thread and return its identifier _thread.start_new_thread(self.threaded, (c,)) #s.close() ##########################################################"" # thread fuction def threaded(self,c): while True: # data received from client data = c.recv(1024) if self.displayIncommingFromClient: print("receving " + str(data)) if not data: print('Bye') # lock released on exit # print_lock.release() break # sort du while -> déconnexion # décodage de la requete: format r n1 n2... listfields = data.split() if self.displayIncommingFromClient: print(str(listfields)) reponse ="" if listfields[0]==b'r': for i in range(1, len(listfields)): #saute le premier champ nbdatarequise=int(listfields[i]) reponse+= str(self.sharedData.getData(nbdatarequise)) + " "; else: print("probleme formatage requete") # conn.sendall(data) #reponse = str(self.sharedData.dataBuffer[0]) + chr(13) # + chr(10) : ne pas mettre le 10 sinon VAL3 interprete comme un caracatère débutant la chaine suiavnte... reponse+= chr(13) # + chr(10) : ne pas mettre le 10 sinon VAL3 interprete comme un caracatère débutant la chaine suiavnte... if self.displayResponseToClient: print("sending " + str(reponse)) c.sendall(reponse.encode('utf-8')) # connection closed c.close() ''' s1, s2 = socket.socketpair() b1 = bytearray(b'----') b2 = bytearray(b'0123456789') b3 = bytearray(b'--------------') s2.recvmsg_into([b1, memoryview(b2)[2:9], b3]) (22, [], 0, None) [b1, b2, b3] ''' #time.sleep(1) # TODO tuer tous ces thread thread lorsque la fenêtre principale ferme # https://stackoverflow.com/questions/323972/is-there-any-way-to-kill-a-thread # on ne doit pas tuer les threads à la bourrin (par contre possible avec process # facon propre : https://dzone.com/articles/understanding ######################################################################################################################## if __name__ == '__main__': try: sharedData=DataBuffer(10000); #10000 données capteur différentes au max thread_1 = CommSensor(sharedData); thread_1.start() thread_2 = CommServer(sharedData); thread_2.start() # Attend que les threads se terminent #thread_1.join() #thread_2.join() while True: time.sleep(1) #print("...") except KeyboardInterrupt: #print("attente fin thread 1") #thread_1.join() print("bye") #dans pyCharm, cliquer sur la tête de mort rouge pour bien tuer tout les processus et libérer les numeros de ports (envoi de SIGKILL) #NE PAS SE CONNECTER AU WIFI ROBOT AIP SI J'UTILISE PC RAPID avec IP 1.49 #ajouter un mutex sur les données partagées =====Application simulateur de client capteurs===== #!/usr/bin/python3 #https://realpython.com/python-sockets/ import socket HOST = '127.0.0.1' # The server's hostname or IP address PORT = 30000 # The port used by the server with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((HOST, PORT)) s.sendall(b'r 0 1 2') data = s.recv(1024) print('Received', repr(data)) =====Application simulateur de client capteurs en continu===== #!/usr/bin/python3 import time # https://docs.python.org/fr/3/library/time.html #https://realpython.com/python-sockets/ import socket HOST = '127.0.0.1' # The server's hostname or IP address PORT = 30000 # The port used by the server ######################################################################################################################## if __name__ == '__main__': try: with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((HOST, PORT)) while True: s.sendall(b'r 1 2 3') data = s.recv(1024) # print('Received', repr(data)) print(repr(data)) time.sleep(0.01) except KeyboardInterrupt: print("bye") =====Application simulateur de robot 6R staubli===== #!/usr/bin/python3 # -*- coding: utf-8 -* #Bertrand Vandeportaele 2019 import os import sys from PyQt4.QtGui import * from PyQt4.QtNetwork import * from PyQt4.QtCore import * from PyQt4 import * import re #pour découpage chaine comme sur https://stackoverflow.com/questions/2175080/sscanf-in-python global numeroPremiereDonneeCapteur #TODO: donner une valeur à cette variable en fonction de votre numéro d'étudiant numeroPremiereDonneeCapteur=100 global etatBouton etatBouton=0 global slider1Value slider1Value=0 global slider2Value slider2Value=0 global slider3Value slider3Value=0 global slider4Value slider4Value=0 global slider5Value slider5Value=0 global slider6Value slider6Value=0 global led0Button ################################################################################ def close(): print('close') exit(0) ################################################################################ def commutTimer(): global timer print('commutTimer') if timer.isActive(): timer.stop() commutTimerButton.setText('start stream sensor') else: timer.start() commutTimerButton.setText('stop stream sensor') ################################################################################ def slider1ValueChanged( value ): #label.setText( str( value ) global numeroPremiereDonneeCapteur global labelSlider1Value global slider1Value slider1Value=value #labelSlider1Value.setText( "J1: "+str(slider1Value) ) #https://mkaz.blog/code/python-string-format-cookbook/ labelSlider1Value.setText( str( numeroPremiereDonneeCapteur+0)+ " -> J1: {:6d}".format(slider1Value) ) print('changed') ################################################################################ def slider2ValueChanged( value ): #label.setText( str( value ) global numeroPremiereDonneeCapteur global labelSlider2Value global slider2Value slider2Value=value labelSlider2Value.setText( str( numeroPremiereDonneeCapteur+1)+ " -> J2: {:6d}".format(slider2Value) ) print('changed') ################################################################################ def slider3ValueChanged( value ): #label.setText( str( value ) global numeroPremiereDonneeCapteur global labelSlider3Value global slider3Value slider3Value=value labelSlider3Value.setText( str( numeroPremiereDonneeCapteur+2)+ " -> J3: {:6d}".format(slider3Value) ) print('changed') ################################################################################ def slider4ValueChanged( value ): #label.setText( str( value ) global numeroPremiereDonneeCapteur global labelSlider4Value global slider4Value slider4Value=value labelSlider4Value.setText( str( numeroPremiereDonneeCapteur+3)+ " -> J4: {:6d}".format(slider4Value) ) print('changed') ################################################################################ def slider5ValueChanged( value ): #label.setText( str( value ) global numeroPremiereDonneeCapteur global labelSlider5Value global slider5Value slider5Value=value labelSlider5Value.setText( str( numeroPremiereDonneeCapteur+4)+ " -> J5: {:6d}".format(slider5Value) ) print('changed') ################################################################################ def slider6ValueChanged( value ): #label.setText( str( value ) global numeroPremiereDonneeCapteur global labelSlider6Value global slider6Value slider6Value=value labelSlider6Value.setText( str( numeroPremiereDonneeCapteur+5)+ " -> J6: {:6d}".format(slider6Value) ) print('changed') ################################################################################ def bouton0(): global numeroPremiereDonneeCapteur global led0Button global etatBouton global labelButtonValue etatBouton=(etatBouton+1)%2 if etatBouton==0: led0Button.setText('Activer la sortie TOR') else: led0Button.setText('Desactiver la sortie TOR') labelButtonValue.setText( str( numeroPremiereDonneeCapteur+6)+" : {:6d}".format(etatBouton) ) print('etatBouton: '+ str(etatBouton) +" \n"); # led0Button.setText('Appuyer sur le bouton') # else: # led0Button.setText('Relacher le bouton') ################################################################################ def sendUDP(i): global numeroPremiereDonneeCapteur global udpSocket global destIP global portOut DestIP = QHostAddress(destIP); global slider1Value global slider2Value global slider3Value global slider4Value global slider5Value global slider6Value global etatBouton # chaine=str(slider1Value)+ " " + str(slider2Value) #ajout @MAC bidon # chaine="00:00:00:00:00:00 "+str(slider1Value)+ " " + str(slider2Value) #ajout champs vides pour être compatible avec le joystick wifi #@MAC: BC:DD:C2:FE:6F:F0 num: 0 0 -> 529.0 , 1 -> 534.0 , 2 -> 0.0 , 3 -> 0.0 , 4 -> 0.0 , 5 -> -73.0 , 6 -> 63.0 , chaine="00:00:00:00:00:00 "+str(numeroPremiereDonneeCapteur)+ " " +str(slider1Value)+ " " + str(slider2Value) + " " + str(slider3Value) + " " + str(slider4Value) + " " + str(slider5Value) + " " + str(slider6Value)+" " +str(etatBouton) #chaines bidons pour générer erreur de parsing sur le serveur # chaine="00:00:00:00:00:00 0 0 0 "+"687f"+" 0 0 "+str(slider1Value)+ " " + str(slider2Value) chaine=chaine+chr(13)+chr(10) print("la chaine envoyée est: "+chaine) udpSocket.writeDatagram(chaine,DestIP, portOut); ################################################################################ def timerUpdate(): sendUDP(0) ################################################################################ global led0Button #destIP='192.168.1.50' #pc simulateur #destIP='192.168.0.112' #pc simulateur #destIP='192.168.1.49' #pc serveur rapid connecté en filaire à réseau AIP destIP='127.0.0.1' #pc serveur sur la boucle locale portOut=10000 posx=10 posy=10 sizex=500 sizey=150 ################################################################################ #par défaut: numeroPremiereDonneeCapteur= 100 #option -n pour choisir numeroPremiereDonneeCapteur if len(sys.argv)==3: if sys.argv[1]=='-n': numeroPremiereDonneeCapteur= int(sys.argv[2]) print("réglage de numeroPremiereDonneeCapteur à: ",str(numeroPremiereDonneeCapteur)); app = QApplication(sys.argv) w=QDialog() statusLabel =QLabel('En attente de datagrammes UDP depuis le PIC32') commutTimerButton=QPushButton('stop stream sensor') quitButton = QPushButton('&Quit') led0Button = QPushButton('Activer la sortie TOR') udpSocket =QUdpSocket() udpSocket.bind(portOut, QUdpSocket.ShareAddress) app.connect(quitButton,QtCore.SIGNAL('clicked()'), close) app.connect(commutTimerButton, QtCore.SIGNAL('clicked()'), commutTimer) app.connect(led0Button,QtCore.SIGNAL('clicked()'), bouton0) buttonLayout =QHBoxLayout() buttonLayout.addStretch(1) buttonLayout.addWidget(quitButton) buttonLayout.addWidget(commutTimerButton) buttonLayout.addStretch(1) #button1Layout =QHBoxLayout() #button1Layout.addStretch(1) #button1Layout.addWidget(led0Button) #button1Layout.addStretch(1) global labelButtonValue labelButtonValue=QLabel( ) labelButtonValue.setGeometry(250, 50, 50, 35) #labelButtonValue.setText( "x: "+str(0 ) ) labelButtonValue.setText( str( numeroPremiereDonneeCapteur+6)+" : {:6d}".format(0) ) button1Layout =QHBoxLayout() button1Layout.addStretch(1) button1Layout.addWidget(labelButtonValue) button1Layout.addStretch(1) button1Layout.addWidget(led0Button) button1Layout.addStretch(1) #http://koor.fr/Python/CodeSamplesQt/PyQtSlider.wp ################################### slider1 = QSlider(Qt.Horizontal); slider1.setMinimum(-160) slider1.setMaximum(160) slider1.setGeometry( 10, 10, 600, 40 ) slider1.valueChanged.connect(slider1ValueChanged ) slider1.setValue( 0 ) global labelSlider1Value labelSlider1Value=QLabel( ) labelSlider1Value.setGeometry(250, 50, 50, 35) labelSlider1Value.setText( str( numeroPremiereDonneeCapteur+0)+ " -> J1: "+str(0 ) ) slider1Layout =QHBoxLayout() slider1Layout.addWidget(labelSlider1Value) slider1Layout.addWidget(slider1) ################################### slider2 = QSlider(Qt.Horizontal); slider2.setMinimum(-127.5) slider2.setMaximum(127.5) slider2.setGeometry( 10, 10, 600, 40 ) slider2.valueChanged.connect(slider2ValueChanged ) slider2.setValue( 0 ) global labelSlider2Value labelSlider2Value=QLabel( ) labelSlider2Value.setGeometry(250, 50, 50, 35) labelSlider2Value.setText( str( numeroPremiereDonneeCapteur+1)+ " -> J2: "+str(0 ) ) slider2Layout =QHBoxLayout() slider2Layout.addWidget(labelSlider2Value) slider2Layout.addWidget(slider2) ################################### slider3 = QSlider(Qt.Horizontal); slider3.setMinimum(-134.5) slider3.setMaximum(134.5) slider3.setGeometry( 10, 10, 600, 40 ) slider3.valueChanged.connect(slider3ValueChanged ) slider3.setValue( 0 ) global labelSlider3Value labelSlider3Value=QLabel( ) labelSlider3Value.setGeometry(250, 50, 50, 35) labelSlider3Value.setText( str( numeroPremiereDonneeCapteur+2)+ " -> J3: "+str(0 ) ) slider3Layout =QHBoxLayout() slider3Layout.addWidget(labelSlider3Value) slider3Layout.addWidget(slider3) ################################### slider4 = QSlider(Qt.Horizontal); slider4.setMinimum(-270) slider4.setMaximum(270) slider4.setGeometry( 10, 10, 600, 40 ) slider4.valueChanged.connect(slider4ValueChanged ) slider4.setValue( 0 ) global labelSlider4Value labelSlider4Value=QLabel( ) labelSlider4Value.setGeometry(250, 50, 50, 35) labelSlider4Value.setText( str( numeroPremiereDonneeCapteur+3)+ " -> J4: "+str(0 ) ) slider4Layout =QHBoxLayout() slider4Layout.addWidget(labelSlider4Value) slider4Layout.addWidget(slider4) ################################### slider5 = QSlider(Qt.Horizontal); slider5.setMinimum(-109.5) slider5.setMaximum(+120.5) slider5.setGeometry( 10, 10, 600, 40 ) slider5.valueChanged.connect(slider5ValueChanged ) slider5.setValue( 0 ) global labelSlider5Value labelSlider5Value=QLabel( ) labelSlider5Value.setGeometry(250, 50, 50, 35) labelSlider5Value.setText( str( numeroPremiereDonneeCapteur+4)+ " -> J5: "+str(0 ) ) slider5Layout =QHBoxLayout() slider5Layout.addWidget(labelSlider5Value) slider5Layout.addWidget(slider5) ################################### slider6 = QSlider(Qt.Horizontal); slider6.setMinimum(-270) slider6.setMaximum(270) slider6.setGeometry( 10, 10, 600, 40 ) slider6.valueChanged.connect(slider6ValueChanged ) slider6.setValue( 0 ) global labelSlider6Value labelSlider6Value=QLabel( ) labelSlider6Value.setGeometry(250, 50, 50, 35) labelSlider6Value.setText( str( numeroPremiereDonneeCapteur+5)+ " -> J6: "+str(0 ) ) slider6Layout =QHBoxLayout() slider6Layout.addWidget(labelSlider6Value) slider6Layout.addWidget(slider6) ################################### sliderLayout =QVBoxLayout() sliderLayout.addStretch(1) sliderLayout.addLayout(slider1Layout) sliderLayout.addStretch(1) sliderLayout.addLayout(slider2Layout) sliderLayout.addStretch(1) sliderLayout.addLayout(slider3Layout) sliderLayout.addStretch(1) sliderLayout.addLayout(slider4Layout) sliderLayout.addStretch(1) sliderLayout.addLayout(slider5Layout) sliderLayout.addStretch(1) sliderLayout.addLayout(slider6Layout) sliderLayout.addStretch(1) mainLayout = QVBoxLayout() mainLayout.addLayout(buttonLayout) mainLayout.addLayout(sliderLayout) mainLayout.addLayout(button1Layout) mainLayout.addWidget(statusLabel) w.setLayout(mainLayout) chaine='@BVDP2021: Port Em '+str(portOut) +' vers IP: '+str(destIP) w.setWindowTitle(chaine) #timer adapted from example 1 of https://www.programcreek.com/python/example/52106/PyQt4.QtCore.QTimer timer = QtCore.QTimer() app.connect(timer, QtCore.SIGNAL('timeout()'), timerUpdate) timer.setInterval(100) timer.start() w.setGeometry(posx,posy,sizex,sizey) #donne le focus au bouton 1 led0Button.setDefault(True) w.show() app.exec_() =====Application affichage animé de données capteurs===== #!/usr/bin/python3 #trouvé sur https://stackoverflow.com/questions/48389470/python-update-matplotlib-from-threads import matplotlib.pyplot as plt from matplotlib.animation import FuncAnimation import numpy as np import threading import random import time import socket HOST = '127.0.0.1' # The server's hostname or IP address PORT = 30000 # The port used by the server class MyDataClass(): def __init__(self): self.XData = [0] self.YData = [0] #self.Y2Data = [0] class MyPlotClass(): def __init__(self, dataClass): self._dataClass = dataClass self.hLine, = plt.plot(0, 0) self.ani = FuncAnimation(plt.gcf(), self.run, interval = 30, repeat=True) #30 ms entre affichage def run(self, i): print("plotting data") self.hLine.set_data(self._dataClass.XData, self._dataClass.YData) self.hLine.axes.relim() self.hLine.axes.autoscale_view() class MyDataFetchClass(threading.Thread): def __init__(self, dataClass): threading.Thread.__init__(self) self._dataClass = dataClass self._period = 0.1 #durée d'attente entre lecture sur socket self._nextCall = time.time() # with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as self.s: #todo gérer probleme de connexion self.s= socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.s.connect((HOST, PORT)) def run(self): # while True: # print("updating data") # # add data to data class # self._dataClass.XData.append(self._dataClass.XData[-1] + 1) # self._dataClass.YData.append(random.randint(0, 256)) # # sleep until next execution # self._nextCall = self._nextCall + self._period; # time.sleep(self._nextCall - time.time()) while True: print("updating data") modeYT=True if modeYT: self.s.sendall(b'r 1 2 3') else: s.sendall(b'r 6 7 3') data = self.s.recv(1024) # print('Received', repr(data)) print(repr(data)) ti = time.time() listfields = data.split() if modeYT: self._dataClass.XData.append(self._dataClass.XData[-1] + 1) self._dataClass.YData.append(float(listfields[0])) # sleep until next execution self._nextCall = self._nextCall + self._period; time.sleep(self._nextCall - time.time()) #x.append(i) #y.append(float(listfields[0])) #y2.append(float(listfields[1])) # # else: # x.append(float(listfields[0])) # y.append(float(listfields[1])) #if ((float)(listfields[2])==1.0): # bouton pressé, on efface #x.clear() #y.clear() # il faudrait effacer la figure # i+=1 # y.append(psutil.cpu_percent()) # ax.plot(x,y,color='b') # if modeYT: # ax.plot(x, y2, color='r') # ax.set_xlim(left=max(0,i-50),right=i+50) # fig.canvas.draw() # time.sleep(0.01) # except KeyboardInterrupt: # print("bye") data = MyDataClass() plotter = MyPlotClass(data) fetcher = MyDataFetchClass(data) fetcher.start() plt.show() #fetcher.join() =====Programme ESP8266 pour capteur===== Un même programme pour différents capteurs, le choix du comportement du programme se fait à l'aide de macro dans le programme pour (des)activer certaines fonctionnalités. //B. Vandeportaele 2019 //choisir la carte NodeMCU1.0(ESP12E module) //pour uploader, presser le bouton reset quand l'ide arduino affiche "connecting..." puis relacher //régler les macros suivantes pour régler le comportement de la carte: //#define HX711PRESENT #define JOYPRESENT #include #include #include WiFiUDP Client; #include #define WSout D2 #define PIXELCOUNT 2 Adafruit_NeoPixel pixels = Adafruit_NeoPixel(PIXELCOUNT, WSout, NEO_GRB + NEO_KHZ800); // A UDP instance to let us send and receive packets over UDP WiFiUDP udp; // wifi connection variables unsigned int localPort = 10000; // local port to listen for UDP packets #include "listereseauxwifi.h" //const char* ssid = "78BF39"; //const char* password = "6D842DAE4B"; char *MACADDRESS=NULL; #define TRANSMITOVERWIFI #ifdef TRANSMITOVERWIFI //String ip = "192.168.1.49"; // the remote IP address IPAddress Ip; #endif // /home/bvandepo/.arduino15/packages/esp8266/hardware/esp8266/2.3.0-rc2/libraries/ESP8266WiFi/src/ESP8266WiFi.h // /home/bvandepo/.arduino15/packages/esp8266/hardware/esp8266/2.3.0-rc2/cores/esp8266/IPAddress.h ////////////////////////// //i2c //#include //attention le code de la balance est bloquant, et donc si le module HX711 n'est pas présent mais que le code est executé, l'esp8266 va faire un watchdog reset et ceci apparait sur la console série: // esp8266 ets Jan 8 2013,rst cause:2, boot mode:(3,7) /* The codes are : 0 -> normal startup by power on 1 -> hardware watch dog reset 2 -> software watch dog reset (From an exception) 3 -> software watch dog reset system_restart (Possibly unfed watchdog got angry) 4 -> soft restart (Possibly with a restart command) 5 -> wake up from deep-sleep Looking at the provided code you can decide from what reason the chip is restarting. */ #ifdef HX711PRESENT #include "HX711.h" HX711 scale(D4, D3); // DOUT, SCK #endif #ifdef JOYPRESENT ////////////////////////////////////////// class JoystickESP8266CD4053B { //L'entrée analogique est forcément A0, car c'est la seule private: int16_t minX, maxX, minY, maxY; float xFactor, yFactor; int16_t centerX, centerY, dZ; uint8_t pinSelect, pinB; int16_t iX, iY; //position intégrée int16_t b; //bouton 1=pressé int16_t X, Y; //position lue int16_t dX, dY; //différence de position par rapport au Zero public: JoystickESP8266CD4053B(uint8_t pinSelectinit, uint8_t pinBinit, int16_t dZinit) { pinSelect = pinSelectinit; pinB = pinBinit; dZ = dZinit; //dead Zone //par défaut les limites pour x et y sont les valeurs min et max codable minX = -32768; maxX = 32767; minY = -32768; maxY = 32767; xFactor = 1; yFactor = 1; } void init() { //analogRead ne fonctionne pas avant appel de setup() pinMode(pinSelect, OUTPUT); pinMode(pinB, INPUT_PULLUP); //pull up pour bouton iX = 0; iY = 0; digitalWrite(pinSelect, LOW); delayMicroseconds(3); centerX = analogRead(A0); digitalWrite(pinSelect, HIGH); delayMicroseconds(3); centerY = analogRead(A0); b = !digitalRead(pinB); } void setLimits(int16_t minXinit, int16_t maxXinit, int16_t minYinit, int16_t maxYinit) { minX = minXinit; maxX = maxXinit; minY = minYinit; maxY = maxYinit; } void setPos(int16_t xinit, int16_t yinit) { iX = xinit; iY = yinit; } void setPosCenter() { iX = (maxX + minX) / 2; iY = (maxY + minY) / 2; } void setFactorOrientation(float xFactorInit, float yFactorInit) { xFactor = xFactorInit; yFactor = yFactorInit; } void update() { digitalWrite(pinSelect, LOW); delayMicroseconds(3); X = analogRead(A0); digitalWrite(pinSelect, HIGH); delayMicroseconds(3); Y = analogRead(A0); dX = (X - centerX) * xFactor; dY = (Y - centerY) * yFactor; /*if (abs(dX)>dZ) x=x+dX; if (abs(dY)>dZ) y=y+dY; */ if (dX > dZ) if (iX < maxX - dX) iX = iX + dX; else iX = maxX; if (dX < -dZ) if (iX > minX - dX) iX = iX + dX; else iX = minX; if (dY > dZ) if (iY < maxY - dY) iY = iY + dY; else iY = maxY; if (dY < -dZ) if (iY > minY - dY) iY = iY + dY; else iY = minY; b = !digitalRead(pinB); /* Serial.print("centerX: "); Serial.print(centerX); Serial.print("centerY: "); Serial.println(centerY); Serial.print("dX: "); Serial.print(dX); Serial.print("dY: "); Serial.println(dY); */ } int16_t getdX() { return dX; } int16_t getdY() { return dY; } int16_t getiX() { return iX; } int16_t getiY() { return iY; } int16_t getX() { return X; } int16_t getY() { return Y; } int16_t getB() { return b; } bool isUp() { return (Y > centerY + dZ); } bool isDown() { return (Y < centerY - dZ); } bool isLeft() { return (X > centerX + dZ); } bool isRight() { return (X < centerY - dZ); } }; ////////////////////////////////////////// JoystickESP8266CD4053B joy(D3, D4, 3); #endif ////////////////////////////////////////// void Debug(char * msg) { #if 1 Serial.print(msg); #endif } ////////////////////////////////////////// unsigned long computeDeltaTime(unsigned long time_begin) { unsigned long time_current; unsigned long time_delta; time_current = micros(); if (time_current > time_begin) time_delta = time_current - time_begin; else //in case micros has rolled over 2^32, may happen approx. once each hour (3600000000us) time_delta = time_current - (time_begin - (unsigned long )4294967296); return time_delta; } ////////////////////////////////////////// #ifdef TRANSMITOVERWIFI void sendMessage(byte message[]) { //sprintf((char*)message,"Hello ca va la?"); udp.beginPacket(Ip, 10000); udp.write(message, strlen((char*)message)); udp.endPacket(); } #endif ////////////////////////////////////////// int getMessage(byte message[], int maxByte) { int cb = udp.parsePacket(); if (cb == 0) return 0; //no dataavailable, quit if (cb > maxByte) cb = maxByte; //don't overrun the buffer, the remaining part of the message WILL BE LOST!! // We've received a packet, read the data from it udp.read(message, cb); // read the packet into the buffer message[cb] = 0; //add a 0 after the content in the buffer return cb; } ////////////////////////////////////////// #define BUFFER_RX_MAX 50 #define ERROR -1 #define NOTHING 0 #define STARTING 5 #define WAITINGFORCONNECTION 6 #define CONNECTED 7 class Communication { public: int state; //last message received byte message[BUFFER_RX_MAX + 1]; //+1 to add an additional 0 after the received bytes to ensure that the string is correctly finished, even if the sender sent some errors int numeroReseauWifi; int nbRetryConnectWifi; //////////// Communication() { state = STARTING; numeroReseauWifi=0; nbRetryConnectWifi=0; configListeReseauWifi(); } //////////// void loop() { //doc at https://www.arduino.cc/en/Reference/WiFiStatus if (state == STARTING) { //Wifi Configuration Serial.println ( "Wifi Configuration" ); #ifdef TRANSMITOVERWIFI Ip.fromString(listeReseauWifi[numeroReseauWifi].serverIP); #endif //WiFi.begin ( ssid, password ); WiFi.begin ( listeReseauWifi[numeroReseauWifi].ssid, listeReseauWifi[numeroReseauWifi].password ); //stocke l'adresse mac if (MACADDRESS==NULL){ MACADDRESS=strdup(WiFi.macAddress().c_str()); Serial.print ( "MAC address for this board: " ); Serial.println ( MACADDRESS); } // Wait for connection state = WAITINGFORCONNECTION; } else if (state == WAITINGFORCONNECTION) { if ( WiFi.status() != WL_CONNECTED ) { Serial.print ( "WAITINGFORCONNECTION to " ); Serial.print ( numeroReseauWifi); Serial.print ( " "); Serial.println ( listeReseauWifi[numeroReseauWifi].ssid); nbRetryConnectWifi++; //flash bleu pixels.setPixelColor(0, Color(0,0,255)); pixels.show(); delay(100); pixels.setPixelColor(0, Color(0,0,0)); pixels.show(); delay(100); #define MAX_NB_RETRY_CONNECT_WIFI 50 if (nbRetryConnectWifi>MAX_NB_RETRY_CONNECT_WIFI) { nbRetryConnectWifi=0; numeroReseauWifi=(numeroReseauWifi+1)%NbReseauWifi; WiFi.begin ( listeReseauWifi[numeroReseauWifi].ssid, listeReseauWifi[numeroReseauWifi].password ); Ip.fromString(listeReseauWifi[numeroReseauWifi].serverIP); //Serial.print ( "Now trying to connect to " ); //flash rouge pixels.setPixelColor(0, Color(255,0,0)); pixels.show(); delay(100); pixels.setPixelColor(0, Color(0,0,0)); pixels.show(); delay(100); } } else { state = CONNECTED; //flash vert pixels.setPixelColor(0, Color(0,255,0)); pixels.show(); delay(500); pixels.setPixelColor(0, Color(0,0,0)); pixels.show(); delay(500); } } else if (state == CONNECTED) { Serial.println ( "" ); Serial.print ( "Connected to " ); Serial.println (listeReseauWifi[numeroReseauWifi].ssid ); Serial.print ( "Local IP address: " ); Serial.println ( WiFi.localIP() ); Serial.print ( "Server IP address: " ); Serial.println (listeReseauWifi[numeroReseauWifi].serverIP ); Serial.println("Starting UDP socket"); udp.begin(localPort); Serial.print("Local port: "); Serial.println(udp.localPort()); state = NOTHING; } else { if ( WiFi.status() == WL_CONNECTION_LOST) { Serial.print ( "WL_CONNECTION_LOST\n" ); state = STARTING; } else if ( WiFi.status() == WL_DISCONNECTED) { Serial.print ( "WL_DISCONNECTED\n" ); state = STARTING; } else { int n = getMessage(message, BUFFER_RX_MAX); if (n == 0) Debug("."); else { Debug("packet received, length="); char msg[11]; snprintf(msg, 10, "%d", n); Debug(msg); Debug(", content= "); Debug((char*)message); /* if (strcmp((char*)message,"OpenTheDoorCompletelyPlease")==0){ state=OPENTHEDOOR; Debug(" -> Open The Door\n"); } else if (strcmp((char*)message,"CloseTheDoorCompletelyPlease")==0){ state=CLOSETHEDOOR; Debug(" -> Close The Door\n"); } else if (strcmp((char*)message,"StopTheDoor")==0){ state=STOPTHEDOOR; Debug(" -> StopTheDoor\n"); } else if (strcmp((char*)message,"SwitchTheLight")==0){ state=SWITCHTHELIGHT; Debug(" -> SwitchTheLight\n"); } else{ state=ERROR; Debug(" -> Error\n"); }*/ } } } } ////////////////////////// void EmitMessage() { #ifdef TRANSMITOVERWIFI /* static int counter=0; static int b1state=0; static int b2state=0; static int b3state=0; //simulate random presses/releases of buttons if(random(0, 20)==0) b1state=(b1state+1)%2; if(random(0, 15)==0) b2state=(b2state+1)%2; if(random(0, 25)==0) b3state=(b3state+1)%2; */ if (state == NOTHING) { /* counter++; sprintf((char*)message,"compteur= %6d b1:%d b2:%d b3:%d\n",counter,b1state,b2state,b3state); */ /*digitalWrite(D2,LOW); delay(3000); digitalWrite(D2,HIGH); delay(3000); */ //sprintf((char*)message, "%d %d %d\n", Ax - AxZero, Ay - AyZero, Sw); unsigned short int numero_data=0; //identification si le capteur fournit plusieurs messages #ifdef HX711PRESENT static float poidsmax=20000; float poids= scale.get_units(1); // scale.get_units(); // inversion!!!! if (abs(poids)>poidsmax) poidsmax=abs(poids); //Serial.println(poids, 1); unsigned char R=0; unsigned char G=0; unsigned char B=0; if (poids>0) R=poids*255./poidsmax; else if (poids<0) G=-poids*255./poidsmax; //else tout à 0 pixels.setPixelColor(0, Color(R,G,B)); pixels.show(); numero_data=0; //identification si le capteur fournit plusieurs messages //sprintf((char*)message, "%s %d %f %d %d\n",MACADDRESS, numero_data,poids,R,G); sprintf((char*)message, "%s %d %f\n",MACADDRESS, numero_data,poids); sendMessage(message); #endif #ifdef JOYPRESENT //joystick joy.update(); pixels.setPixelColor(0, Color(joy.getX()/ 8, joy.getY() / 8, 0)); //attention Ax,Ay va de 0 à 1024 inclus pixels.setPixelColor(1, Color(0, 0, joy.getB() * 128)); //attention Ax,Ay va de 0 à 1024 inclus pixels.show(); numero_data=1; //identification si le capteur fournit plusieurs messages sprintf((char*)message, "%s %d %d %d %d %d %d %d %d\n", MACADDRESS, numero_data, joy.getX() , joy.getY(),joy.getB(), joy.getdX(),joy.getdY(),joy.getiX(),joy.getiY()); sendMessage(message); #endif /* //compteur numero_data=1; //identification si le capteur fournit plusieurs messages static int cpt=0; cpt++; sprintf((char*)message, "%s %d %d\n", MACADDRESS, numero_data, cpt); sendMessage(message); */ //sprintf((char*)message,"%d\n",analogRead(A0)); } #endif } }; ////////////////////////////////////////// Communication communication; ////////////////////////////////////////// //Be carefull, The Watchdog resets every 4 seconds if the loop function is not finished ////////////////////////////////////////// uint32_t Color(byte r, byte g, byte b) { uint32_t c; c = r; c <<= 8; c |= g; c <<= 8; c |= b; return c; } ////////////////////////////////////////// void setup() { randomSeed(analogRead(0)); //serial communication setup for debugging Serial.begin ( 115200 ); delay(100); Serial.println ( "Serial Configuration Completed" ); Serial.println( "Compiled: " __DATE__ ", " __TIME__ ", " __VERSION__); //GPIOs Configuration Serial.println ( "GPIOs Configuration (some already done through constructors)" ); //Wifi Configuration done in first iterations of communication.loop #ifdef HX711PRESENT // scale.set_scale(250.f); //// this value is obtained by calibrating the scale with known weights scale.tare(10); //tare basée sur moyenne de 10 mesures #endif #ifdef JOYPRESENT joy.init(); joy.setLimits(-32767, 32767, -32767, 32767); joy.setPosCenter(); joy.setFactorOrientation(0.1, 0.1); #endif pixels.begin(); for (byte i = 0; i < PIXELCOUNT; i++) pixels.setPixelColor(i, Color(0, 0, 0)); pixels.show(); }; ////////////////////////////////////////// // the loop function runs over and over again forever void loop() { //Serial.println(micros()); //test_buttons_and_relays(); communication.loop(); communication.EmitMessage(); // if (communication.isSwitchTheLight()) light.commute(); if (communication.state!=CONNECTED) delay(100); //for debuging purposes, it slows the display delay(2); } ////////////////////////////////////////// fichier header à mettre dans le dossier du sketch pour paramétrer les différents hotspot wifi auxquels la carte va essayer de se connecter: //B. Vandeportaele 2019 #define NB_RESEAU_WIFI_MAX 50 //////////////////////////////////////////// typedef struct { const char* ssid; const char* password; const char* serverIP; } reseauWifi; reseauWifi listeReseauWifi[NB_RESEAU_WIFI_MAX]; //variable globale pour gérer la liste de réseau unsigned char NbReseauWifi=0; //////////////////////////////////////////// void ajouteReseauWifi(char * ssid, char * clef, char* serverIP){ if (NbReseauWifi