def __init__(self, _fen_principale, _fen_creation, *__args):
        """
            Constructeur de la classe

            Récupère les fenetres et branche leurs conecteurs

            :param _fen_principale : Le fenêtre principale FenetrePrincipale
            :param _fen_creation : La fenêtre de paramétrage FenetreCreation
            :param __args : Arguments associés à l'héritage de QFileDialog

        """
        super().__init__(*__args)
        _log.Linfo("Init -- ReseauControleur")

        self.RC_fen_principale = _fen_principale
        self.RC_fen_creation = _fen_creation

        self.RC_barre_progression_creation = None
        self.RC_barre_progression_simulation = None

        self.RC_thread = QtCore.QThread()
        self.RC_worker = None
        self.RC_resultat = None

        self.RC_file_manager = FileManager()
        from Controleur.Statistiques import Statistiques
        self.RC_statistiques = Statistiques()
        self.RC_file_manager.FMchargerStatistiques()

        self.RC_fen_principale.FPobtenirConnecteur().connect(
            self.RCactionSignalFenetrePrincipale)
        self.RC_fen_creation.FCobtenirConnecteur().connect(
            self.RCactionSignalFenetreCreation)

        self.RC_fen_principale.FPafficherReseau()
    def run(self):
        """
            Execute la création du réseau et emet les signaux en conséquent

        """
        _log.Linfo("Début -- ThreadCreation.run")

        _reseau = self.TC_moteur_reseau.GcreerReseau(self.TC_param)

        # Enregistrement du réseau obtenu
        _file_manager = FileManager()
        _file_manager.FMviderEtats(_garder_etat_initial=False)
        _file_manager.FMenregistrerEtat(_reseau=_reseau, _show_html=True)

        # Ajout des statistiques relevant de cet état initial
        from Controleur.Statistiques import Statistiques
        _statistiques = Statistiques()
        _statistiques.SajouterDonnees(_reseau, 0)
        _file_manager.FMsauvegarderStatistiques()

        # Envoie des signaux
        self.TC_resultat.emit(_reseau)
        self.TC_finished.emit()

        _log.Linfo("Fin -- ThreadCreation.run")
Example #3
0
    def FMviderEtats(self, _garder_etat_initial):
        """
            Permet de supprimer l'ensemble des fichiers sauvegardés en local

        :param _garder_etat_initial: boolean, si vrai ne supprime pas les données relatives au premier etat
        """
        _log.Linfo("Début ## FileManager.FMviderEtats")

        _chemin = self.FM_chemin_local + "\\resultats simulation"

        if os.path.exists(_chemin):
            from Controleur.Statistiques import Statistiques
            _statistiques = Statistiques()
            _statistiques.SviderEtats(_garder_etat_initial)
            if _garder_etat_initial:
                for _fichier in os.listdir(_chemin):
                    _acces = os.path.join(_chemin, _fichier)
                    try:
                        if os.path.isfile(_acces) and "etat0" not in _fichier:
                            os.unlink(_acces)
                    except Exception as e:
                        print(e)

            else:
                shutil.rmtree(_chemin)
    def FPafficherReseau(self):
        """
            Affiche dans la section didiée de la fenêtre, le reseau enregistré en local sous forme d'une page html

        """
        _log.Linfo("Début ## FenetrePrincipale.FPafficherReseau")

        _statistiques = Statistiques()
        self.FPD_aire_informations.setText(
            _statistiques.SgenererTexte(self.FP_selection))

        _fileManager = FileManager()
        _chemin = _fileManager.FMchargerHTMLEtat(self.FP_selection)

        _qurl = QUrl()
        _local_url = _qurl.fromLocalFile(_chemin)

        self.FP_view.load(_local_url)

        self.FPafficherGraphiques()
    def FPafficherGraphiques(self):
        """
        Affiche dans la section didiée de la fenêtre les deux graphiques
        Premier graphique (en haut) : La durée de vie du réseau en fonction de l'intervalle de changement de
        rôle utilisé
        Second graphique : Le nombre de capteurs connectés à la passerelle en fonction du temps

        Les données sont affichées sous forme de points, les valeurs s'affichent au passage de la souris
        """
        _log.Linfo("Début ## FenetrePrincipale.FPafficherGraphiques")

        _statistiques = Statistiques()
        _donnees_graphique1, _donnees_graphique2 = _statistiques.SgenererDonneesGraphiques(
        )
        # Graphique 1
        _ax = self.FP_figure_graphique1.add_subplot(111)
        _ax.clear()
        _lignes = _ax.plot(_donnees_graphique1["y"], _donnees_graphique1["x"],
                           'o')
        _ax.set_xlabel("Intervalle de temps entre les changements de rôle")
        _ax.set_ylabel("Durée de vie du réseau")
        _ax.set_title("Résultats durée de vie du réseau")
        mplcursors.cursor(_lignes, hover=True)
        self.FP_figure_graphique1.tight_layout()
        self.FP_canvas_graphique1.draw()

        # Graphique 2
        _ax = self.FP_figure_graphique2.add_subplot(111)
        _ax.clear()
        _lignes = _ax.plot(_donnees_graphique2["y"], _donnees_graphique2["x"],
                           'o')
        _ax.set_xlabel("Durée de la simulation en unité de temps")
        _ax.set_ylabel("Nombre de capteurs connectés")
        _ax.set_title("Capteurs connectés à la passerelle")
        mplcursors.cursor(_lignes, hover=True)
        self.FP_figure_graphique2.tight_layout()
        self.FP_canvas_graphique2.draw()
Example #6
0
    def SlancerSimulation(self, _reseau, _show_html):
        """
            Permet de lancer le processus de simulation de la vie du réseau. Cf diagramme d'activité pour connaitre son
            fonctionnement algorithmique.

            :param _reseau: Reseau, le réseau à traiter
            :param _show_html: bool, Permet de définir si l'état du réseau doit être affiché pendant la simulation

            :return: Reseau, le réseau une fois traité
        """

        _log.Linfo("Début ## Simulateur.SlancerSimulation")

        from Modele.Reseau import Reseau
        if type(_reseau) is not Reseau:
            _log.Lerror("Valeur Argument errone _reseau")
            raise Exception("Valeur Argument errone _reseau")
        if type(_show_html) is not bool:
            _log.Lerror("Valeur Argument errone _show_html")
            raise Exception("Valeur Argument errone _show_html")

        from Controleur.Statistiques import Statistiques
        _statistiques = Statistiques()
        _file_manager = FileManager()

        # Chrono pour savoir combien de temps la simulation a durée
        _start = time.time()

        _dernier_roulement = 0
        _reseau_simulation = _reseau
        self.S_duree_simulation = 0
        self.S_duree_de_vie = 0
        self.S_intervalle_roulement = 0
        # Initialisation des compteurs
        _etat = 0
        _total = 1
        _cycle = 0

        while not self.__SmaximumAtteint():

            _log.Linfo("Info ## Cycle " + str(_cycle))

            self.S_connecteur.emit(Signaux.INITIALISATION_SIMULATION, dict())

            _reseau_simulation = copy.deepcopy(_reseau)

            # Détermination de l'intervalle de temps
            self.__SdeterminationIntervalleTemps()

            _text_progression = "Simulation en cours.. " \
                                "\nCycle " + str(_cycle) + \
                                "\nintervalle utilisé : " + str(self.S_intervalle_roulement) + " unité(s) de temps"
            self.S_connecteur.emit(
                Signaux.PROGRESSION_SIMULATION,
                dict({
                    "avancee": 0,
                    "text": _text_progression
                }))

            # Configuration topologique du réseau (routage et ensemble dominant)
            _reseau_simulation = self.SconfigurationTopologique(
                _reseau_simulation)

            _fin_de_vie_atteinte, _capteurs_deconnectes = self.SfinDeVieAtteinte(
                _reseau_simulation, self.S_intervalle_roulement)
            self.S_duree_de_vie = 0

            # Tant que la fin de vie du réseau n'a pas été atteinte, on simule la consommation énergétique en
            # enregistrant les étapes intermédiaires
            while not _fin_de_vie_atteinte:
                _log.Linfo("Info ## état " + str(_etat))

                # Cas où le temps écoulé correspond à l'intervalle de temps de changement de rôles des capteurs :
                # le rôle des capteurs est modifié et l'état est enregistré
                if self.S_intervalle_roulement != 0:
                    if self.S_duree_de_vie == 0 \
                            or self.S_duree_de_vie - _dernier_roulement >= self.S_intervalle_roulement:
                        _dernier_roulement = self.S_duree_de_vie
                        _reseau_simulation = self.SconfigurationTopologique(
                            _reseau_simulation)
                        _etat += 1
                        _total += 1
                        _file_manager.FMenregistrerEtat(
                            _reseau_simulation, _show_html)
                        _statistiques.SajouterDonnees(_reseau_simulation,
                                                      _cycle,
                                                      self.S_duree_simulation)
                        self.S_connecteur.emit(
                            Signaux.NOUVEL_ETAT,
                            dict({
                                "etat": _etat,
                                "total": _total
                            }))

                # On simule la consommation énergétique des capteurs puis on regarde si la fin de vie a été atteinte
                _reseau_simulation = self.__SsimulationSurUnRoulement(
                    _reseau_simulation, _capteurs_deconnectes)

                _fin_de_vie_atteinte, _capteurs_deconnectes = self.SfinDeVieAtteinte(
                    _reseau_simulation, self.S_intervalle_roulement)
                _ratio = len(_capteurs_deconnectes) / _reseau.R_nbr_noeuds - (
                    1 - self.S_fin_de_vie)
                self.S_connecteur.emit(
                    Signaux.PROGRESSION_SIMULATION,
                    dict({
                        "avancee": int(_ratio * 100),
                        "text": _text_progression
                    }))

            # Fin premier While : la fin de vie du réseau a été atteinte, on sauvegarde les états et on recommence avec
            # un nouvel intervalle

            # Ajout de l'état de la fin de vie du réseau
            _etat += 1
            _total += 1
            _file_manager.FMenregistrerEtat(_reseau_simulation, _show_html)
            _statistiques.SajouterDonnees(_reseau_simulation, _cycle,
                                          self.S_duree_simulation)

            self.S_resultats.append(
                dict({
                    "intervalle": self.S_intervalle_roulement,
                    "resultat": self.S_duree_de_vie
                }))
            _statistiques.SajouterResultat(self.S_intervalle_roulement,
                                           self.S_duree_de_vie)

            self.S_connecteur.emit(Signaux.NOUVEL_ETAT,
                                   dict({
                                       "etat": _etat,
                                       "total": _total
                                   }))
            # On met la barre de progression à 100%
            self.S_connecteur.emit(
                Signaux.PROGRESSION_SIMULATION,
                dict({
                    "avancee": 100,
                    "text": _text_progression
                }))

            self.S_duree_simulation += self.S_intervalle_recolte * 100  # Pour séparer les résultats d'un cycle à lautre
            _cycle += 1

        # Fin while, cad fin de la simulation, le maximum a été trouvé

        # Si les étapes intermédiaires n'ont pas été enregistrées sous format html, en enregistre quand même le dernier
        # état afin d'avoir le premier et le dernier état d'affiché
        if not _show_html:
            _etat += 1
            _total += 1
            _file_manager.FMenregistrerEtat(_reseau_simulation, True)
            self.S_connecteur.emit(Signaux.NOUVEL_ETAT,
                                   dict({
                                       "etat": _etat,
                                       "total": _total
                                   }))

        FileManager.FMsauvegarderStatistiques()

        # Informations sur la durée de la simulation
        _end = time.time()
        _temps = (_end - _start) // 1
        self.S_connecteur.emit(Signaux.FIN_SIMULATION,
                               dict({"duree": abs(_temps)}))

        _log.Linfo("Info ## Fin simulation")

        return _reseau_simulation
class ReseauControleur(QFileDialog):
    """
        class Simulateur

        Controleur qui fait le lien entre le modèle et la vue. Il gère toutes les intéractons avec les fenêtres et les
        moteurset. Permet de lancer la génération d'un réseau ainsi que la simulation de sa vie

        :var self.RC_fen_principale, FenetrePrincipale
        :var self.RC_fen_creation, FenetreCreation

        :var self.RC_barre_progression_creation, BarreProgression : La barre de progression associée à l'avancement de
        la création du réseau
        :var self.RC_barre_progression_simulation, BarreProgression : La barre de progression associée à l'avancement
        de la simulation

        :var self.RC_thread, QtCore.QThread : Le thread receptacle qui recevra un objet ThreadSimulation ou
        ThreadCreation pour le lancer
        :var self.RC_worker, ThreadSimulation ou ThreadCreation : Instancie un objet qui sera transformé en QThread

        :var self.RC_resultat, Reseau : L'objet dans lequel sera stocké le résultat de la génération

    """
    def __init__(self, _fen_principale, _fen_creation, *__args):
        """
            Constructeur de la classe

            Récupère les fenetres et branche leurs conecteurs

            :param _fen_principale : Le fenêtre principale FenetrePrincipale
            :param _fen_creation : La fenêtre de paramétrage FenetreCreation
            :param __args : Arguments associés à l'héritage de QFileDialog

        """
        super().__init__(*__args)
        _log.Linfo("Init -- ReseauControleur")

        self.RC_fen_principale = _fen_principale
        self.RC_fen_creation = _fen_creation

        self.RC_barre_progression_creation = None
        self.RC_barre_progression_simulation = None

        self.RC_thread = QtCore.QThread()
        self.RC_worker = None
        self.RC_resultat = None

        self.RC_file_manager = FileManager()
        from Controleur.Statistiques import Statistiques
        self.RC_statistiques = Statistiques()
        self.RC_file_manager.FMchargerStatistiques()

        self.RC_fen_principale.FPobtenirConnecteur().connect(
            self.RCactionSignalFenetrePrincipale)
        self.RC_fen_creation.FCobtenirConnecteur().connect(
            self.RCactionSignalFenetreCreation)

        self.RC_fen_principale.FPafficherReseau()

    def RCactionSignalFenetrePrincipale(self, _signal, _data=0):
        """
            Analyse le signal émit par la fenêtre principale et agit en conséquent. Un signal est émit par la fenêtre
            principale lorsque l'utilisateur intéragit avec un boutton

            :param _signal : Enum Signaux, Le signal de type Signals à analyser. Liste des signaux concernés :
                - GENERER_RESEAU : Cas de demande de génération d'un réseau : la fenêtre de création est ouverte
                - EXPORTER_XML : Cas de demande d'exportation d'un état du réseau au format XML
                - CHARGER_XML : Cas de demande d'importation d'un état d'un réseau depuis un fichier XML
                - EXPORTER_RESULTAT : Cas de demande d'exportation du résultat de la simulation, cad l'ensemble des
                    états dans lequel est passé le réseau
                - IMPORTER_RESULTAT : Cas de demande d'importation d'un résultat d'une simulation
                - LANCER_SIMULATION : Cas de demande de lancement de la simulation
                - ARRIERE : Cas de la demande d'affichage de l'état précédent
                - AVANT : Cas de la demande d'affichage de l'état suivant
                - SAUT_ARRIERE : Cas de la demande d'affichage du cycle précédent
                - SAUT_AVANT : Cas de la demande d'affichage du cycle suivant
                - SAUT_TEMPOREL : Cas doù l'utilisateur utilise la barre glissante pour choisir un état précis
            :param _data : est utilisé pour transmettre des données supplémentaires dans le signal. Cas d'utilisations :
                - _LANCER_SIMULATION : permet de transmettre la volonté de l'utilisateur à vouloir afficher les états
                    dans lesquels passe le réseau lors de la simulation. Deux états : 0 = False, R\\{0] = True
                - _SAUT_TEMPOREL : permet de transmettre la position du curseur de la barre défillante. Entier

        """
        _log.Linfo("Début ## ReseauControleur.RCactionSignalFenetrePrincipale")
        _log.Linfo("Info ## Signal = " + str(_signal))

        # =============================================================================
        # Cas de demande de génération d'un réseau : la fenêtre de création est ouverte
        # Signal GENERER_RESEAU
        # =============================================================================
        if _signal == Signaux.GENERER_RESEAU:
            self.RC_fen_creation.show()

        # ==============================================================
        # Cas de demande d'exportation d'un état du réseau au format XML
        # Signal : EXPORTER_XML
        # ==============================================================
        elif _signal == Signaux.EXPORTER_XML:

            # Récupère les données XML du réseau affiché
            _reseau = self.RC_file_manager.FMchargerEtat(
                self.RC_fen_principale.FP_selection)

            if _reseau is None:
                ReseauControleur.RCmessageErreur("Aucun réseau à exploiter")

            else:
                # Ouvre une boite de dialogue qui demande à l'utilisateur l'endroit où exporter le fichier
                _options = QFileDialog.Options()
                _options |= QFileDialog.DontUseNativeDialog
                _filename, _ = QFileDialog.getSaveFileName(
                    self,
                    "Spécifier l'endroit où exporter le fichier",
                    "",
                    "Fichier XML (*.xml)",
                    options=_options)

                # Enregistre le réseau dans un nouveau fichier XML
                if _filename:
                    self.RC_file_manager.FMsauvegarderReseauVersXML(
                        _reseau, _filename)
                    ReseauControleur.RCmessageInformation(
                        "Le réseau a été exporté avec succès !")

        # ========================================================================
        # Cas de demande d'importation d'un état d'un réseau depuis un fichier XML
        # Signal : CHARGER_XML
        # ========================================================================
        elif _signal == Signaux.CHARGER_XML:
            try:
                # Ouvre une boite de dialogue qui demande à l'utilisateur le fichier XML contenant le réseau
                _options = QFileDialog.Options()
                _options |= QFileDialog.DontUseNativeDialog
                _filename, _ = QFileDialog.getOpenFileName(
                    self,
                    "Spécifier le fichier à importer",
                    "",
                    "Fichier XML (*.xml)",
                    options=_options)

                # Si le fichier existe
                if _filename:
                    # Charge le réseau
                    _reseau = self.RC_file_manager.FMchargerReseauDepuisXML(
                        _filename)
                    if _reseau is not None:
                        # Puis l'enregistre en local pour le manipuler. Supprime les états déjà présents
                        self.RC_file_manager.FMviderEtats(
                            _garder_etat_initial=False)
                        self.RC_file_manager.FMenregistrerEtat(_reseau,
                                                               _show_html=True)

                        _log.Linfo("Info ## Réseau importé")
                        ReseauControleur.RCmessageInformation(
                            "Le réseau a été importé avec succès !")
                        self.RC_fen_principale.FPuptdateLabelSelection(0, 1)
                        self.RC_fen_principale.FPafficherReseau()
            except Exception as _e:
                _log.Lerror("Erreur lors du chargement du fichier : " +
                            str(_e))
                ReseauControleur.RCmessageErreur(
                    "Erreur lors du chargement du fichier : " + str(_e))

        # ============================================================================================================
        # Cas de demande d'exportation du résultat de la simulation, cad l'ensemble des états dans lequel est passé le
        # réseau
        # Signal : EXPORTER_RESULTAT
        # ============================================================================================================
        elif _signal == Signaux.EXPORTER_RESULTAT:
            if len(self.RC_file_manager.FMlisterEtats()) == 0:
                _log.Linfo("WARNING ## Aucune données à exporter")
                ReseauControleur.RCmessageErreur("Aucune données à exporter")

            else:
                # Ouvre une boite de dialogue qui demande à l'utilisateur l'endroit où exporter le dossier
                _options = QFileDialog.Options()
                _options |= QFileDialog.DontUseNativeDialog
                _options |= QFileDialog.ShowDirsOnly
                _filename = QFileDialog.getExistingDirectory(
                    self, "Spécifier l'endroit où exporter l'ensemble des "
                    "données",
                    "",
                    options=_options)

                _done, _message = self.RC_file_manager.FMexporterResultat(
                    _filename)

                if not _done:
                    _log.Lerror("Erreur lors de l'exportation : \n" + _message)
                    ReseauControleur.RCmessageErreur(
                        "Erreur lors de l'exportation : \n" + _message)
                else:
                    _log.Linfo(
                        "L'ensemble des fichiers a été exporté avec succès !")
                    ReseauControleur.RCmessageInformation(
                        "L'ensemble des fichiers a été exporté avec succès !")

        # ===========================================================
        # Cas de demande d'importation d'un résultat d'une simulation
        # Signal : IMPORTER_RESULTAT
        # ===========================================================
        elif _signal == Signaux.IMPORTER_RESULTAT:
            # Ouvre une boite de dialogue qui demande à l'utilisateur l'endroit où se situe le dossier à importer
            _options = QFileDialog.Options()
            _options |= QFileDialog.DontUseNativeDialog
            _options |= QFileDialog.ShowDirsOnly
            _filename = QFileDialog.getExistingDirectory(
                self,
                "Sélectionner le dossier à importer",
                "",
                options=_options)
            _nbr_imported, _message = self.RC_file_manager.FMimporterResultat(
                _filename)

            if _nbr_imported == 0:
                _log.Lerror("Erreur lors de l'exportation : \n" + _message)
                ReseauControleur.RCmessageErreur(
                    "Erreur lors de l'importation : \n" + _message)
            else:
                _log.Linfo(
                    "L'ensemble des fichiers a été importé avec succès !")
                ReseauControleur.RCmessageInformation(
                    "L'ensemble des fichiers a été importé avec succès !")
                self.RC_fen_principale.FPuptdateLabelSelection(
                    0, _nbr_imported)
                self.RC_fen_principale.FPafficherReseau()

        # ============================================
        # Cas de demande de lancement de la simulation
        # Signal : LANCER_SIMULATION
        # ============================================
        elif _signal == Signaux.LANCER_SIMULATION:
            # TODO : Version sup., ajouter une fenêtre de paramétrage qui demande les paramètre cf Simulateur
            # _data contient l'information si l'utilisateur veut générer l'html de chaque état pendant la simulation
            _show = True
            if _data == 0:
                _show = False

            _log.Linfo(
                "INFO ## Lancement de la simulation, Generation html : " +
                str(_show))
            self.RClancerSimulation(_show_html=_show)

        # =================================================
        # Cas de la demande d'affichage de l'état précédent
        # Signal : ARRIERE
        # =================================================
        elif _signal == Signaux.ARRIERE:
            # Seulement si on est pas déjà au premier état
            if self.RC_fen_principale.FP_selection > 0:
                _log.Linfo("INFO ## Récupération de l'état précédent")
                self.RC_fen_principale.FPuptdateLabelSelection(
                    self.RC_fen_principale.FP_selection - 1,
                    self.RC_fen_principale.FP_total)
                self.RC_fen_principale.FPafficherReseau()

        # ===============================================
        # Cas de la demande d'affichage de l'état suivant
        # Signal : AVANT
        # ===============================================
        elif _signal == Signaux.AVANT:
            if self.RC_fen_principale.FP_selection < self.RC_fen_principale.FP_total - 1:
                _log.Linfo("INFO ## Récupération de l'état suivant")
                self.RC_fen_principale.FPuptdateLabelSelection(
                    self.RC_fen_principale.FP_selection + 1,
                    self.RC_fen_principale.FP_total)
                self.RC_fen_principale.FPafficherReseau()

        # ================================================
        # Cas de la demande d'affichage du cycle précédent
        # Signal : SAUT_ARRIERE
        # ================================================
        if _signal == Signaux.SAUT_ARRIERE:
            _log.Linfo(
                "INFO ## Récupération du premier état du cycle précédent")
            _etat = self.RC_statistiques.S_etatCyclePrecedent(
                self.RC_fen_principale.FP_selection)

            if _etat != self.RC_fen_principale.FP_selection:
                self.RC_fen_principale.FPuptdateLabelSelection(
                    _etat, self.RC_fen_principale.FP_total)
                self.RC_fen_principale.FPafficherReseau()

        # ==============================================
        # Cas de la demande d'affichage du cycle suivant
        # Signal : SAUT_AVANT
        # ==============================================
        if _signal == Signaux.SAUT_AVANT:
            _log.Linfo("INFO ## Récupération du premier état du cycle suivant")
            _etat = self.RC_statistiques.S_etatCycleSuivant(
                self.RC_fen_principale.FP_selection)

            if _etat != self.RC_fen_principale.FP_selection:
                self.RC_fen_principale.FPuptdateLabelSelection(
                    _etat, self.RC_fen_principale.FP_total)
                self.RC_fen_principale.FPafficherReseau()

        # ============================================================================
        # Cas doù l'utilisateur utilise la barre glissante pour choisir un état précis
        # Signal : SAUT_TEMPOREL
        # ============================================================================
        if _signal == Signaux.SAUT_TEMPOREL:
            _log.Linfo("INFO ## Changement à l'état " + str(_data))
            self.RC_fen_principale.FPuptdateLabelSelection(
                _data, self.RC_fen_principale.FP_total)
            self.RC_fen_principale.FPafficherReseau()

    def RClancerSimulation(self, _show_html):
        """
            Démarre, dans un thread, la simulation sur le réseau affiché et connecte ses signaux

            :param _show_html : Booléen, Permet de définir si l'état du réseau doit être affiché pendant la simulation
        """
        _log.Linfo("Début ## ReseauControleur.RClancerSimulation")

        self.RC_file_manager.FMviderEtats(_garder_etat_initial=True)

        _reseau = self.RC_file_manager.FMchargerEtat(0)

        if _reseau is None:
            _log.Linfo("WARNING ## Aucun réseau à exploiter")
            ReseauControleur.RCmessageErreur("Aucun réseau à exploiter")
        else:
            # Création d'abord d'un objet ThreadSimulation et mutation en Thread pour pouvoir manipuler ses connecteurs
            self.RC_worker = ThreadSimulation(_reseau, _show_html=_show_html)
            self.RC_worker.moveToThread(self.RC_thread)

            # Connection des signaux
            self.RC_thread.started.connect(self.RC_worker.run)
            self.RC_thread.finished.connect(
                self.RC_fen_principale.FPafficherReseau)
            self.RC_worker.TS_finished.connect(self.RC_thread.quit)
            self.RC_worker.TS_connecteur.connect(self.RCactionSignalSimulateur)

            self.RC_thread.start()

    def RCactionSignalSimulateur(self, _signal, _datas):
        """
            Reçoit et analyse les signaux émis par le simulateur
            Principalement utilisé pour instancier et faire progresser une barre de progression

            :param _signal : Enum Signaux, Le signal de type Signals à analyser. Liste des signaux concernés :
                - NOUVEL_ETAT : Cas où un nouvel état a été enregistré et est à afficher (typiquement à la fin de la
                    simulation et à chaque changement de rôle des capteurs)
                - INITIALISATION_SIMULATION : Au début de la simulation, création de la barre de progression
                - PROGRESSION_SIMULATION : Pour modifier les valeurs de la barre de progression
                - FIN_SIMULATION : Ferme la barre de progression et notifie l'utilisateur

            :param _datas : Dict(String : Objet) Les données envoyé lors de l'émission du signal
                Associations :
                Signaux.NOUVEL_ETAT => etat (int) le numéro du nouvel état ; total (int) le nombre d'états
                Signaux.INITIALISATION_SIMULATION => Aucun
                Signaux.PROGRESSION_SIMULATION => avancee (int) la position de 0 à 100 où placer la barre de
                    progression ; text (String) le texte à afficher au dessus de la barre de progression
                Signaux.FIN_SIMULATION => duree (float) le temps qu'a duré la simulation

        """
        _log.Linfo("Début ## ReseauControleur.RCactionSignalSimulateur")

        # ===========================================================================================================
        # Cas où un nouvel état a été enregistré et est à afficher (typiquement à la fin de la simulation et à chaque
        # changement de rôle des capteurs)
        # Signal : NOUVEL_ETAT
        # ===========================================================================================================
        if _signal == Signaux.NOUVEL_ETAT:
            _log.Linfo("Info ## Nouvel état signalé")
            self.RC_fen_principale.FPuptdateLabelSelection(
                _datas["etat"], _datas["total"])
            self.RC_fen_principale.FPafficherReseau()

        # ==============================================================
        # Au début de la simulation, création de la barre de progression
        # Signal : INITIALISATION_SIMULATION
        # ==============================================================
        elif _signal == Signaux.INITIALISATION_SIMULATION:
            _log.Linfo("Info ## Initialisation de la simulation signalée")
            self.RC_barre_progression_simulation = BarreProgression()

        # ====================================================
        # Pour modifier les valeurs de la barre de progression
        # Signal : PROGRESSION_SIMULATION
        # ====================================================
        elif _signal == Signaux.PROGRESSION_SIMULATION:
            _log.Linfo("Info ## Progression de la simulation signalée")
            self.RC_barre_progression_simulation.BPchangementValeur(
                _datas["avancee"])
            self.RC_barre_progression_simulation.BPchangementLabel(
                _datas["text"])

        # ======================================================
        # Ferme la barre de progression et notifie l'utilisateur
        # Signal : FIN_SIMULATION
        # ======================================================
        elif _signal == Signaux.FIN_SIMULATION:
            _log.Linfo(
                "Info ## Fin de la simulation de la simulation signalée")
            if self.RC_barre_progression_simulation is not None:
                # on met à 100% et on ferme la fenêtre
                self.RC_barre_progression_simulation.BPfin()
            self.RCmessageInformation(
                "Simulation terminée, temps d'exécution : " +
                str(_datas["duree"]) + " secondes")

    def RCactionSignalFenetreCreation(self, _signal, _params=None):
        """
            Reçoit et analyse les signaux émis par la fenêtre de création de réseau

            :param _signal : Enum Signaux, Le signal de type Signals à analyser. Liste des signaux concernés :
                - ANNULER_PARAMETRES : L'utilisateur annule la création du réseau
                - VALIDER_PARAMETRES : L'utilisateur demande la création du réseau
            :param _params: ParametresCreation, l'objet contenant les paramètres saisis par l'utilisateur dans la fenêtre de
                création

        """
        _log.Linfo("Début ## ReseauControleur.RCactionSignalFenetreCreation")

        # ==========================================
        # L'utilisateur annule la création du réseau
        # Signal : ANNULER_PARAMETRES
        # ==========================================
        if _signal == Signaux.ANNULER_PARAMETRES:
            _log.Linfo("Info ## Annulation de la création du réseau")
            self.RC_fen_creation.close()

        # ==========================================
        # L'utilisateur demande la création du réseau
        # Signal : VALIDER_PARAMETRES
        # ==========================================
        elif _signal == Signaux.VALIDER_PARAMETRES and _params is not None:
            _log.Linfo("Info ## Validation de la création du réseau")
            self.RC_fen_creation.close()
            self.RCcreerReseau(_params)

    def RCcreerReseau(self, _param):
        """
            Démarre, dans un thread, la génération d'un réseau

            :param _param : ParametresCreation, Les paramètres reçus pour la création du réseau

        """
        _log.Linfo("Début ## ReseauControleur.RCcreerReseau")

        if self.RCcontroleParametres(_param):
            # Création d'abord d'un objet ThreadCreation et mutation en Thread pour pouvoir manipuler ses connecteurs
            self.RC_worker = ThreadCreation(_param)
            self.RC_worker.moveToThread(self.RC_thread)
            self.RC_worker.TC_finished.connect(self.RC_thread.quit)

            self.RC_thread.started.connect(self.RC_worker.run)
            self.RC_thread.finished.connect(
                self.RC_fen_principale.FPafficherReseau)

            self.RC_worker.TC_connecteur.connect(self.RCactionSignalGenerateur)
            self.RC_worker.TC_resultat.connect(
                self.RCactionSignalGenerateurEmissionResultat)

            self.RC_thread.start()

    def RCactionSignalGenerateur(self, _signal, _valeur, _texte, _temps=-1):
        """
            Analyse le signal émit par la création du réseau (Objet Generateur)
            Principalement utilisé pour instancier et faire progresser une barre de progression

            :param _signal : Enum Signaux, Le signal de type Signals à analyser. Liste des signaux concernés :
                - INITIALISATION_CREATION_GRAPHE : Au début de la génération, création de la barre de progression
                - INFORMATION_CREATION_GRAPHE : Informations à placer dans le log, relatives à l'avancement
                - AVANCEE_CREATION_GRAPHE : Pour modifier les valeurs de la barre de progression
                - FIN_CREATION_GRAPHE : Ferme la barre de progression et notifie l'utilisateur
            :param _valeur: int, L'avancement de la création
            :param _texte: String, L'information à afficher
            :param _temps: float, Le temps restant estimé (en secondes)

        """
        _log.Linfo("Début ## ReseauControleur.RCactionSignalGenerateur")

        # ==============================================================
        # Au début de la génération, création de la barre de progression
        # Signal : INITIALISATION_CREATION_GRAPHE
        # ==============================================================
        if _signal == Signaux.INITIALISATION_CREATION_GRAPHE:
            _log.Linfo("Info ## Initialisation de la génération signalée")
            self.RC_barre_progression_creation = BarreProgression()

        # ===========================================================
        # Informations à placer dans le log, relatives à l'avancement
        # Signal : INFORMATION_CREATION_GRAPHE
        # ===========================================================
        elif _signal == Signaux.INFORMATION_CREATION_GRAPHE:
            _log.Linfo("Info ## " + _texte)

        # ====================================================
        # Pour modifier les valeurs de la barre de progression
        # Signal : AVANCEE_CREATION_GRAPHE
        # ====================================================
        elif _signal == Signaux.AVANCEE_CREATION_GRAPHE and self.RC_barre_progression_creation is not None:
            _log.Linfo("Info ## Progresion de la génération signalée")
            # on modifie l'avancée et on ajoute le texte
            self.RC_barre_progression_creation.BPchangementValeur(_valeur)
            if _temps == -1:
                self.RC_barre_progression_creation.BPchangementLabel(
                    "Création du réseau en cours..")
            else:
                self.RC_barre_progression_creation.BPchangementLabel(
                    "Création du réseau en cours..", _temps)
            _log.Linfo(_texte)

        # ======================================================
        # Ferme la barre de progression et notifie l'utilisateur
        # Signal : FIN_CREATION_GRAPHE
        # ======================================================
        elif _signal == Signaux.FIN_CREATION_GRAPHE and self.RC_barre_progression_creation is not None:
            _log.Linfo("Info ## Réseau créé avec succès")
            self.RCmessageInformation("Réseau créé avec succès")
            self.RC_barre_progression_creation.BPfin()

    def RCactionSignalGenerateurEmissionResultat(self, _reseau):
        """
            Réceptionne le réseau créé par le générateur

            :param _reseau : Reseau, Le résulat émit

        """
        _log.Linfo(
            "Début ## ReseauControleur.RCactionSignalGenerateurEmissionResultat"
        )

        self.RC_resultat = _reseau

        self.RC_fen_principale.FPuptdateLabelSelection(_selection=0, _total=1)

    def RCcontroleParametres(self, _param):
        """
            Permet de controler les paramètres saisis par l'utilisateur.

            :param _param : ParametresCreation, Les paramètres à contrôler.

            :return booléen, faux si les paramètres ne conviennent pas, vrai sinon

        """
        _log.Linfo("Début ## ReseauControleur.RCcontroleParametres")

        _text_erreur = ""

        if _param.PC_min_distance > _param.PC_max_distance:
            _text_erreur += "La distance minimum doit être inférieure ou égale à la distance maximale\n"
        if _param.PC_max_size < 10:
            _text_erreur += "La taille maximale doit être supérieur à 10\n"
        if _param.PC_marge > _param.PC_max_size / 2:
            _text_erreur += "La marge doit être inférieure à la moitiée de la taille maximale\n"
        if _param.PC_nbr_capteurs < 2:
            _text_erreur += "Le nombre de capteurs doit être supérieur à 1\n"

        if _text_erreur != "":
            _log.Linfo("Warning ## " + _text_erreur)
            ReseauControleur.RCmessageErreur(_text_erreur)
            return False
        return True

    @staticmethod
    def RCmessageErreur(_message_erreur):
        """
            Permet d'afficher un message d'erreur dans une boite de dialogue type erreur

            :param _message_erreur : Le message à afficher

        """

        _boite = QMessageBox()
        _boite.setIcon(QMessageBox.Critical)
        _boite.setText("Erreur(s)")
        _boite.setWindowTitle("Erreur(s)")
        _boite.setDetailedText(
            "Le(s) erreur(s) suivante(s) ont été détectée(s) : \n" +
            _message_erreur)
        _boite.setStandardButtons(QMessageBox.Ok)

        _boite.exec_()

    @staticmethod
    def RCmessageInformation(_message_info):
        """
            Permet d'afficher un message d'information dans une boite de dialogue type information

            :param _message_info : Le message à afficher

        """

        _boite = QMessageBox()
        _boite.setIcon(QMessageBox.Information)
        _boite.setText(_message_info)
        _boite.setWindowTitle("Information(s))")
        _boite.setStandardButtons(QMessageBox.Ok)

        _boite.exec_()
Example #8
0
    def FMchargerStatistiques(self):
        """
            Permet de charger en local depuis un fichier XML les informations contenues dans le singleton Statistique

            Les données sont stockées sous la forme suivante :

            <statistique>
                <nbretats>
                <nbrresultats>
                <etats>
                    <etat>
                        <numero_etat>
                        </numero_etat>
                        <niveau_de_batterie_moyen>
                        </niveau_de_batterie_moyen>
                        <nbr_actifs>
                        </nbr_actifs>
                        <cycle>
                        </cycle>
                        <moment_insertion>
                        </moment_insertion>
                    </etat>
                    <etat>
                        ...
                    </etat>
                    ...
                </etats>
                <resultats>
                    <resultat>
                        <intervalle></intervalle>
                        <dureedevie></dureedevie>
                    </resultat>
                <resultats>
            </statistique>
        """
        _log.Linfo("Début ## FileManager.FMchargerStatistiques")

        from Controleur.ReseauControleur import ReseauControleur

        _chemin = self.FM_chemin_local + "\\resultats simulation\\statistiques.xml"

        if os.path.exists(_chemin):
            from Controleur.Statistiques import Statistiques
            _statistiques = Statistiques()

            _racine = parse(_chemin)

            # Récupération des états
            for _etat in _racine.iter("etat"):
                _netat = int(next(_etat.iter("numero_etat")).text)
                _niveau_batterie_moyen = int(
                    next(_etat.iter("niveau_de_batterie_moyen")).text)
                _nbr_actifs = int(next(_etat.iter("nbr_actifs")).text)
                _cycle = int(next(_etat.iter("cycle")).text)
                _moment = int(next(_etat.iter("moment_insertion")).text)

                _statistiques.SajouterDonneesBrutes(_niveau_batterie_moyen,
                                                    _nbr_actifs, _cycle,
                                                    _moment)

            # Récupérations des résultats de performance de la simulation
            for _resultat in _racine.iter("resultat"):
                _intervalle = float(next(_resultat.iter("intervalle")).text)
                _dureedevie = float(next(_resultat.iter("duree")).text)

                _statistiques.SajouterResultat(_intervalle, _dureedevie)

            # Test si le nombre d'états détectés et celui donné correspondent
            _nbr_etats = int(next(_racine.iter("nbretats")).text)
            if _statistiques.S_nombre_etats != _nbr_etats:

                ReseauControleur.RCmessageInformation(
                    "Le nombre d'état en meta et réél ne correspondent pas. "
                    "Chargement des informations statistiques échoué")
                _statistiques.SviderEtats(False)

            # Test si le nombre de résultats détecté et celui donné correspondent
            _nbr_resultats = int(next(_racine.iter("nbrresultats")).text)
            if len(_statistiques.S_resultats) != _nbr_resultats:
                ReseauControleur.RCmessageInformation(
                    "Le nombre de résultats en meta et réél ne correspondent pas. "
                    "Chargement des informations statistiques échoué")
                _statistiques.SviderEtats(False)
Example #9
0
    def FMsauvegarderStatistiques():
        """
            Permet de sauvegarder en local dans un fichier XML les informations contenues dans le singleton Statistique

            Les données sont stockées sous la forme suivante :

            <statistique>
                <nbretats>
                <nbrresultats>
                <etats>
                    <etat>
                        <numero_etat>
                        </numero_etat>
                        </niveau_de_batterie_moyen>
                        <niveau_de_batterie_moyen>
                        </niveau_de_batterie_moyen>
                        <nbr_actifs>
                        </nbr_actifs>
                        <moment_insertion>
                        </moment_insertion>
                        <cycle>
                        </cycle>
                    </etat>
                    <etat>
                        ...
                    </etat>
                    ...
                </etats>
                <resultats>
                    <resultat>
                        <intervalle></intervalle>
                        <dureedevie></dureedevie>
                    </resultat>
                <resultats>
            </statistique>
        """
        _log.Linfo("Début ## FileManager.FMsauvegarderStatistiques")

        from Controleur.Statistiques import Statistiques
        _statistiques = Statistiques()

        _chemin = FileManager.FM_chemin_local + "\\resultats simulation\\statistiques"
        # La racine
        _racine = Element("statistique")

        # Sauvegarde des états
        _nbretats = SubElement(_racine, "nbretats")
        _nbretats.text = str(_statistiques.S_nombre_etats)

        # Les éléments de chaque état
        _etats = SubElement(_racine, "etats")
        for _etat in range(0, _statistiques.S_nombre_etats):

            _e = SubElement(_etats, "etat")

            SubElement(_e, "numero_etat").text = str(_etat)

            SubElement(_e, "niveau_de_batterie_moyen").text = str(
                _statistiques.S_niveau_de_batterie_moyen[_etat])

            SubElement(_e, "nbr_actifs").text = str(
                _statistiques.S_nbr_actifs[_etat])

            SubElement(_e, "cycle").text = str(_statistiques.S_cycles[_etat])

            SubElement(_e, "moment_insertion").text = str(
                _statistiques.S_moment_insertion[_etat])

        # Sauvegarde des résultats
        _nbrresultats = SubElement(_racine, "nbrresultats")
        _nbrresultats.text = str(len(_statistiques.S_resultats))

        _resultats = SubElement(_racine, "resultats")
        for _resultat in _statistiques.S_resultats:
            _r = SubElement(_resultats, "resultat")

            SubElement(_r, "intervalle").text = str(_resultat["intervalle"])
            SubElement(_r, "duree").text = str(_resultat["duree"])

        # Deux lignes pour bien mettre en page l'xml
        _xml = tostring(_racine, 'utf-8')
        _xml = minidom.parseString(_xml).toprettyxml("  ")

        with open(_chemin + ".xml", 'w') as f:
            f.write(_xml)
Example #10
0
    def GgenerationHTML(_reseau):
        """
        Génère l'html de l'affichage à partir d'un réseau

        Algorithme tiré de l'exemple : https://plot.ly/python/network-graphs/

        L'affichage est décomposée. Ainsi les arcs puis les noeuds sont affichés en trois parties : les dominants et
        les non dominants, ainsi que les déconnectés

        :param _reseau : Reseau, le réseau à traiter

        :return String, le code HTML
        """
        _log.Linfo("Début ## Generateur.GgenerationHTML")

        # Récupération, pour commencer, l'ensemble des noeuds déconnectés
        from Moteur.Simulateur import Simulateur
        _simulateur = Simulateur(None)

        # On test si on est dans le cas du cycle 0, si c'est le cas on cherche si la fin de vie est atteinte avec la
        # méthode adéquate
        from Controleur.Statistiques import Statistiques
        _statistiques = Statistiques()
        if len(_statistiques.S_cycles) == 0 or max(
                _statistiques.S_cycles) == 0:
            _intervalle = 0
        else:
            _intervalle = -1

        _, _ensemble_deconnecte = _simulateur.SfinDeVieAtteinte(
            _reseau, _intervalle)

        # ==============================================================================================================
        # Paramétrage des arcs
        # ==============================================================================================================

        colors = []
        colors_dominant = []
        _arcs = []
        _arcs_dominants = []
        # Choix des couleurs en premier.
        # Les arcs de l'ensemble dominant sont rouges, les autres bleus clairs
        # Les arcs déconnectés de l'ensemble dominant sont noirs, les autres gris
        # Auss idécomposition des arcs en deux partis, ceux de l'ensemble dominant et les autres
        for _arc in _reseau.R_graphe.edges():
            if _arc in _reseau.R_ensemble_dominant.edges():
                _arcs_dominants.append(_arc)
                if _arc[0] in _ensemble_deconnecte or _arc[
                        1] in _ensemble_deconnecte:
                    colors_dominant.append("black")
                else:
                    colors_dominant.append("red")
            else:
                _arcs.append(_arc)
                if _arc[0] in _ensemble_deconnecte or _arc[
                        1] in _ensemble_deconnecte:
                    colors.append("gray")
                else:
                    colors.append("#A9D0F5")

        # Données des arcs non dominants à afficher
        edge_trace = [
            dict(type='scatter',
                 x=[
                     _reseau.R_graphe.node[edge[0]]['pos'][0],
                     _reseau.R_graphe.node[edge[1]]['pos'][0]
                 ],
                 y=[
                     _reseau.R_graphe.node[edge[0]]['pos'][1],
                     _reseau.R_graphe.node[edge[1]]['pos'][1]
                 ],
                 mode='lines',
                 line=dict(width=2, color=colors[c]))
            for c, edge in enumerate(_arcs)
        ]

        # Données des arcs dominants à afficher
        edge_trace_dominant = [
            dict(type='scatter',
                 x=[
                     _reseau.R_graphe.node[edge[0]]['pos'][0],
                     _reseau.R_graphe.node[edge[1]]['pos'][0]
                 ],
                 y=[
                     _reseau.R_graphe.node[edge[0]]['pos'][1],
                     _reseau.R_graphe.node[edge[1]]['pos'][1]
                 ],
                 mode='lines',
                 line=dict(width=2, color=colors_dominant[c]))
            for c, edge in enumerate(_arcs_dominants)
        ]

        # ==============================================================================================================
        # Paramétrage des noeuds
        # ==============================================================================================================

        _nodes_pos = []
        _nodes_pos_dominant = []
        _nodes_pos_deconnectes = []
        # Décomposition des arcs en trois parties, les noeuds dominants, les déconnectés et le reste
        for _noeud in _reseau.R_graphe.nodes():
            if _reseau.R_graphe.node[_noeud]['role'] != Roles.PUIT:
                if _noeud in _ensemble_deconnecte:
                    _nodes_pos_deconnectes.append([
                        _reseau.R_graphe.node[_noeud]['pos'][0],
                        _reseau.R_graphe.node[_noeud]['pos'][1]
                    ])
                elif _noeud in _reseau.R_ensemble_dominant.nodes():
                    _nodes_pos_dominant.append([
                        _reseau.R_graphe.node[_noeud]['pos'][0],
                        _reseau.R_graphe.node[_noeud]['pos'][1]
                    ])
                else:
                    _nodes_pos.append([
                        _reseau.R_graphe.node[_noeud]['pos'][0],
                        _reseau.R_graphe.node[_noeud]['pos'][1]
                    ])
        _nodes_pos = numpy.array(_nodes_pos)
        _nodes_pos_dominant = numpy.array(_nodes_pos_dominant)
        _nodes_pos_deconnectes = numpy.array(_nodes_pos_deconnectes)

        # Données des noeuds à afficher
        _x, _y = [], []
        for _pos in _nodes_pos:
            _x.append(_pos[0])
            _y.append(_pos[1])
        node_trace = dict(
            type='scatter',
            x=_x,
            y=_y,
            hoverinfo='text',
            text=[],
            mode='markers',
            marker=dict(
                showscale=True,
                cmax=FenetreCreation.FCobtenirCapaciteMaxBatterie(),
                cmin=0,
                # colorscale options
                # 'Greys' | 'YlGnBu' | 'Greens' | 'YlOrRd' | 'Bluered' | 'RdBu' |
                # 'Reds' | 'Blues' | 'Picnic' | 'Rainbow' | 'Portland' | 'Jet' |
                # 'Hot' | 'Blackbody' | 'Earth' | 'Electric' | 'Viridis' |
                colorscale='Reds',
                reversescale=True,
                color=[],
                size=10,
                colorbar=dict(thickness=15,
                              title='Niveau de la batterie',
                              xanchor='left',
                              titleside='right')))

        # Données des noeuds dominants à afficher
        _x, _y = [], []
        for _pos in _nodes_pos_dominant:
            _x.append(_pos[0])
            _y.append(_pos[1])
        node_trace_dominant = dict(
            type='scatter',
            x=_x,
            y=_y,
            hoverinfo='text',
            text=[],
            mode='markers',
            marker=dict(
                showscale=False,
                cmax=FenetreCreation.FCobtenirCapaciteMaxBatterie(),
                cmin=0,
                # colorscale options
                # 'Greys' | 'YlGnBu' | 'Greens' | 'YlOrRd' | 'Bluered' | 'RdBu' |
                # 'Reds' | 'Blues' | 'Picnic' | 'Rainbow' | 'Portland' | 'Jet' |
                # 'Hot' | 'Blackbody' | 'Earth' | 'Electric' | 'Viridis' |
                colorscale='Reds',
                reversescale=True,
                color=[],
                size=10,
                colorbar=dict(thickness=15,
                              title='Niveau de la batterie',
                              xanchor='left',
                              titleside='right'),
                line=dict(width=2, color="red")))

        # Données des noeuds déconnectés à afficher
        _x, _y = [], []
        for _pos in _nodes_pos_deconnectes:
            _x.append(_pos[0])
            _y.append(_pos[1])
        if len(_nodes_pos_deconnectes) > 0:
            node_trace_deconnecte = dict(
                type='scatter',
                x=_x,
                y=_y,
                hoverinfo='text',
                text=[],
                mode='markers',
                marker=dict(
                    showscale=False,
                    # colorscale options
                    # 'Greys' | 'YlGnBu' | 'Greens' | 'YlOrRd' | 'Bluered' | 'RdBu' |
                    # 'Reds' | 'Blues' | 'Picnic' | 'Rainbow' | 'Portland' | 'Jet' |
                    # 'Hot' | 'Blackbody' | 'Earth' | 'Electric' | 'Viridis' |
                    colorscale='Reds',
                    reversescale=True,
                    color=[],
                    size=10,
                    line=dict(width=0)))
        else:
            node_trace_deconnecte = []

        # Si il n'y a pas de données à afficher dans les noeuds, l'échelle de couleurs ne s'affiche pas.
        # On fait donc en sorte que l'échelle des noeuds dominants s'affiche à la place.
        if len(_nodes_pos) == 0:
            node_trace_dominant["marker"]["showscale"] = True

        _texte_puit = ""

        # Ajout des informations pour l'affichage d'informations supplémentaires
        # - Le texte qui s'affiche au survole d'un noeud avec la souris
        # - la couleur du noeud
        for node, adjacencies in enumerate(_reseau.R_graphe.adjacency()):
            # Le puit est dessiné en violet et les capteurs en nuance de couleur en fonction du niveau de leur batterie
            # Sont affichés au passage de la souris :
            #   - Le prochain noeud vers lequel envoyer les données
            #   - l'énergie restante (si ce n'est pas un puit, si c'est le cas sa couleur est mise en violet). Si il
            #       n'a plus d'énergie, sa couleur est mise en noir
            #   - le nombre de capteurs adjacent (si c'est le puit)

            if _reseau.R_graphe.node[node]['role'] == Roles.PUIT:
                _texte_puit = "Passerelle | " + str(len(
                    adjacencies[1])) + " capteurs adjacents"
            else:
                node_info = "Capteur n°" + str(node) + " | " + \
                            "Nv batterie : " + str(int(_reseau.R_graphe.node[node]['batterie'])) + " | " + \
                            "Route : " + str(_reseau.R_graphe.node[node]['route'])

                if node in _ensemble_deconnecte:
                    if _reseau.R_graphe.nodes()[node]['batterie'] > 0:
                        node_trace_deconnecte['marker']['color'] += tuple(
                            ['gray'])
                    else:
                        node_trace_deconnecte['marker']['color'] += tuple(
                            ['black'])
                    node_trace_deconnecte['text'] += tuple([node_info])
                elif node in _reseau.R_ensemble_dominant:
                    node_trace_dominant['marker']['color'] += tuple(
                        [_reseau.R_graphe.node[node]['batterie']])
                    node_trace_dominant['text'] += tuple([node_info])
                else:
                    node_trace['marker']['color'] += tuple(
                        [_reseau.R_graphe.node[node]['batterie']])
                    node_trace['text'] += tuple([node_info])

        # Le puit à afficher différemment
        _puits_trace = []
        for _noeud in _reseau.R_graphe.nodes():
            if _reseau.R_graphe.node[_noeud]['role'] == Roles.PUIT:
                _puits_trace.append(
                    dict(type='scatter',
                         x=[_reseau.R_graphe.node[_noeud]['pos'][0]],
                         y=[_reseau.R_graphe.node[_noeud]['pos'][1]],
                         hoverinfo='text',
                         text=_texte_puit,
                         mode='markers',
                         marker=dict(showscale=False,
                                     colorscale='Greys',
                                     reversescale=True,
                                     color='yellow',
                                     symbol=['pentagon'],
                                     size=20,
                                     line=dict(width=2, color="red"))))

        # On concatène l'ensemble des données, arcs et noeuds, à afficher. L'affiche est supperposé de gauche à droite
        if len(_nodes_pos_deconnectes) > 0:
            _datas = edge_trace + [node_trace] + edge_trace_dominant + [
                node_trace_deconnecte
            ] + [node_trace_dominant] + _puits_trace
        else:
            _datas = edge_trace + [node_trace] + edge_trace_dominant + [
                node_trace_dominant
            ] + _puits_trace

        # La création de la figure finale à afficher
        fig = go.Figure(data=_datas,
                        layout=go.Layout(title='',
                                         titlefont=dict(size=16),
                                         showlegend=False,
                                         hovermode='closest',
                                         margin=dict(b=20, l=5, r=5, t=40),
                                         annotations=[
                                             dict(text="",
                                                  showarrow=False,
                                                  xref="paper",
                                                  yref="paper",
                                                  x=0.005,
                                                  y=-0.002)
                                         ],
                                         xaxis=dict(showgrid=False,
                                                    zeroline=False,
                                                    showticklabels=False),
                                         yaxis=dict(showgrid=False,
                                                    zeroline=False,
                                                    showticklabels=False)))

        # Pour finir génération du html
        html = plotly.offline.plot(fig, auto_open=False, output_type='div')

        return """<html><head><meta charset="utf-8" /></head><body><script type="text/javascript">window.PlotlyConfig = 
                    {MathJaxConfig: 'local'};</script>""" \
               + html \
               + """<script type="text/javascript">window.addEventListener("resize", function(){Plotly.Plots.resize(docu