#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Mesure de la direction du vent

# Importation des bibliothèques utilisées par le script
from gpiozero import MCP3008
import time
import math
import os

# Initialise l'intervalle de mesure 300s = 5 * 60s = 5mn
mesure = 300

# Liste pour conserver la direction du vent
liste_angles_5mn = []
# Initialise la direction précédente
direction_precedente = 0.0

# Fonction qui compare la tension lue à la liste de valeurs relevées
# Il est possible de régler la plage de comparaison (entre 0.0 et 0.2 environ)
def compare(valeur, tension_lue):
	# Définit la plage dans laquelle la comparaison est faite
    plage = 0.03
    # Vérifie si la tension lue est dans la plage définie
    if ( (tension_lue > (valeur * (1.0 - plage)))  and (tension_lue < (valeur *(1.0 + plage))) ):
        # Si c'est le cas, renvoyer True = Vrai
        return True
    # Si la tension n'a pas été trouvée il y a une erreur 
    # Renvoyer False = Faux    
    return False

# Convertit la tension lue en angle en utilisant
# la fonction compare() ci-dessus 
def conversion_volt_degres(tension_lue, direction_precedente):
    # Si la comparaison est vraie, retourne la valeur de l'angle (16 possibilités)
    # Les tensions utilisées dans la liste sont celles qui ont été relevées 
    # Lors des tests de la girouette
    if (compare(2.86, tension_lue)):
        return 0.0
        
    if (compare(1.87, tension_lue)):    
        return 22.5
        
    if (compare(2.05, tension_lue)): 
        return 45
        
    if (compare(0.50, tension_lue)):     
        return 67.5
        
    if (compare(0.55, tension_lue)):
        return 90.0

    if (compare(0.40, tension_lue)):
        return 112.5

    if (compare(1.00, tension_lue)):
        return 135.0

    if (compare(0.72, tension_lue)):
        return 157.5

    if (compare(1.44, tension_lue)):    
        return 180

    if (compare(1.27, tension_lue)):
        return 202.5

    if (compare(2.51, tension_lue)):
        return 225

    if (compare(2.43, tension_lue)):
        return 247.5

    if (compare(3.17, tension_lue)):
        return 270.0
	
    if (compare(2.94, tension_lue)):
        return 292.5

    if (compare(3.06, tension_lue)): 
        return 315.0
	
    if (compare(2.68, tension_lue)):
        return 337.5
	
    # Si aucun comparaison n'est vraie, il y a une erreur et
    # la fonction retourne la valeur précédente de la direction du vent 
    # On considère qu'il n'y a pas de gros écart entre 2 valeurs consécutives    
    return direction_precedente  
    
# Fonction qui enregistre la direction du vent dans une liste_angles_5mn
def enregistre_direction(direction):
    global liste_angles_5mn
    liste_angles_5mn.append(direction)
    
# Fonction qui calcule la moyenne des directions en fonction du contenu de la liste_angles_5mn    
def direction_moyenne(angles):
        # d'après http://en.wikipedia.org/wiki/Directional_statistics

        somme_sinus = 0.0
        somme_cosinus = 0.0

        for angle in angles:
            r = math.radians(angle)
            somme_sinus += math.sin(r)
            somme_cosinus += math.cos(r)

        nombre_mesures = float(len(angles))
        s = somme_sinus / nombre_mesures
        c = somme_cosinus / nombre_mesures
        arc = math.degrees(math.atan(s/c))
        moyenne_dir_vent = 0.0
        
        # Gerer la division par zero
        if c == 0 :
            c = 0.00001

        if s > 0 and c > 0:
            moyenne_dir_vent = arc
        elif c < 0:
            moyenne_dir_vent = arc + 180
        elif s < 0 and c > 0:
            moyenne_dir_vent = arc + 360

        return 0.0 if moyenne_dir_vent == 360 else moyenne_dir_vent



# Boucle infinie du programme
while True:
     # Vider la liste des directions du vent
    liste_angles_5mn = []
    
    # Noter l'heure de début de l'intervalle de 5mn
    heure_debut = time.time()
    
    # Début de la temporisation de 5mn
    while time.time() - heure_debut <= mesure:
        # lire l'entrée A0 du MCP3008
        adc = MCP3008(channel=0)
        
        # Les lignes en commentaire impriment les valeurs pour# Aider à la mise au point du script
        #print("Valeur : ", adc.value)
        #print(f'Tension : {adc.value * 3.3:.3f}v ')
        
        # Calcul de la tension lue en multipliant la valeur sur A0 par 3,3
        tension_lue = adc.value * 3.3
    
        # Retrouver la direction du vent en fonction de la tension lue
        direction = conversion_volt_degres(tension_lue, direction_precedente)
        # Enregistrer la direction actuelle
        # Sera utilisée en cas d'erreur dans la conversion tension => angle
        direction_precedente = direction
        # Enregistrer la direction du vent dans la liste
        enregistre_direction(direction)
       
        #print (direction)
        #print(f'Direction : {direction:.2f} degrés')
        #print(liste_angles_5mn)
        
        # Arrêter le script 5 pour éviter la surcharge du CPU
        time.sleep(5)
        # Effacer l'écran (utilse si les print() précedents sont utilisés.
        #os.system("clear")
        
    # Les 5 minutes sont terminées
    
    # Effacer l'écran
    os.system("clear")

    # Calculer et afficher la direction moyenne du vent
    direction = direction_moyenne(liste_angles_5mn)
    # Afficher la direction moyenne du vent pendant les 5 minutes précédentes.
    print (f'Direction moyenne : {direction : .2f} degrés')
    
    time.sleep(1)
    
