//======================================================================================================================================================================== // CONFIG_RESEAU_NMEA.QML // Ce fichier traite la configuration de PGNs NMEA2000. La page permet notamment de : // - Afficher tous les PGN/Field déjà configurés (présents ou absent mais utilisés sur un capteur) // - Afficher tous les PGN que ShipHeart peut traiter et qu'il a vu passer sur le réseau "récemment" // La page est appelée depuis la page PARAMETRES_AVANCES. //======================================================================================================================================================================== import QtQuick 2.12 import QtQuick.Controls 2.12 import qt.koriolan.shipheart 1.0 import"fonctions_date_heure.js" as Fonctions_date_heure Shipheart_page { id: page_config_reseau_nmea // Mis en forme : readonly property double affichage_hauteur_utile: shipheart_hauteur_page - shipheart_hauteur_bandeau_haut - shipheart_hauteur_bandeau_bas readonly property double pourcentage_largeur_labels_formulaire: 0.5 readonly property int nombre_capteurs_affiches_sur_une_colonne: 8 readonly property int nombre_sondes_affichees_sur_une_colonne: 8 readonly property double pourcentage_largeur_colonne_gauche: 0.75 readonly property int espace_colonnes_principales: 20 readonly property double pourcentage_bandeau_bas_largeur_zone_retour: 1.0 readonly property int periode_init_raffraichissement_parametres: 1 // En ms readonly property int periode_raffraichissement_parametres: 1000 // En ms /!\ Laisser à 1s afin que le compteur secondes fonctionne correctement... // Affichage : property int niveau_page: 0 property int defaut_bus_ow: 0 // Modèles : // Note : les modèles chargés dans 'main.qml' n'ont pas à être rechargés dans les pages suivantes //=========================================================== // Timer periode raffraichissement parametres : //=========================================================== Timer { id: timer_raffraichissement_parametres interval: periode_init_raffraichissement_parametres triggeredOnStart: false running: true repeat: true onTriggered: { if (interval == periode_init_raffraichissement_parametres) // Premier passage, 1ms après le premier chargement { interval = periode_raffraichissement_parametres; init_page(); } else { mise_a_jour_donnees(); } } } // Titre de la page : Shipheart_titre_1 {titre:qsTr("Réseau NMEA2000"); hauteur: shipheart_hauteur_bandeau_haut} //------------------------------------------------------- // Ecran de gauche (liste des PGNs) : //------------------------------------------------------- Rectangle { id: zone_affichage_gauche x: 0 y: shipheart_hauteur_bandeau_haut; width: (shipheart_largeur_page * pourcentage_largeur_colonne_gauche) - (espace_colonnes_principales / 2) height: affichage_hauteur_utile color: "transparent" //------------------------------------------------------------------- // Grille pour afficher les PGNs : GridView { id: grille_principale width: parent.width height: parent.height cellWidth: parent.width; cellHeight: affichage_hauteur_utile / nombre_sondes_affichees_sur_une_colonne snapMode: GridView.SnapToRow // L'arret de l'affichage se fera sur une rangée entière clip: true // Nécessaire pour que les Delegates s'arretent à l'intérieur de la GridView model: modele_grille_principale delegate: Rectangle { width: grille_principale.cellWidth height: grille_principale.cellHeight color: "transparent" Rectangle { width: parent.width - 10 height: parent.height - 10 anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter radius: shipheart_rayon_bouton color: shipheart_couleur_fond_bouton border.color: couleur_blanc_casse border.width: (actif === 0) ? 1 : 0 Text { anchors.fill: parent horizontalAlignment: Qt.AlignLeft verticalAlignment: Qt.AlignTop topPadding: 10 leftPadding: 20 text: "PGN : " + pgn + " - Field : " + field color: (actif === 1) ? couleur_gris_moyen : couleur_blanc_casse font.pixelSize: 14 wrapMode: Label.Wrap } Text { anchors.fill: parent horizontalAlignment: Qt.AlignLeft verticalAlignment: Qt.AlignTop topPadding: 10 leftPadding: parent.width / 4 text: nom color: (actif === 1) ? couleur_gris_moyen : couleur_blanc_casse font.pixelSize: 16 font.weight: Font.Bold wrapMode: Label.Wrap } Text { anchors.fill: parent horizontalAlignment: Qt.AlignRight verticalAlignment: Qt.AlignTop topPadding: 10 rightPadding: 20 text: Fonctions_date_heure.chaine_duree(age *1000) // age + " s" color: (actif === 1) ? couleur_gris_moyen : couleur_blanc_casse font.pixelSize: 14 wrapMode: Label.Wrap } Text { anchors.fill: parent horizontalAlignment: Qt.AlignLeft verticalAlignment: Qt.AlignBottom bottomPadding: 10 leftPadding: 20 text: nom_capteur color: (actif === 1) ? couleur_gris_moyen : couleur_blanc_casse font.pixelSize: 18 font.weight: Font.Bold wrapMode: Label.Wrap } Text { anchors.fill: parent horizontalAlignment: Qt.AlignRight verticalAlignment: Qt.AlignBottom bottomPadding: 10 rightPadding: 20 visible: valeur_valide text: valeur color: (actif === 1) ? couleur_gris_moyen : couleur_blanc_casse font.pixelSize: 18 font.bold: true } } MouseArea { // Zone d'interaction. On est obligé de la mettre dans la grille pour que Rectangle et MouseArea soient frères ou parent/enfant ET qu'on n'occupe qu'un espace dans la grille. anchors.fill: parent enabled: actif === 0 onClicked: { shipheart_clic(); stackView.push("config_capteur.qml", {"type_entrees": shipheart_capteur_type_entrees_nmea, "entrees": pgn + ":" + field}); } } } ListModel { id: modele_grille_principale } Label { anchors.fill: parent horizontalAlignment: Qt.AlignHCenter verticalAlignment: Qt.AlignVCenter visible: parent.count === 0 text: qsTr("Aucun PGN n'a encore été détecté sur le réseau NMEA2000...") color: couleur_rouge_transparent font.pixelSize: 15 font.bold: true wrapMode: Label.Wrap } } } //------------------------------------------------------- // Ecran de droite (liste des sondes de température) : //------------------------------------------------------- Rectangle { id: zone_affichage_droite x: (shipheart_largeur_page * pourcentage_largeur_colonne_gauche) + (espace_colonnes_principales / 2) y: shipheart_hauteur_bandeau_haut; width: (shipheart_largeur_page * (1 - pourcentage_largeur_colonne_gauche)) - (espace_colonnes_principales / 2) height: affichage_hauteur_utile color: "transparent" } //------------------------------------------------------- // Bandeau bas : //------------------------------------------------------- Row { x: 0 y: shipheart_hauteur_page - shipheart_hauteur_bandeau_bas; width: shipheart_largeur_page; height: shipheart_hauteur_bandeau_bas; padding: 5 spacing: 5 //................................................. // Bouton retour //................................................. Rectangle { id: bandeau_bas_zone_retour width: (parent.width * pourcentage_bandeau_bas_largeur_zone_retour) - (2 * parent.padding) height: shipheart_hauteur_bandeau_bas - parent.topPadding - parent.bottomPadding; radius: shipheart_rayon_bouton color: shipheart_couleur_fond_bouton Image { source: "/images/icone_retour.png" sourceSize.height: 30 anchors { verticalCenter: parent.verticalCenter horizontalCenter: parent.horizontalCenter } } MouseArea { // Zone d'interaction. On est obligé de la mettre dans la grille pour que Rectangle et MouseArea soient frères ou parent/enfant ET qu'on n'occupe qu'un espace dans la grille. id: mouse_area_bandeau_bas_zone_retour anchors.fill: parent onClicked: { shipheart_clic(); stackView.pop() } } } } // Note : il est inutile de prévoir un Mousearea pour sortir de l'économiseur sur cette page puisqu'il // est systématiquement bloqué pour toutes les pages lancées depuis 'Paramètres Avancés'. //============================================================================================================= // Init de la page //============================================================================================================= function init_page() { niveau_page = stackView.depth - 1; // Permet de stocker le niveau de la page dans la Stackview mise_a_jour_donnees(); } //============================================================================================================= // Mise à jour des données //============================================================================================================= function mise_a_jour_donnees() { var req, res; var i; var nb; //======================================================================= // Grille principale (liste des sondes de température configurées) : modele_grille_principale.clear(); // RAZ des valeurs existantes req = 'SELECT '; req += ' Pgn, '; req += ' Field, ' req += ' Nom, '; req += ' Actif, '; req += ' (SELECT Unite FROM TB_Variables WHERE Cle_primaire=ID_Variable) AS Unite, '; req += ' Valeur, '; req += ' Precision_affichage_mesures,' req += ' (UNIX_TIMESTAMP() - UNIX_TIMESTAMP(Date_maj)) AS Age '; req += ' FROM TB_Nmea2000 '; req += ' ORDER BY Pgn, Field'; //console.log("Requête = [ " + req + "; ]"); nb = bdd.requete(req); for (i = 0; i < nb; i ++) { res = bdd.lecture_ligne(); if (!res.isEmpty) { modele_grille_principale.append({ "pgn": Number(res[0]), "field": Number(res[1]), "nom": res[2], "actif": Number(res[3]), "valeur": Number(res[5]).toFixed(Number(res[6])) + ((res[4] !== "") ? (" " + res[4]) : ""), "valeur_valide": true, "age": Number(res[7]), "nom_capteur": qsTr("PGN non affecté") }); } } // Mise à jour du nom des capteurs utilisant ces sondes : for (i = 0; i < modele_grille_principale.count; i ++) { if (modele_grille_principale.get(i).actif > 0) { req = 'SELECT Nom FROM TB_Capteurs WHERE Adresse_module=0 AND Type_entrees=' + shipheart_capteur_type_entrees_nmea + ' AND Entrees="' + modele_grille_principale.get(i).pgn + ':' + modele_grille_principale.get(i).field + '" '; //console.log("Requête = [ " + req + "; ]"); var n = bdd.requete(req); if (n > 0) { res = bdd.lecture_ligne(); modele_grille_principale.setProperty(i, "nom_capteur", res[0]); } } } // Mise à jour du champ 'valeur_valide' : : for (i = 0; i < modele_grille_principale.count; i ++) { if (modele_grille_principale.get(i).actif === 0) // On ne teste que les entrées qui sont Inactive (les Actives ont forcément une valeur valide) { // Recherche su au moins un PGN/Field pointe sur le même PGN et est actif (dans ce cas, le Compagnon et l'Appli maintiennent à jour les valeurs de tous les Fields, même ceux qui ne sont pas valides) req = 'SELECT COUNT(*) FROM TB_Nmea2000 WHERE Pgn=' + modele_grille_principale.get(i).pgn + ' AND Actif=1 '; //console.log("Requête = [ " + req + "; ]"); res = bdd.requete_unique(req); if (Number(res[0]) === 0) modele_grille_principale.setProperty(i, "valeur_valide", false); // Si aucun PGN/Field pointant sur le même PGN n'est actif, alors la valeur ne sera jamais mise à jour et il vaut mieux ne pas l'afficher... } } } }