Outils pour utilisateurs

Outils du site


infrareseau

Application serveur de données capteurs

multi_server_sensors.py
#!/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

simu_client_srs.py
#!/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

simu_client_srs_continu.py
#!/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

simu_sensor_2_staubli.py
#!/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

srs_animate_thread.py.py
#!/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.

demo_udp_8266_sensor_Bvdp.ino
//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 <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <WiFiUdp.h>
WiFiUDP Client;
 
 
#include <Adafruit_NeoPixel.h>
#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 <Wire.h> 
 
 
 
//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:

listereseauxwifi.h
//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<NB_RESEAU_WIFI_MAX){
listeReseauWifi[NbReseauWifi].ssid=strdup(ssid);
listeReseauWifi[NbReseauWifi].password=strdup(clef);
listeReseauWifi[NbReseauWifi].serverIP=strdup(serverIP);
NbReseauWifi++;
}
}
////////////////////////////////////////////
void configListeReseauWifi(){
//mettre ici des appels tels ajouteReseauWifi("hotspot ssid","clef ","adresse ipv4 du serveur");  
 ajouteReseauWifi("HUAWEI GR5 2017","12345678","192.168.43.14"); //hotspot huawei
 ajouteReseauWifi("78BF39","","192.168.1.49");  //thomson, sans mot de passe, avant c'était 6D842DAE4B
}
////////////////////////////////////////////
 
infrareseau.txt · Dernière modification : 2021/03/19 14:50 de bvandepo