import serial, time, sys
import serial.tools.list_ports
import time, sys
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.stats import linregress


class arduino():
    def __init__(self,port):
        self.serie = serial.Serial(port,baudrate=115200)
        synchro = ord(self.serie.read())
        while synchro != 0:
            synchro = ord(self.serie.read())

    def sortie_numerique(self,pin,etat):
        self.serie.write(chr(1).encode('latin-1'))
        self.serie.write(chr(pin).encode('latin-1'))
        self.serie.write(chr(etat).encode('latin-1'))

    def entree_numerique(self,pin):
        self.serie.write(chr(2).encode('latin-1'))
        self.serie.write(chr(pin).encode('latin-1'))
        val=ord(self.serie.read())
        return val

    def sortie_analogique(self,pin,val):
        self.serie.write(chr(3).encode('latin-1'))
        self.serie.write(chr(pin).encode('latin-1'))
        self.serie.write(chr(val).encode('latin-1'))

    def entree_analogique(self,pin):
        self.serie.write(chr(4).encode('latin-1'))
        self.serie.write(chr(pin).encode('latin-1'))
        val1=ord(self.serie.read())
        val2=ord(self.serie.read())
        return val1*256 + val2

    def son(self,pin,freq,duree=0):
        self.serie.write(chr(5).encode('latin-1'))
        self.serie.write(chr(pin).encode('latin-1'))
        self.serie.write(chr(freq>>8 & 255).encode('latin-1'))
        self.serie.write(chr(freq & 255).encode('latin-1'))
        self.serie.write(chr(duree>>8 & 255).encode('latin-1'))
        self.serie.write(chr(duree & 255).encode('latin-1'))
        time.sleep(duree/1000)

    def module_us(self,echo,trig):
        self.serie.write(chr(6).encode('latin-1'))
        self.serie.write(chr(echo).encode('latin-1'))
        self.serie.write(chr(trig).encode('latin-1'))
        val1=ord(self.serie.read())
        val2=ord(self.serie.read())
        return val1*256 + val2

    def resistance_pt100(self,cs,di,do,clk):
        self.serie.write(chr(7).encode('latin-1'))
        self.serie.write(chr(cs).encode('latin-1'))
        self.serie.write(chr(di).encode('latin-1'))
        self.serie.write(chr(do).encode('latin-1'))
        self.serie.write(chr(clk).encode('latin-1'))
        val1=ord(self.serie.read())
        val2=ord(self.serie.read())
        return 430*(val1*256 + val2)/32768

    def lecture_Vcc(self):
        self.serie.write(chr(8).encode('latin-1'))
        val1=ord(self.serie.read())
        val2=ord(self.serie.read())
        val=float(val1*256 + val2)
        Vcc=round(1023*1.1/val,3)
        return Vcc

    def entree_analogdec(self,pin):
        self.serie.write(chr(9).encode('latin-1'))
        self.serie.write(chr(pin).encode('latin-1'))
        val1=ord(self.serie.read())
        val2=ord(self.serie.read())
        valRef1=ord(self.serie.read())
        valRef2=ord(self.serie.read())
        valdec= (val1*256 + val2)*1.085/((valRef1*256 + valRef2))
        return round(valdec,3)

    def fermer(self):
        self.serie.close()

def port_Arduino():
    print("\n Recherche d'un port série (USB) pour la connexion avec le microcontroleur Arduino... \n")
    portsUSB = serial.tools.list_ports.comports(include_links=False)
    if (len(portsUSB) != 0):
        if (len(portsUSB) > 1):
            print (str(len(portsUSB)) + " ports USB actifs ont été trouvés:")
        else:
            print ("un port USB actif a été trouvé :")
        ligne = 1
        portArduino=""
        for port in portsUSB :
            print('n° '+str(ligne) + ' : ' + port.device + ' – type constructeur :  '+ str(port.manufacturer))
            if str(port.manufacturer)=="wch.cn" or str(port.manufacturer)=="Arduino (www.arduino.cc)":
                portArduino=port.device
            ligne=ligne+1
        if portArduino =="":
            print("\n Aucun microcontroleur Arduino n'a été détecté sur un port USB")
            print("Veuillez vérifier le branchement USB avec le microcontroleur Arduino")
            sys.exit()
        else :
            return portArduino
    else:
        print("\n Aucun port USB actif n'a été trouvé")
        print("Veuillez vérifier toutes les connexions USB")
        sys.exit()

try:
    carte=arduino(port_Arduino())
except:
    port=input("Erreur de connexion  - sur quel port série USB est branché le microcontrôleur ? ")
    carte=arduino(port)
time.sleep(0.1)

# initialisation
pression=[]                   # liste des pressions
profondeur=[]                 # liste des profondeurs
broche=1                      # broche analogique A1 pour le capteur
time.sleep(1)
print("\n --------- début des mesures --------------\n")
compteur=0
nb_mesure = 5
carte.sortie_numerique(13,1) # allume la led pour le début des mesures

# mesures avec saisie au clavier de la profondeur
while compteur != nb_mesure:
    prof=1e-2*float(input('saisir la profondeur en centimètre ––> '))   # saisie de la profondeur
    profondeur.append(prof)             # enregistrement de la profondeur dans la liste
    mes_num=carte.entree_analogique(broche) # lecture de la valeur numérique (1024 niveaux)
    pression.append(mes_num/1023*5000)  # calcul pression en fonction du modèle du capteur
    compteur += 1

carte.sortie_numerique(13,0) # éteind la led pour la fin des mesures
carte.fermer()                      # fermeture de la communication sur le port

# sauvegarde des données

nomFichier="hydrostatique"
valeurs = {'profondeur (en m)': profondeur,'pression (en V)': pression}
data = pd.DataFrame(valeurs)
print("________________________________")
print("Récapitulatif des données saisies \n")
print(data)
print("________________________________")
print("\n sauvegarde des données dans le fichier %s.csv"%nomFichier)
data.to_csv(nomFichier+'.csv',sep=';',index=False)
##
# exploitation des données et modélisation affine
fig= plt.figure(figsize =(14,10),num="loi de l'hydrostatique")
regression = np.polyfit(profondeur, pression, 1)    # régression linéaire
f_reg=np.poly1d(regression)                         # initialisation de la fonction modèle affine
plt.plot(profondeur,pression,'+',label='mesures')   # tracé des valeurs expérimentales
x=np.linspace(0,1.2*max(profondeur),50)             # création des abcisses pour le tracé du modèle
plt.plot(x,f_reg(x),'-',color='r',label='régression linéaire')      # tracé du modèle
plt.title(r'$\Delta p=f(\Delta z)$')  # titre de la figure
plt.xlim(0, 1.2*max(profondeur))    # paramétrage axe des abscisses entre 0 et 1,2*profondeur max
plt.ylim(0, 1.2*max(pression))      # paramétrage axe des ordonnées entre 0 et 1,2*pression max
plt.xlabel(r'profondeur $\Delta \, z(m)$')        # légendes des axes
plt.ylabel(r'$\Delta p\,(Pa)$')
plt.legend(loc='lower right',fontsize=12) # paramétrages de la légende
# Affichage en consolde des valeurs de la pente et de l'ordonnée à l'origine
pente=round(regression[0],1)
ordonneeOrigine=round(regression[1],1)
print(r"$\Delta p$ = "+str(pente) + r" $\times \Delta z$ + "+ str(ordonneeOrigine))
# sauvegarde des courbes
print("\n________________________________")
print("\n sauvegarde de la courbe dans le fichier %s.png"%nomFichier)
plt.savefig(nomFichier+'.png',dpi=150)
plt.show()                                # tracé de la figure
