3881 lines
197 KiB
QML
3881 lines
197 KiB
QML
import QtQuick 2.12
|
|
import QtQuick.Controls 2.12
|
|
import QtQuick.Layouts 1.12
|
|
import Qt.labs.folderlistmodel 2.12
|
|
|
|
import qt.koriolan.shipheart 1.0
|
|
import"fonctions.js" as Fonctions
|
|
import"fonctions_date_heure.js" as Fonctions_date_heure
|
|
import"fonctions_localisation.js" as Fonctions_localisation
|
|
import"suncalc.js" as Suncalc
|
|
|
|
import "."
|
|
|
|
|
|
Shipheart_page {
|
|
id: page_accueil
|
|
|
|
// Mis en forme :
|
|
readonly property double pourcentage_largeur_page_affichage_circuit: 0.7
|
|
readonly property int espace_colonnes_principales: 30
|
|
readonly property int espace_colonnes_secondaires: 10
|
|
readonly property bool flag_fleches_suite_onglets: false // Permet de simplement dévalider les flèches si besoin
|
|
readonly property int largeur_bouton_suite: flag_fleches_suite_onglets ? 15 : 0
|
|
readonly property int espace_bouton_suite: flag_fleches_suite_onglets ? 10 : 0
|
|
|
|
readonly property int deport_haut_masquage_onglets: 20
|
|
readonly property int espace_onglets_circuits: 10
|
|
readonly property int espace_onglets_reservoirs: 10
|
|
readonly property int espace_onglets_batteries: 10
|
|
readonly property int espace_onglets_capteurs: 10
|
|
readonly property int rayon_onglets: 20
|
|
|
|
readonly property int onglet_page_top_margin_texte_haut: 15
|
|
readonly property int onglet_page_bottom_margin_texte_bas: 10
|
|
|
|
readonly property int espace_lignes_principales: 30
|
|
readonly property int espace_lignes_secondaires: 10
|
|
|
|
readonly property double bandeau_bas_spacing: 5
|
|
readonly property double bandeau_bas_largeur_zone_status_connexions: 65
|
|
readonly property double bandeau_bas_largeur_zone_pages: shipheart_largeur_page - bandeau_bas_largeur_zone_status_connexions - bandeau_bas_largeur_zone_parametres
|
|
readonly property double bandeau_bas_largeur_zone_parametres: 85
|
|
|
|
readonly property int periode_init_timer_principal: 1 // En ms
|
|
readonly property int step_timer_appui_long: 30 // en ms
|
|
readonly property int periode_timer_chrono: 100 // En ms
|
|
readonly property int periode_timer_minuteur: 1000 // En ms
|
|
|
|
|
|
// Affichage :
|
|
property int nombre_colonnes_affichage_circuits: 2
|
|
property int nombre_circuits_affiches_sur_une_colonne: 4
|
|
property int nombre_colonnes_affichage_capteurs: 3
|
|
|
|
// Données :
|
|
property bool flag_init_tache_de_fond: true // Permet de traiter jsute après le démarrage une première tâche de fond (pour la partie "toute les minutes") avant de se synchroniser sur les changements de minutes
|
|
property int valeur_timer_appui_long: 0
|
|
property int id_groupe_circuits: 0
|
|
property int id_groupe_reservoirs: 0
|
|
property int id_groupe_batteries: 0
|
|
property int id_groupe_capteurs: 0
|
|
property double pourcentage_hauteur_zone_haut_vs_bas: 0.5
|
|
property string image_etat_connexion_1: ""
|
|
property string image_etat_connexion_2: ""
|
|
property string image_etat_connexion_3: ""
|
|
property string image_etat_connexion_4: ""
|
|
property string date_courante: "----"
|
|
property string heure_courante: "--:--:--"
|
|
|
|
property int id_message_users: 0
|
|
property int message_users_code: shipheart_message_users_code_aucun
|
|
|
|
property int compteur_chrono: 0
|
|
property bool flag_mouse_area_chrono_pressed: false // Nécessaire car le mousearea est dans un delegate de pages et on ne peut donc pas lui donner un ID unique.
|
|
property int compteur_minuteur: 0
|
|
property int compteur_initial_minuteur: 0
|
|
property bool flag_mouse_area_minuteur_pressed: false // Nécessaire car le mousearea est dans un delegate de pages et on ne peut donc pas lui donner un ID unique.
|
|
property int etat_minuteur: 0 // 0=Off, 1=On
|
|
property int reveils_next_jour: 0 // entre 1 (lundi) et 7 (dimanche) voire 8 (tous les jours). Note : 0 indique qu'il n'y a aucune condition valide actuellement.
|
|
property int reveils_next_heure: 0
|
|
property int reveils_next_minute: 0
|
|
property int reveils_next_distance: 0
|
|
|
|
// Modèles :
|
|
// Note : les modèles chargés dans 'main.qml' n'ont pas à être rechargés dans les pages suivantes
|
|
|
|
|
|
//===========================================================
|
|
// Modèles de lecture de répertoire :
|
|
// Attention : pour que les modèles maintiennent à jour leur données,
|
|
// il faut que le répertoire cible (le contenant) ne soient pas modifié.
|
|
// Par exemple, le fait de supprimer le répertoire (pour le vider)
|
|
// puis de le recréer avec le même nom fait perdre le lien au modèle
|
|
// qui ne se met alors plus à jour...
|
|
//===========================================================
|
|
FolderListModel {
|
|
id: repertoire_a_valider
|
|
nameFilters: ["*.enc"]
|
|
showDirs: false
|
|
sortField: FolderListModel.Time // Tri sur l'heure du fichier
|
|
folder: "file://" + shipheart_repertoire_versions_a_valider // Pour un fichier, il faut obligatoirement ajouter 'file:' devant. Ou 'qrc:' pour une URL. Le message d'alerte de QT Creator est toujours là...
|
|
onStatusChanged: {
|
|
// Suppression de fichiers les plus anciens pour ne garder que le plus récent :
|
|
for (let i=0; i < repertoire_a_valider.count; i++)
|
|
{
|
|
if (i > 0) // Le fichier de rang 0 est le plus récent du fait du tri par date
|
|
{
|
|
let commande = "rm " + shipheart_repertoire_versions_a_valider + "/" + repertoire_a_valider.get(i, "fileName");
|
|
console.log("Exécution de la commande [ " + commande + " ]");
|
|
systeme.commande_shell(commande, "");
|
|
}
|
|
}
|
|
|
|
// Mise à jour de 'shipheart_fichier_a_valider' utilisé pour les mises àjour à distance :
|
|
if ((repertoire_a_valider.count > 0) &&
|
|
(!repertoire_a_valider.get(0, "fileName").includes("_new")) && // On ignore les fichiers de config usine car trop dangereux et probablement pas utile (si besoin d'une Factory Reset, le faire directement depuis le bouton dédié)
|
|
(!repertoire_a_valider.get(0, "fileName").includes("_restore")) ) // On élimine les fichiers de restoration car ils ne sont pas utile pour les mises à jour à distance
|
|
{
|
|
shipheart_fichier_a_valider = repertoire_a_valider.get(0, "fileName");
|
|
}
|
|
else shipheart_fichier_a_valider = "";
|
|
}
|
|
}
|
|
|
|
FolderListModel {
|
|
id: repertoire_a_charger
|
|
nameFilters: ["*.enc"]
|
|
showDirs: false
|
|
sortField: FolderListModel.Time // Tri sur l'heure du fichier
|
|
folder: "file://" + shipheart_repertoire_versions_a_charger // Pour un fichier, il faut obligatoirement ajouter 'file:' devant. Ou 'qrc:' pour une URL. Le message d'alerte de QT Creator est toujours là...
|
|
onStatusChanged: {
|
|
// Suppression de fichiers les plus anciens pour ne garder que le plus récent :
|
|
for (let i=0; i < repertoire_a_charger.count; i++)
|
|
{
|
|
//console.log("A_CHARGER : "+ i +"- fichier = "+ repertoire_a_charger.get(i, "fileName")+" / "+ repertoire_a_charger.get(i, "fileModified"));
|
|
if (i > 0) // Le fichier de rang 0 est le plus récent du fait du tri par date
|
|
{
|
|
let commande = "rm " + shipheart_repertoire_versions_a_charger + "/" + repertoire_a_charger.get(i, "fileName");
|
|
systeme.commande_shell(commande, "");
|
|
}
|
|
}
|
|
|
|
// Mise à jour de 'shipheart_fichier_a_charger' utilisé pour les mises àjour à distance :
|
|
if ((repertoire_a_charger.count > 0) &&
|
|
(!repertoire_a_charger.get(0, "fileName").includes("_new")) && // On ignore les fichiers de config usine car trop dangereux et probablement pas utile (si besoin d'une Factory Reset, le faire directement depuis le bouton dédié)
|
|
(!repertoire_a_charger.get(0, "fileName").includes("_restore")) ) // On élimine les fichiers de restoration car ils ne sont pas utile pour les mises à jour à distance
|
|
|
|
{
|
|
shipheart_fichier_a_charger = repertoire_a_charger.get(0, "fileName");
|
|
}
|
|
else shipheart_fichier_a_charger = "";
|
|
|
|
shipheart_nb_fichiers_a_charger = repertoire_a_charger.count;
|
|
}
|
|
}
|
|
|
|
//===========================================================
|
|
// Economiseur :
|
|
// Il n'est mis que sur cette page qui est toujours présente.
|
|
// NB : si on le met dans Shipheart_page, une instance est créée
|
|
// pour chaque page de niveau inférieur (et alors, on décrémente
|
|
// plusieurs fois par seconde en fonction du niveau de pages...).
|
|
//===========================================================
|
|
Timer {
|
|
id: timer_economiseur
|
|
interval: 1000
|
|
running: true
|
|
repeat: true
|
|
onTriggered: {
|
|
if ((shipheart_compteur_economiseur > 0) &&
|
|
(message_users_code === shipheart_message_users_code_aucun) && // Si un message user est affiché, on ne décrémente pas le compteur d'économiseur...
|
|
(shipheart_flag_blocage_compteurs_pendant_config === false) && // Permet de ne pas décompter tant qu'on est en configuration (SDIR #221)
|
|
!shipheart_flag_nettoyage_ecran_en_cours ) // SDIR #244
|
|
{
|
|
if (-- shipheart_compteur_economiseur === 0) mise_en_veille(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//===========================================================
|
|
// Timer principal (a priori, 1 seconde) :
|
|
//===========================================================
|
|
Timer {
|
|
id: timer_home
|
|
interval: periode_init_timer_principal // Cette valeur n'est utilisée qu'une fois au démarrage. Ensuite, elle est fixée à 1s
|
|
triggeredOnStart: false // Cette valeur est importante car, si TRUE, on a des soucis lors du réarmement suite à un appui sur un bouton (exemple : consigne dans 'Shipheart_bouton_circuit')
|
|
running: true
|
|
repeat: true
|
|
onTriggered: {
|
|
//------------------------------------------------
|
|
// Init puis adaptation de la période du timer :
|
|
if (interval === periode_init_timer_principal) { // Premier passage, 1ms après le premier chargement
|
|
init_page();
|
|
interval = shipheart_periode_timer_home;
|
|
}
|
|
else // Hors phase d'init :
|
|
{
|
|
//----------------------------------------------------------------
|
|
// Mises à jour des données selon que la page est visible ou non :
|
|
if (stackView.depth === (shipheart_niveau_home + 1)) // Désactive le raffraichissement quand la page n'est pas activée dans la pile
|
|
{
|
|
mise_a_jour();
|
|
if (boite_information_reseaux.opened) boite_information_reseaux.message = maj_message_reseaux();
|
|
}
|
|
|
|
//------------------------------------------------
|
|
// Suivi du time-out de niveau d'accès :
|
|
if ((shipheart_compteur_time_out_niveau_acces > 0) &&
|
|
(shipheart_flag_blocage_compteurs_pendant_config === false)) // Permet de ne pas décompter tant qu'on est en configuration (SDIR #187)
|
|
{
|
|
if (-- shipheart_compteur_time_out_niveau_acces === 0)
|
|
{
|
|
shipheart_niveau_acces_en_cours = shipheart_niveau_acces_aucun;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------
|
|
// Mise à jour des messages users :
|
|
if (boite_message_user.visible) maj_messages_users();
|
|
|
|
//------------------------------------------------
|
|
// Tâche de fond :
|
|
tache_de_fond();
|
|
}
|
|
}
|
|
}
|
|
|
|
//===========================================================
|
|
// Timer pour gérer les appuis longs :
|
|
//===========================================================
|
|
Timer {
|
|
id: timer_appui_long
|
|
interval: step_timer_appui_long
|
|
triggeredOnStart: false
|
|
running: false
|
|
repeat: true
|
|
onTriggered: {
|
|
if (valeur_timer_appui_long < shipheart_mouse_press_and_hold_interval_tres_long) valeur_timer_appui_long+= step_timer_appui_long;
|
|
else // Le fait de ne pas utilise le OnPressandHold permet d'être sût que la sortie se fait au même moment que la fin du comptage (sinon, on peut avoir de petits décalages)
|
|
{
|
|
timer_appui_long.running = false;
|
|
|
|
if (flag_mouse_area_chrono_pressed)
|
|
{
|
|
timer_chrono.stop(); // Normalement déjà arrêté...
|
|
compteur_chrono = 0;
|
|
}
|
|
if (flag_mouse_area_minuteur_pressed)
|
|
{
|
|
timer_minuteur.stop(); // Normalement déjà arrêté...
|
|
etat_minuteur = 0;
|
|
compteur_minuteur = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//===========================================================
|
|
// Timer chrono :
|
|
//===========================================================
|
|
Timer {
|
|
id: timer_chrono
|
|
interval: periode_timer_chrono
|
|
triggeredOnStart: false
|
|
running: false
|
|
repeat: true
|
|
onTriggered: {
|
|
compteur_chrono ++;
|
|
|
|
if (compteur_chrono >= (24 * 60 * 60 * 10)) compteur_chrono = 0; // Rebouclage au bout de 24h
|
|
}
|
|
}
|
|
|
|
//===========================================================
|
|
// Timer minuteur :
|
|
//===========================================================
|
|
Timer {
|
|
id: timer_minuteur
|
|
interval: periode_timer_minuteur
|
|
triggeredOnStart: false
|
|
running: false
|
|
repeat: true
|
|
onTriggered: {
|
|
compteur_minuteur --;
|
|
if (compteur_minuteur <= 0)
|
|
{
|
|
timer_minuteur.stop();
|
|
traitement_fin_minuteur();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//===========================================================
|
|
// Lorsque la page est sur le point d'être affichée dans la pile :
|
|
//===========================================================
|
|
StackView.onActivating: { // Le 'onActivating' permet de ne pas voir la mise à jour puisqu'elle est lancée dès que la page va être chargée
|
|
// StackView.onActivated: { // Le 'onActivated' laisse voir la mise à jour (puisqu'elle est lancée quand la page est complètement affichée
|
|
init_circuits(); // Utile au démarrage ET au retour d'autres pages si on a modifié la config des groupes de circuits entre temps...
|
|
init_reservoirs();
|
|
init_batteries();
|
|
init_capteurs();
|
|
init_pages();
|
|
}
|
|
|
|
|
|
//===========================================================
|
|
// Grille principale :
|
|
//===========================================================
|
|
GridLayout {
|
|
id: home_grid
|
|
columns: 2
|
|
columnSpacing: espace_colonnes_principales
|
|
rowSpacing: 0
|
|
|
|
//-------------------------------------------------------
|
|
// Zone de gauche :
|
|
//-------------------------------------------------------
|
|
Rectangle {
|
|
width: (shipheart_largeur_page * pourcentage_largeur_page_affichage_circuit) - (espace_colonnes_principales / 2)
|
|
height: shipheart_hauteur_page - shipheart_hauteur_bandeau_bas - home_grid.rowSpacing;
|
|
color: "transparent"
|
|
|
|
//.................................................................................
|
|
// Circuits
|
|
//.................................................................................
|
|
Rectangle {
|
|
id: zone_circuits
|
|
|
|
width: parent.width
|
|
height: (parent.height * pourcentage_hauteur_zone_haut_vs_bas) - (espace_lignes_principales / 2)
|
|
color: "transparent"
|
|
|
|
//-----------------------------------------------------------
|
|
// Onglets :
|
|
Rectangle {
|
|
id: onglets_circuits
|
|
|
|
width: parent.width
|
|
height: shipheart_hauteur_bandeau_haut
|
|
color: "transparent"
|
|
visible: (modele_onglets_circuits.count > 1) ? true : false
|
|
|
|
ListModel {
|
|
id: modele_onglets_circuits
|
|
}
|
|
|
|
GridView {
|
|
id: grille_onglets_circuits
|
|
|
|
property int index_base_en_cours: 0 // Utilsé pour stocker l'index du premier widget affiché à gauche
|
|
|
|
x: largeur_bouton_suite + espace_bouton_suite
|
|
y: -deport_haut_masquage_onglets
|
|
width: parent.width - (2 * (largeur_bouton_suite + espace_bouton_suite))
|
|
height: parent.height + deport_haut_masquage_onglets
|
|
cellWidth: width / ((modele_onglets_circuits.count > 0) ? Math.min(modele_onglets_circuits.count, 5) : 1)
|
|
cellHeight: shipheart_hauteur_bandeau_haut + deport_haut_masquage_onglets
|
|
|
|
highlightRangeMode: flag_fleches_suite_onglets
|
|
? GridView.StrictlyEnforceRange // Nécessaire pour que 'index_base_en_cours' soit mis à jour. Au passage, autorise de faire défiler les widgets jusqu'à ne garder que le dernier visible (pas génant et même plutôt sympa...)
|
|
: GridView.NoHighlightRange
|
|
flow: GridView.FlowTopToBottom // Items are laid out from top to bottom, and the view scrolls horizontally
|
|
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_onglets_circuits
|
|
|
|
onMovementEnded: {
|
|
index_base_en_cours = currentIndex; // Capte la valeur de currentIndex aà la fin du mouvement (la valeur vaut alors l'index du widget le plus à gauche). Si on ne le capte pas, la valeur de CurrentIndex repasse à 0 après l'arrêt du flicker (pourquoi...???)
|
|
}
|
|
|
|
delegate: Rectangle {
|
|
width: grille_onglets_circuits.cellWidth - 2
|
|
height: grille_onglets_circuits.cellHeight
|
|
radius: 20
|
|
color: model.actif ? shipheart_couleur_fond_bouton_actif : shipheart_couleur_fond_bouton
|
|
|
|
Text {
|
|
text: model.libelle
|
|
font.pixelSize: 14
|
|
font.bold: model.actif
|
|
opacity: model.actif ? 1.0 : 0.8
|
|
color: couleur_blanc_casse
|
|
anchors.fill: parent
|
|
horizontalAlignment: Text.AlignHCenter
|
|
verticalAlignment: Text.AlignVCenter
|
|
topPadding: deport_haut_masquage_onglets
|
|
wrapMode: Text.WordWrap
|
|
// elide: Text.ElideRight
|
|
}
|
|
Image {
|
|
source: (model.etat === 1) ? "/images/coin_bas_droite_orange.png" : "/images/coin_bas_droite_rouge.png"
|
|
sourceSize.height: 20
|
|
anchors {
|
|
bottom: parent.bottom
|
|
right: parent.right
|
|
}
|
|
visible: model.etat !== 0
|
|
}
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
onClicked: {
|
|
shipheart_clic();
|
|
id_groupe_circuits = model.id;
|
|
init_circuits();
|
|
}
|
|
}
|
|
}
|
|
ScrollBar.vertical: ScrollBar {}
|
|
} // Fin de Gridview des onglets
|
|
|
|
// Flèche de suite gauche :
|
|
Image {
|
|
anchors {
|
|
bottom: grille_onglets_circuits.bottom
|
|
right: grille_onglets_circuits.left
|
|
rightMargin: espace_bouton_suite
|
|
}
|
|
source: "/images/fleche_suite_gauche_sombre.png"
|
|
width: largeur_bouton_suite
|
|
height: grille_onglets_circuits.height - deport_haut_masquage_onglets
|
|
opacity: 0.5
|
|
visible: (!grille_onglets_circuits.moving) // Permet de ne pas afficher la flèche pendant le mouvement (surtout génant à cause du lag généré par la fin du mouvement qui est assez lent).
|
|
&& (grille_onglets_circuits.index_base_en_cours > 0)
|
|
&& flag_fleches_suite_onglets
|
|
}
|
|
|
|
// Flèche de suite droite :
|
|
Image {
|
|
anchors {
|
|
bottom: grille_onglets_circuits.bottom
|
|
left: grille_onglets_circuits.right
|
|
leftMargin: espace_bouton_suite
|
|
}
|
|
source: "/images/fleche_suite_droite_sombre.png"
|
|
width: largeur_bouton_suite
|
|
height: grille_onglets_circuits.height - deport_haut_masquage_onglets
|
|
opacity: 0.5
|
|
visible: (!grille_onglets_circuits.moving) // Permet de ne pas afficher la flèche pendant le mouvement (surtout génant à cause du lag généré par la fin du mouvement qui est assez lent).
|
|
&& ((grille_onglets_circuits.count - grille_onglets_circuits.index_base_en_cours) > (modele_onglets_circuits.count * (grille_onglets_circuits.height / grille_onglets_circuits.cellHeight))) // le calcul 'height/cellheight' donne le nombre de lignes de widget (généralement, 1 ou 2)
|
|
&& flag_fleches_suite_onglets
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// Boutons de circuits :
|
|
Rectangle {
|
|
Layout.row: 1
|
|
Layout.column: 1
|
|
width: parent.width + espace_colonnes_secondaires
|
|
height : (onglets_circuits.visible) ? (parent.height - shipheart_hauteur_bandeau_haut - espace_onglets_batteries) : parent.height
|
|
y: (onglets_circuits.visible) ? (shipheart_hauteur_bandeau_haut + espace_onglets_batteries) : 0
|
|
color: "transparent"
|
|
|
|
ListModel {
|
|
id: modele_circuits
|
|
}
|
|
|
|
GridView {
|
|
id: circuits_grid
|
|
|
|
x: 0
|
|
width: parent.width
|
|
height: parent.height
|
|
cellWidth: parent.width / nombre_colonnes_affichage_circuits;
|
|
cellHeight: height / nombre_circuits_affiches_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_circuits
|
|
|
|
delegate: Shipheart_bouton_circuit {
|
|
}
|
|
|
|
ScrollBar.vertical: ScrollBar {}
|
|
|
|
// Texte si aucun circuit n'est configuré sur cet onglet :
|
|
Label {
|
|
width: parent.width - espace_colonnes_secondaires // Le 'espace_colonnes_secondaires' permet e compenser l'augmentation de taille permettant d'annuler la perte d'un espace en fin de ligne de grille
|
|
height: parent.height
|
|
horizontalAlignment: Qt.AlignHCenter
|
|
verticalAlignment: Qt.AlignVCenter
|
|
visible: parent.count === 0
|
|
text: qsTr("Aucun circuit n'est configuré pour ce groupe...<br /><br />Si ce groupe n'a pas d'utilité, vous pouvez le supprimer dans le menu [Circuits] des Paramètres Avancés.")
|
|
color: couleur_rouge_transparent
|
|
font.pixelSize: 15
|
|
font.bold: true
|
|
wrapMode: Label.Wrap
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//.................................................................................
|
|
// Capteurs
|
|
//.................................................................................
|
|
Rectangle {
|
|
id: zone_capteurs
|
|
|
|
y: zone_circuits.height + espace_lignes_principales
|
|
width: parent.width
|
|
height: (parent.height * (1 - pourcentage_hauteur_zone_haut_vs_bas)) - (espace_lignes_principales / 2)
|
|
color: "transparent"
|
|
|
|
//-----------------------------------------------------------
|
|
// Onglets :
|
|
Rectangle {
|
|
id: onglets_capteurs
|
|
|
|
width: parent.width
|
|
height: shipheart_hauteur_bandeau_haut
|
|
color: "transparent"
|
|
visible: (modele_onglets_capteurs.count > 1) ? true : false
|
|
clip: true // Permet de limiter l'affichage des éléments enfants à ce rectangle (utile pour la partie haute des onglets à masquer...)
|
|
|
|
ListModel {
|
|
id: modele_onglets_capteurs
|
|
}
|
|
|
|
GridView {
|
|
id: grille_onglets_capteurs
|
|
|
|
x: largeur_bouton_suite + espace_bouton_suite
|
|
y: -deport_haut_masquage_onglets
|
|
width: parent.width
|
|
height: parent.height + deport_haut_masquage_onglets
|
|
cellWidth: width / ((modele_onglets_capteurs.count > 0) ? Math.min(modele_onglets_capteurs.count, 5) : 1)
|
|
cellHeight: shipheart_hauteur_bandeau_haut + deport_haut_masquage_onglets
|
|
|
|
highlightRangeMode: GridView.NoHighlightRange
|
|
flow: GridView.FlowTopToBottom // Items are laid out from top to bottom, and the view scrolls horizontally
|
|
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_onglets_capteurs
|
|
|
|
delegate: Rectangle {
|
|
width: grille_onglets_capteurs.cellWidth - 2
|
|
height: grille_onglets_capteurs.cellHeight
|
|
radius: 20
|
|
color: model.actif ? shipheart_couleur_fond_bouton_actif : shipheart_couleur_fond_bouton
|
|
|
|
Text {
|
|
text: model.libelle
|
|
font.pixelSize: 14
|
|
font.bold: model.actif
|
|
opacity: model.actif ? 1.0 : 0.8
|
|
color: couleur_blanc_casse
|
|
anchors.fill: parent
|
|
horizontalAlignment: Text.AlignHCenter
|
|
verticalAlignment: Text.AlignVCenter
|
|
topPadding: deport_haut_masquage_onglets
|
|
wrapMode: Text.WordWrap
|
|
}
|
|
Image {
|
|
source: (model.etat === 1) ? "/images/coin_bas_droite_orange.png" : "/images/coin_bas_droite_rouge.png"
|
|
sourceSize.height: 20
|
|
anchors {
|
|
bottom: parent.bottom
|
|
right: parent.right
|
|
}
|
|
visible: model.etat !== 0
|
|
}
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
onClicked: {
|
|
shipheart_clic();
|
|
id_groupe_capteurs = model.id;
|
|
init_capteurs();
|
|
}
|
|
}
|
|
}
|
|
ScrollBar.vertical: ScrollBar {}
|
|
} // Fin de Gridview des onglets
|
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------
|
|
// Boutons de capteurs :
|
|
Rectangle {
|
|
Layout.row: 1
|
|
Layout.column: 1
|
|
width: parent.width + espace_colonnes_secondaires
|
|
height : (onglets_capteurs.visible) ? (parent.height - shipheart_hauteur_bandeau_haut - espace_onglets_batteries) : parent.height
|
|
y: (onglets_capteurs.visible) ? (shipheart_hauteur_bandeau_haut + espace_onglets_batteries) : 0
|
|
color: "transparent"
|
|
|
|
ListModel {
|
|
id: modele_capteurs
|
|
}
|
|
|
|
GridView {
|
|
id: capteurs_grid
|
|
|
|
y: 0
|
|
width: parent.width
|
|
height: parent.height
|
|
cellWidth: parent.width / nombre_colonnes_affichage_capteurs;
|
|
cellHeight: (circuits_grid.cellHeight * 2) // Garanti que tous les boutons ont la même hauteur en prenant la hauteur d'un circuit comme référénce pour la batterie
|
|
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_capteurs
|
|
delegate: Shipheart_bouton_capteur {
|
|
}
|
|
|
|
ScrollBar.vertical: ScrollBar {}
|
|
|
|
// Texte si aucun capteur n'est configuré pour cet onglet :
|
|
Label {
|
|
width: parent.width - espace_colonnes_secondaires // Le 'espace_colonnes_secondaires' permet de compenser l'augmentation de taille permettant d'annuler la perte d'un espace en fin de ligne de grille
|
|
height: parent.height
|
|
horizontalAlignment: Qt.AlignHCenter
|
|
verticalAlignment: Qt.AlignVCenter
|
|
visible: parent.count === 0
|
|
text: qsTr("Aucun capteur n'est configuré pour ce groupe...<br /><br />Si ce groupe n'a pas d'utilité, vous pouvez le supprimer dans le menu [Capteurs] des Paramètres Avancés.")
|
|
color: couleur_rouge_transparent
|
|
font.pixelSize: 15
|
|
font.bold: true
|
|
wrapMode: Label.Wrap
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------
|
|
// Zone Droite :
|
|
//-------------------------------------------------------
|
|
Rectangle {
|
|
width: (shipheart_largeur_page * (1 - pourcentage_largeur_page_affichage_circuit)) - (espace_colonnes_principales / 2)
|
|
height: shipheart_hauteur_page - shipheart_hauteur_bandeau_bas - home_grid.rowSpacing;
|
|
color: "transparent"
|
|
|
|
//.................................................................................
|
|
// Réservoirs
|
|
//.................................................................................
|
|
Rectangle {
|
|
id: zone_reservoirs
|
|
|
|
width: parent.width
|
|
height: (parent.height * pourcentage_hauteur_zone_haut_vs_bas) - (espace_lignes_principales / 2)
|
|
color: "transparent"
|
|
|
|
//-----------------------------------------------------------
|
|
// Onglets :
|
|
Rectangle {
|
|
id: onglets_reservoirs
|
|
|
|
width: parent.width
|
|
height: shipheart_hauteur_bandeau_haut
|
|
color: "transparent"
|
|
visible: (modele_onglets_reservoirs.count > 1) ? true : false
|
|
|
|
ListModel {
|
|
id: modele_onglets_reservoirs
|
|
}
|
|
|
|
GridView {
|
|
id: grille_onglets_reservoirs
|
|
|
|
x: largeur_bouton_suite + espace_bouton_suite
|
|
y: -deport_haut_masquage_onglets
|
|
width: parent.width - (2 * (largeur_bouton_suite + espace_bouton_suite))
|
|
height: parent.height + deport_haut_masquage_onglets
|
|
cellWidth: width / ((modele_onglets_reservoirs.count > 0) ? Math.min(modele_onglets_reservoirs.count, 3) : 1)
|
|
cellHeight: shipheart_hauteur_bandeau_haut + deport_haut_masquage_onglets
|
|
|
|
highlightRangeMode: GridView.NoHighlightRange
|
|
flow: GridView.FlowTopToBottom // Items are laid out from top to bottom, and the view scrolls horizontally
|
|
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_onglets_reservoirs
|
|
|
|
delegate: Rectangle {
|
|
width: grille_onglets_reservoirs.cellWidth - 2
|
|
height: grille_onglets_reservoirs.cellHeight
|
|
radius: 20
|
|
color: model.actif ? shipheart_couleur_fond_bouton_actif : shipheart_couleur_fond_bouton
|
|
|
|
Text {
|
|
text: model.libelle
|
|
font.pixelSize: 14
|
|
font.bold: model.actif
|
|
opacity: model.actif ? 1.0 : 0.8
|
|
color: couleur_blanc_casse
|
|
anchors.fill: parent
|
|
horizontalAlignment: Text.AlignHCenter
|
|
verticalAlignment: Text.AlignVCenter
|
|
topPadding: deport_haut_masquage_onglets
|
|
wrapMode: Text.WordWrap
|
|
}
|
|
Image {
|
|
source: (model.etat === 1) ? "/images/coin_bas_droite_orange.png" : "/images/coin_bas_droite_rouge.png"
|
|
sourceSize.height: 20
|
|
anchors {
|
|
bottom: parent.bottom
|
|
right: parent.right
|
|
}
|
|
visible: model.etat !== 0
|
|
}
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
onClicked: {
|
|
shipheart_clic();
|
|
id_groupe_reservoirs = model.id;
|
|
init_reservoirs();
|
|
}
|
|
}
|
|
}
|
|
ScrollBar.vertical: ScrollBar {}
|
|
} // Fin de Gridview des onglets
|
|
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// Boutons de réservoirs :
|
|
Rectangle {
|
|
Layout.row: 1
|
|
Layout.column: 1
|
|
width: parent.width + espace_colonnes_secondaires
|
|
height : (onglets_reservoirs.visible) ? (parent.height - shipheart_hauteur_bandeau_haut - espace_onglets_batteries) : parent.height
|
|
y: (onglets_reservoirs.visible) ? (shipheart_hauteur_bandeau_haut + espace_onglets_batteries) : 0
|
|
|
|
color: "transparent"
|
|
|
|
ListModel {
|
|
id: modele_reservoirs
|
|
}
|
|
|
|
GridView {
|
|
id: reservoirs_grid
|
|
|
|
width: parent.width
|
|
height: parent.height
|
|
cellWidth: parent.width;
|
|
cellHeight: circuits_grid.cellHeight // Garanti que tous les boutons ont la même hauteur en prenant la hauteur d'un circuit comme référénce pour le réservoir
|
|
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_reservoirs
|
|
delegate: Shipheart_bouton_reservoir {
|
|
}
|
|
|
|
ScrollBar.vertical: ScrollBar {}
|
|
|
|
// Texte si aucun réservoir n'est configuré sur cet onglet :
|
|
Label {
|
|
width: parent.width - espace_colonnes_secondaires // Le 'espace_colonnes_secondaires' permet e compenser l'augmentation de taille permettant d'annuler la perte d'un espace en fin de ligne de grille
|
|
height: parent.height
|
|
horizontalAlignment: Qt.AlignHCenter
|
|
verticalAlignment: Qt.AlignVCenter
|
|
visible: parent.count === 0
|
|
text: qsTr("Aucun réservoir n'est configuré pour ce groupe...<br /><br />Si ce groupe n'a pas d'utilité, vous pouvez le supprimer dans le menu [Réservoirs] des Paramètres Avancés.")
|
|
color: couleur_rouge_transparent
|
|
font.pixelSize: 15
|
|
font.bold: true
|
|
wrapMode: Label.Wrap
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//.................................................................................
|
|
// Batteries
|
|
//.................................................................................
|
|
Rectangle {
|
|
id: zone_batteries
|
|
|
|
y: zone_reservoirs.height + espace_lignes_principales
|
|
width: parent.width
|
|
height: (parent.height * (1 - pourcentage_hauteur_zone_haut_vs_bas)) - (espace_lignes_principales / 2)
|
|
color: "transparent"
|
|
|
|
//-----------------------------------------------------------
|
|
// Onglets :
|
|
Rectangle {
|
|
id: onglets_batteries
|
|
|
|
width: parent.width
|
|
height: shipheart_hauteur_bandeau_haut
|
|
color: "transparent"
|
|
visible: (modele_onglets_batteries.count > 1) ? true : false
|
|
clip: true // Permet de limiter l'affichage des éléments enfants à ce rectangle (utile pour la partie haute des onglets à masquer...)
|
|
|
|
ListModel {
|
|
id: modele_onglets_batteries
|
|
}
|
|
|
|
GridView {
|
|
id: grille_onglets_batteries
|
|
|
|
x: largeur_bouton_suite + espace_bouton_suite
|
|
y: -deport_haut_masquage_onglets
|
|
width: parent.width - (2 * (largeur_bouton_suite + espace_bouton_suite))
|
|
height: parent.height + deport_haut_masquage_onglets
|
|
cellWidth: width / ((modele_onglets_batteries.count > 0) ? Math.min(modele_onglets_batteries.count, 3) : 1)
|
|
cellHeight: shipheart_hauteur_bandeau_haut + deport_haut_masquage_onglets
|
|
|
|
highlightRangeMode: GridView.NoHighlightRange
|
|
flow: GridView.FlowTopToBottom // Items are laid out from top to bottom, and the view scrolls horizontally
|
|
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_onglets_batteries
|
|
|
|
delegate: Rectangle {
|
|
width: grille_onglets_batteries.cellWidth - 2
|
|
height: grille_onglets_batteries.cellHeight
|
|
radius: 20
|
|
color: model.actif ? shipheart_couleur_fond_bouton_actif : shipheart_couleur_fond_bouton
|
|
|
|
Text {
|
|
text: model.libelle
|
|
font.pixelSize: 14
|
|
font.bold: model.actif
|
|
opacity: model.actif ? 1.0 : 0.8
|
|
color: couleur_blanc_casse
|
|
anchors.fill: parent
|
|
horizontalAlignment: Text.AlignHCenter
|
|
verticalAlignment: Text.AlignVCenter
|
|
topPadding: deport_haut_masquage_onglets
|
|
wrapMode: Text.WordWrap
|
|
}
|
|
Image {
|
|
source: (model.etat === 1) ? "/images/coin_bas_droite_orange.png" : "/images/coin_bas_droite_rouge.png"
|
|
sourceSize.height: 20
|
|
anchors {
|
|
bottom: parent.bottom
|
|
right: parent.right
|
|
}
|
|
visible: model.etat !== 0
|
|
}
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
onClicked: {
|
|
shipheart_clic();
|
|
id_groupe_batteries = model.id;
|
|
init_batteries();
|
|
}
|
|
}
|
|
}
|
|
ScrollBar.vertical: ScrollBar {}
|
|
} // Fin de Gridview des onglets
|
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------
|
|
// Boutons de batteries :
|
|
Rectangle {
|
|
Layout.row: 1
|
|
Layout.column: 1
|
|
width: parent.width + espace_colonnes_secondaires
|
|
height : (onglets_batteries.visible) ? (parent.height - shipheart_hauteur_bandeau_haut - espace_onglets_batteries) : parent.height
|
|
y: (onglets_batteries.visible) ? (shipheart_hauteur_bandeau_haut + espace_onglets_batteries) : 0
|
|
color: "transparent"
|
|
|
|
ListModel {
|
|
id: modele_batteries
|
|
}
|
|
|
|
GridView {
|
|
id: batteries_grid
|
|
|
|
y: 0
|
|
width: parent.width
|
|
height: parent.height
|
|
cellWidth: parent.width;
|
|
cellHeight: circuits_grid.cellHeight // Garanti que tous les boutons ont la même hauteur en prenant la hauteur d'un circuit comme référénce pour la batterie
|
|
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_batteries
|
|
delegate: Shipheart_bouton_batterie {
|
|
}
|
|
|
|
ScrollBar.vertical: ScrollBar {}
|
|
|
|
// Texte si aucune batterie n'est configurée pour cet onglet :
|
|
Label {
|
|
width: parent.width - espace_colonnes_secondaires // Le 'espace_colonnes_secondaires' permet e compenser l'augmentation de taille permettant d'annuler la perte d'un espace en fin de ligne de grille
|
|
height: parent.height
|
|
horizontalAlignment: Qt.AlignHCenter
|
|
verticalAlignment: Qt.AlignVCenter
|
|
visible: parent.count === 0
|
|
text: qsTr("Aucun parc de batterie n'est configuré pour ce groupe...<br /><br />Si ce groupe n'a pas d'utilité, vous pouvez le supprimer dans le menu [Batteries] des Paramètres Avancés.")
|
|
color: couleur_rouge_transparent
|
|
font.pixelSize: 15
|
|
font.bold: true
|
|
wrapMode: Label.Wrap
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------
|
|
// Bandeau bas :
|
|
//-------------------------------------------------------
|
|
Rectangle {
|
|
Layout.columnSpan: 2 // Regroupe les deux colonnes principales (circuits/capteurs à gauche et réservoirs/batteries à droite)
|
|
|
|
width: shipheart_largeur_page;
|
|
height: shipheart_hauteur_bandeau_bas;
|
|
color: "transparent"
|
|
|
|
|
|
//.................................................
|
|
// Zone d'état des connexions
|
|
//.................................................
|
|
Rectangle {
|
|
id: bandeau_bas_zone_status_connexions
|
|
|
|
width: bandeau_bas_largeur_zone_status_connexions;
|
|
height: shipheart_hauteur_bandeau_bas
|
|
radius: shipheart_rayon_bouton
|
|
color: shipheart_couleur_fond_bouton
|
|
|
|
Image {
|
|
source: image_etat_connexion_1
|
|
sourceSize.height: parent.height * 0.35;
|
|
sourceSize.width: bandeau_bas_largeur_zone_status_connexions
|
|
anchors.top: parent.top
|
|
anchors.topMargin: 10
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: (shipheart_generation_shipbase < shipheart_generation_shipbase_v2) ? (parent.width - width)/2 : 0
|
|
}
|
|
Image {
|
|
source: image_etat_connexion_2
|
|
sourceSize.height: parent.height * 0.3;
|
|
sourceSize.width: bandeau_bas_largeur_zone_status_connexions
|
|
anchors.bottom: parent.bottom
|
|
anchors.bottomMargin: 10
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: (shipheart_generation_shipbase < shipheart_generation_shipbase_v2) ? (parent.width - width)/2 : 0
|
|
}
|
|
Image {
|
|
source: image_etat_connexion_3
|
|
sourceSize.height: parent.height * 0.35;
|
|
sourceSize.width: bandeau_bas_largeur_zone_status_connexions
|
|
anchors.top: parent.top
|
|
anchors.topMargin: 10
|
|
anchors.right: parent.right
|
|
}
|
|
Image {
|
|
source: image_etat_connexion_4
|
|
sourceSize.height: parent.height * 0.3;
|
|
sourceSize.width: bandeau_bas_largeur_zone_status_connexions
|
|
anchors.bottom: parent.bottom
|
|
anchors.bottomMargin: 10
|
|
anchors.right: parent.right
|
|
}
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
onClicked: {
|
|
shipheart_clic();
|
|
boite_information_reseaux.message = maj_message_reseaux();
|
|
boite_information_reseaux.open();
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// Onglets :
|
|
Rectangle {
|
|
id: onglets_pages
|
|
|
|
x: bandeau_bas_zone_status_connexions.width + bandeau_bas_spacing
|
|
width: bandeau_bas_largeur_zone_pages
|
|
height: shipheart_hauteur_bandeau_bas
|
|
color: "transparent"
|
|
|
|
ListModel {
|
|
id: modele_onglets_pages
|
|
}
|
|
|
|
GridView {
|
|
id: grille_onglets_pages
|
|
|
|
property int index_base_en_cours: 0 // Utilsé pour stocker l'index du premier widget affiché à gauche
|
|
|
|
x: largeur_bouton_suite + espace_bouton_suite
|
|
width: parent.width - (2 * (largeur_bouton_suite + espace_bouton_suite))
|
|
height: parent.height
|
|
cellWidth: width / ((modele_onglets_pages.count > 0) ? Math.min(modele_onglets_pages.count, 5) : 1)
|
|
cellHeight: height
|
|
|
|
highlightRangeMode: flag_fleches_suite_onglets
|
|
? GridView.StrictlyEnforceRange // Nécessaire pour que 'index_base_en_cours' soit mis à jour. Au passage, autorise de faire défiler les widgets jusqu'à ne garder que le dernier visible (pas génant et même plutôt sympa...)
|
|
: GridView.NoHighlightRange
|
|
flow: GridView.FlowTopToBottom // Items are laid out from top to bottom, and the view scrolls horizontally
|
|
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_onglets_pages
|
|
|
|
onMovementEnded: {
|
|
index_base_en_cours = currentIndex; // Capte la valeur de currentIndex aà la fin du mouvement (la valeur vaut alors l'index du widget le plus à gauche). Si on ne le capte pas, la valeur de CurrentIndex repasse à 0 après l'arrêt du flicker (pourquoi...???)
|
|
}
|
|
|
|
delegate: Rectangle {
|
|
x: 5
|
|
width: grille_onglets_pages.cellWidth - 5
|
|
height: grille_onglets_pages.cellHeight
|
|
radius: shipheart_rayon_bouton
|
|
color: model.actif ? shipheart_couleur_fond_bouton_actif : shipheart_couleur_fond_bouton
|
|
|
|
//==================================================
|
|
// Ephéméride :
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
color: "transparent"
|
|
visible: model.type === shipheart_type_page_preconfiguree_ephemeride
|
|
|
|
Text {
|
|
id: texte_date
|
|
text: date_courante
|
|
textFormat: Text.RichText // Autorise la prise en compte de <sup> par exemple...
|
|
anchors {
|
|
top: parent.top
|
|
topMargin: onglet_page_top_margin_texte_haut
|
|
horizontalCenter: parent.horizontalCenter
|
|
}
|
|
font.pixelSize: 15
|
|
color: couleur_blanc_casse
|
|
}
|
|
Text {
|
|
id: texte_heure
|
|
text: heure_courante
|
|
anchors {
|
|
bottom: parent.bottom
|
|
bottomMargin: onglet_page_bottom_margin_texte_bas
|
|
horizontalCenter: parent.horizontalCenter
|
|
}
|
|
font.pixelSize: 18
|
|
font.weight: Font.Bold
|
|
color: couleur_blanc_casse
|
|
}
|
|
|
|
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_date_heure
|
|
anchors.fill: parent
|
|
onClicked: {
|
|
shipheart_clic();
|
|
stackView.push("ephemeride.qml")
|
|
}
|
|
}
|
|
}
|
|
|
|
//==================================================
|
|
// Chronomètre :
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
color: "transparent"
|
|
visible: model.type === shipheart_type_page_preconfiguree_chronometre
|
|
|
|
Image {
|
|
source: "/images/chronometre.png"
|
|
sourceSize.height: 25
|
|
anchors {
|
|
top: parent.top
|
|
topMargin: onglet_page_top_margin_texte_haut
|
|
horizontalCenter: parent.horizontalCenter
|
|
}
|
|
}
|
|
Text {
|
|
text: Math.trunc(compteur_chrono / (60 * 60 * 10)).toString().padStart(2, '0') + ":" + Math.trunc((compteur_chrono / (60 * 10)) % 60).toString().padStart(2, '0') + ":" + Math.trunc((compteur_chrono / 10) % 60).toString().padStart(2, '0') + "," + (compteur_chrono % 10)
|
|
anchors {
|
|
bottom: parent.bottom
|
|
bottomMargin: onglet_page_bottom_margin_texte_bas
|
|
horizontalCenter: parent.horizontalCenter
|
|
}
|
|
horizontalAlignment: Text.AlignHCenter
|
|
font.pixelSize: 18
|
|
font.weight: Font.Bold
|
|
color: couleur_blanc_casse
|
|
visible: (compteur_chrono !== 0)
|
|
}
|
|
|
|
Rectangle { // Barre grandissante pour montrer durée d'appui vs tempo nécessaire :
|
|
width: (valeur_timer_appui_long / shipheart_mouse_press_and_hold_interval_tres_long) * parent.width
|
|
height: parent.height
|
|
color: couleur_rouge_transparent
|
|
radius: shipheart_rayon_bouton
|
|
visible: (mouse_area_chrono.pressed)
|
|
&& ((valeur_timer_appui_long / shipheart_mouse_press_and_hold_interval_tres_long) > 0.05) // Permet de ne pas commencer à afficher la barre défilante dans le cas d'un appui simple
|
|
}
|
|
|
|
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_chrono
|
|
anchors.fill: parent
|
|
onClicked: {
|
|
shipheart_clic();
|
|
if (timer_chrono.running) timer_chrono.stop();
|
|
else timer_chrono.start();
|
|
|
|
timer_appui_long.running = false;
|
|
valeur_timer_appui_long = 0;
|
|
}
|
|
// Attention : la ligne suivante est nécessaire pour que dès que l'appui est supérieur au délai
|
|
// d'appui long (500ms en standard), le 'onClicked' ne soit PAS déclenché. Utile notamment lors
|
|
// d'un appui long "incomplet" qui ne RAZ pas le compteur mais qui ne relance pas non plus le comptage...
|
|
onPressAndHold: {
|
|
if (timer_chrono.running)
|
|
{
|
|
boite_dialogue_affichage_duree.type = "chrono";
|
|
boite_dialogue_affichage_duree.open();
|
|
}
|
|
}
|
|
onPressed: {
|
|
shipheart_clic();
|
|
if (!timer_chrono.running) // On n'enclenche pas un appui long si le compteur tourne (il faut d'abord l'arrêter avant de le RAZ)
|
|
{
|
|
timer_appui_long.running = true;
|
|
valeur_timer_appui_long = 0;
|
|
flag_mouse_area_chrono_pressed = true;
|
|
}
|
|
}
|
|
onExited: {
|
|
timer_appui_long.running = false;
|
|
valeur_timer_appui_long = 0;
|
|
flag_mouse_area_chrono_pressed = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
//==================================================
|
|
// Minuteur :
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
color: "transparent"
|
|
visible: model.type === shipheart_type_page_personnalisee_minuteur
|
|
|
|
Image {
|
|
source: "/images/sablier.png"
|
|
sourceSize.height: 25
|
|
anchors {
|
|
top: parent.top
|
|
topMargin: onglet_page_top_margin_texte_haut
|
|
horizontalCenter: parent.horizontalCenter
|
|
}
|
|
}
|
|
Text {
|
|
text: Math.trunc(compteur_minuteur / (60 * 60)).toString().padStart(2, '0') + ":" + Math.trunc((compteur_minuteur / 60) % 60).toString().padStart(2, '0') + ":" + Math.trunc(compteur_minuteur % 60).toString().padStart(2, '0')
|
|
anchors {
|
|
bottom: parent.bottom
|
|
bottomMargin: onglet_page_bottom_margin_texte_bas
|
|
horizontalCenter: parent.horizontalCenter
|
|
}
|
|
horizontalAlignment: Text.AlignHCenter
|
|
font.pixelSize: 18
|
|
font.weight: Font.Bold
|
|
color: couleur_blanc_casse
|
|
visible: (compteur_minuteur !== 0)
|
|
}
|
|
|
|
Rectangle { // Barre grandissante pour montrer durée d'appui vs tempo nécessaire :
|
|
width: (valeur_timer_appui_long / shipheart_mouse_press_and_hold_interval_tres_long) * parent.width
|
|
height: parent.height
|
|
color: couleur_rouge_transparent
|
|
radius: shipheart_rayon_bouton
|
|
visible: (mouse_area_minuteur.pressed)
|
|
&& ((valeur_timer_appui_long / shipheart_mouse_press_and_hold_interval_tres_long) > 0.05) // Permet de ne pas commencer à afficher la barre défilante dans le cas d'un appui simple
|
|
}
|
|
|
|
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_minuteur
|
|
anchors.fill: parent
|
|
onClicked: {
|
|
shipheart_clic();
|
|
if (etat_minuteur === 0)
|
|
{
|
|
boite_dialogue_minuteur.valeur_tumbler_heure = 0;
|
|
boite_dialogue_minuteur.valeur_tumbler_minute = 3;
|
|
boite_dialogue_minuteur.valeur_tumbler_seconde = 0
|
|
boite_dialogue_minuteur.open();
|
|
}
|
|
else
|
|
{
|
|
if (timer_minuteur.running) timer_minuteur.stop();
|
|
else timer_minuteur.start();
|
|
|
|
timer_appui_long.running = false;
|
|
valeur_timer_appui_long = 0;
|
|
}
|
|
}
|
|
// Attention : la ligne suivante est nécessaire pour que dès que l'appui est supérieur au délai
|
|
// d'appui long (500ms en standard), le 'onClicked' ne soit PAS déclenché. Utile notamment lors
|
|
// d'un appui long "incomplet" qui ne RAZ pas le compteur mais qui ne relance pas non plus le comptage...
|
|
onPressAndHold: {
|
|
if (timer_minuteur.running)
|
|
{
|
|
boite_dialogue_affichage_duree.type = "minuteur";
|
|
boite_dialogue_affichage_duree.open();
|
|
}
|
|
}
|
|
onPressed: {
|
|
shipheart_clic();
|
|
if (!timer_minuteur.running) // On n'enclenche pas un appui long si le compteur tourne (il faut d'abord l'arrêter avant de le RAZ)
|
|
{
|
|
timer_appui_long.running = true;
|
|
valeur_timer_appui_long = 0;
|
|
flag_mouse_area_minuteur_pressed = true;
|
|
}
|
|
}
|
|
onExited: {
|
|
timer_appui_long.running = false;
|
|
valeur_timer_appui_long = 0;
|
|
flag_mouse_area_minuteur_pressed = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
//==================================================
|
|
// Réveil :
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
color: "transparent"
|
|
visible: model.type === shipheart_type_page_preconfiguree_reveil
|
|
|
|
Image {
|
|
source: "/images/reveil.png"
|
|
sourceSize.height: 25
|
|
anchors {
|
|
top: parent.top
|
|
topMargin: onglet_page_top_margin_texte_haut
|
|
horizontalCenter: parent.horizontalCenter
|
|
}
|
|
}
|
|
Text {
|
|
text: Fonctions_date_heure.nom_jour_semaine(reveils_next_jour) + " " + Fonctions.format_deux_digits(reveils_next_heure, '0') + ":" + Fonctions.format_deux_digits(reveils_next_minute, '0')
|
|
anchors {
|
|
bottom: parent.bottom
|
|
bottomMargin: onglet_page_bottom_margin_texte_bas
|
|
horizontalCenter: parent.horizontalCenter
|
|
}
|
|
horizontalAlignment: Text.AlignHCenter
|
|
font.pixelSize: 15
|
|
color: couleur_blanc_casse
|
|
visible: (reveils_next_jour !== 0)
|
|
}
|
|
|
|
MouseArea {
|
|
id: mouse_area_reveils
|
|
anchors.fill: parent
|
|
onClicked: {
|
|
shipheart_clic();
|
|
boite_dialogue_reveil.open();
|
|
}
|
|
}
|
|
}
|
|
|
|
//==================================================
|
|
// Page personnalisée :
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
color: "transparent"
|
|
visible: (model.type === shipheart_type_page_personnalisee_non_masquable)
|
|
|| (model.type === shipheart_type_page_personnalisee_masquable)
|
|
|
|
Text {
|
|
text: model.libelle
|
|
font.pixelSize: 15
|
|
font.weight: Font.Bold
|
|
color: couleur_blanc_casse
|
|
anchors.fill: parent
|
|
horizontalAlignment: Text.AlignHCenter
|
|
verticalAlignment: Text.AlignVCenter
|
|
wrapMode: Text.WordWrap
|
|
// elide: Text.ElideRight
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
onClicked: {
|
|
shipheart_clic();
|
|
stackView.push("page_personnalisee.qml", {"id_page": model.id })
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//==================================================
|
|
// Toutes les pages :
|
|
Image {
|
|
source: (model.etat === 1) ? "/images/coin_bas_droite_orange.png" : "/images/coin_bas_droite_rouge.png"
|
|
sourceSize.height: 20
|
|
anchors {
|
|
bottom: parent.bottom
|
|
right: parent.right
|
|
}
|
|
visible: model.etat !== 0
|
|
}
|
|
|
|
}
|
|
ScrollBar.vertical: ScrollBar {}
|
|
} // Fin de Gridview des onglets
|
|
|
|
// Flèche de suite gauche :
|
|
Image {
|
|
anchors {
|
|
bottom: grille_onglets_pages.bottom
|
|
right: grille_onglets_pages.left
|
|
rightMargin: espace_bouton_suite
|
|
}
|
|
source: "/images/fleche_suite_gauche_sombre.png"
|
|
width: largeur_bouton_suite
|
|
height: grille_onglets_pages.height
|
|
opacity: 0.5
|
|
visible: (!grille_onglets_pages.moving) // Permet de ne pas afficher la flèche pendant le mouvement (surtout génant à cause du lag généré par la fin du mouvement qui est assez lent).
|
|
&& (grille_onglets_pages.index_base_en_cours > 0)
|
|
&& flag_fleches_suite_onglets
|
|
}
|
|
|
|
// Flèche de suite droite :
|
|
Image {
|
|
anchors {
|
|
bottom: grille_onglets_pages.bottom
|
|
left: grille_onglets_pages.right
|
|
leftMargin: espace_bouton_suite
|
|
}
|
|
source: "/images/fleche_suite_droite_sombre.png"
|
|
width: largeur_bouton_suite
|
|
height: grille_onglets_pages.height
|
|
opacity: 0.5
|
|
visible: (!grille_onglets_pages.moving) // Permet de ne pas afficher la flèche pendant le mouvement (surtout génant à cause du lag généré par la fin du mouvement qui est assez lent).
|
|
&& ((grille_onglets_pages.count - grille_onglets_pages.index_base_en_cours) > (modele_onglets_pages.count * (grille_onglets_pages.height / grille_onglets_pages.cellHeight))) // le calcul 'height/cellheight' donne le nombre de lignes de widget (généralement, 1 ou 2)
|
|
&& flag_fleches_suite_onglets
|
|
}
|
|
}
|
|
|
|
//.................................................
|
|
// Paramètres
|
|
//.................................................
|
|
Rectangle {
|
|
id: bandeau_bas_zone_parametres
|
|
|
|
x: onglets_pages.x + onglets_pages.width // On ne rajoute pas le 'bandeau_bas_spacing' car les boutons dans la grille n'étant pas centrés, on ajouterait 2 espaces avant ce bouton
|
|
width: bandeau_bas_largeur_zone_parametres;
|
|
height: shipheart_hauteur_bandeau_bas
|
|
radius: shipheart_rayon_bouton
|
|
color: shipheart_couleur_fond_bouton
|
|
|
|
Text {
|
|
id: texte_parametres
|
|
text: shipheart_code_pays
|
|
anchors {
|
|
top: parent.top
|
|
topMargin: onglet_page_top_margin_texte_haut
|
|
horizontalCenter: parent.horizontalCenter
|
|
}
|
|
font.pixelSize: 18
|
|
font.weight: Font.Bold
|
|
color: couleur_gris_tres_pale
|
|
}
|
|
|
|
Image {
|
|
id: image_parametres
|
|
source: "/images/icone_parametres.png"
|
|
sourceSize.height: 25
|
|
anchors {
|
|
bottom: parent.bottom
|
|
bottomMargin: onglet_page_bottom_margin_texte_bas
|
|
horizontalCenter: parent.horizontalCenter
|
|
}
|
|
}
|
|
Image {
|
|
id: image_alarme_paramètres // Affichage du coin inférieur-droit en rouge si une erreur de paramètres est détectée
|
|
source: "/images/coin_bas_droite_rouge.png"
|
|
sourceSize.height: 20
|
|
anchors {
|
|
bottom: parent.bottom
|
|
right: parent.right
|
|
}
|
|
visible: shipheart_defaut_config_k_bus
|
|
}
|
|
Image {
|
|
id: image_info_paramètres // Affichage du coin inférieur-droit en bleu si une nouvelle version est dispo
|
|
source: "/images/coin_bas_droite_bleu_koriolan.png"
|
|
sourceSize.height: 20
|
|
anchors {
|
|
bottom: parent.bottom
|
|
right: parent.right
|
|
}
|
|
visible: !image_alarme_paramètres.visible &&
|
|
((shipheart_fichier_a_charger !== "") || (shipheart_fichier_a_valider !== ""))
|
|
}
|
|
|
|
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_parametres
|
|
anchors.fill: parent
|
|
onClicked: {
|
|
shipheart_clic();
|
|
stackView.push("parametres.qml")
|
|
}
|
|
pressAndHoldInterval: shipheart_mouse_press_and_hold_interval_tres_long
|
|
onPressAndHold: {
|
|
stackView.pop();
|
|
}
|
|
}
|
|
}
|
|
|
|
} // Fin de bandeau bas
|
|
} // Fin de grille principale
|
|
|
|
//-------------------------------------------------------
|
|
// Boite en travaux :
|
|
//-------------------------------------------------------
|
|
Shipheart_boite_dialogue {
|
|
id: boite_information_en_travaux
|
|
niveau: 0
|
|
imageTitreSource: "/images/cone_chantier.png";
|
|
message: qsTr("Cette page est actuellement en travaux. <br />Elle sera rendue disponible très rapidement à travers une mise à jour.<br /><br />Merci de votre patience...<br /><br />L'équipe ShipHeart")
|
|
}
|
|
|
|
//-------------------------------------------------------
|
|
// Réseaux :
|
|
//-------------------------------------------------------
|
|
Shipheart_boite_dialogue {
|
|
id: boite_information_reseaux
|
|
niveau: 0
|
|
imageTitreSource: "/images/satellite.png";
|
|
}
|
|
|
|
//-------------------------------------------------------
|
|
// Messages Users :
|
|
//-------------------------------------------------------
|
|
Shipheart_boite_dialogue {
|
|
id: boite_message_user
|
|
onClicked: {
|
|
acquittement_message_users(bouton);
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------
|
|
// Boite de chargement du minuteur :
|
|
//-------------------------------------------------------
|
|
Shipheart_boite_dialogue_minuteur {
|
|
id: boite_dialogue_minuteur
|
|
onClicked: {
|
|
//console.log("Le Bouton [" + bouton + "] est appuyé");
|
|
if (bouton === shipheart_boite_dialogue_bouton_1)
|
|
{
|
|
compteur_minuteur = (heure * 60 * 60) + (minute * 60) + seconde
|
|
if (compteur_minuteur !== 0) // Si la valeur sélectionnée est nulle, on ne lancer rien....
|
|
{
|
|
etat_minuteur = 1;
|
|
compteur_initial_minuteur = compteur_minuteur;
|
|
timer_minuteur.start();
|
|
}
|
|
}
|
|
boite_dialogue_minuteur.close(); // Dans tous les cas... (notamment si ANNULER)
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------
|
|
// Boite de dialogues concernant les réveils :
|
|
//-------------------------------------------------------
|
|
Shipheart_boite_dialogue_reveils {
|
|
id: boite_dialogue_reveil
|
|
|
|
onClicked: {
|
|
//console.log("Le Bouton [" + bouton + "] est appuyé");
|
|
if (bouton === shipheart_boite_dialogue_bouton_1)
|
|
{
|
|
check_reveils();
|
|
}
|
|
boite_dialogue_reveil.close(); // Tous le traitement est fait dans la boite de dialogue...
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------
|
|
// Boite d'affichage d'une durée :
|
|
// Utilisée pour chrono et minuteur
|
|
//-------------------------------------------------------
|
|
Shipheart_boite_dialogue_affichage_duree {
|
|
id: boite_dialogue_affichage_duree
|
|
|
|
onClicked: {
|
|
boite_dialogue_affichage_duree.close();
|
|
}
|
|
}
|
|
|
|
|
|
//===========================================================
|
|
// Economiseur : Doit être placé en fin de page pour fonctionner
|
|
//===========================================================
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
preventStealing: true // Permet que cela fonctionne même si un élément flickable (notamment) soit derrière et "vole" le click
|
|
enabled: flag_economiseur_actif
|
|
onClicked: {
|
|
shipheart_clic();
|
|
mise_en_veille(0);
|
|
}
|
|
}
|
|
|
|
|
|
//=================================================================================================
|
|
// Fonction : Traite les tâches à effectuer à l'ouverture de la page
|
|
//=================================================================================================
|
|
function init_page()
|
|
{
|
|
var req, res;
|
|
|
|
|
|
console.log("shipheart_type_installation = "+ shipheart_type_installation)
|
|
|
|
// Paramètres dépendant du type d'installation :
|
|
switch (shipheart_type_installation)
|
|
{
|
|
//---------------------------------------------------------------------------
|
|
case shipheart_type_installation_ecran_deporte_7_pouces:
|
|
nombre_colonnes_affichage_circuits = 1
|
|
nombre_circuits_affiches_sur_une_colonne = 3
|
|
break;
|
|
|
|
//---------------------------------------------------------------------------
|
|
case shipheart_type_installation_ecran_deporte_10_pouces:
|
|
nombre_colonnes_affichage_circuits = 2
|
|
nombre_circuits_affiches_sur_une_colonne = 4
|
|
break;
|
|
|
|
//---------------------------------------------------------------------------
|
|
case shipheart_type_installation_ecran_deporte_22_pouces:
|
|
nombre_colonnes_affichage_circuits = 3
|
|
nombre_circuits_affiches_sur_une_colonne = 6
|
|
break;
|
|
|
|
//---------------------------------------------------------------------------
|
|
default: // Dans ce cas, ce sont les valeurs par défaut qui sont conservées.
|
|
case shipheart_type_installation_shipbase:
|
|
break;
|
|
}
|
|
|
|
console.log("Version en cours d'utilisation = " + AppInfo.version)
|
|
|
|
// Mise à jour de la version de l'Application QT dans la BDD :
|
|
req = 'UPDATE TB_Systeme SET Valeur="' + AppInfo.version + '" WHERE Nom="Version_soft_application_qt" ';
|
|
bdd.requete_unique(req);
|
|
|
|
// Récupération de la langue en cours d'utilisation :
|
|
req = 'SELECT Valeur FROM TB_Configuration WHERE Nom="Langue" ';
|
|
res = bdd.requete_unique(req);
|
|
shipheart_langue = Number(res[0]);
|
|
|
|
// Et changement de langue si celle demandée n'est pas le FR (démarrage par défaut) :
|
|
shipheart_code_pays = Fonctions_localisation.code_pays(shipheart_langue);
|
|
shipheart_code_langue = Fonctions_localisation.code_langue(shipheart_langue); // Utilisé pour les 'toLocaleDateString' par exemple
|
|
backend.change_langue(shipheart_code_langue);
|
|
|
|
// Récupération du fuseau horaire en cours :
|
|
req = 'SELECT Valeur FROM TB_Configuration WHERE Nom="Fuseau_horaire" ';
|
|
res = bdd.requete_unique(req);
|
|
shipheart_fuseau_horaire = Number(res[0]);
|
|
|
|
// Récupération de l'indicateur d'heure d'été :
|
|
req = 'SELECT Valeur FROM TB_Configuration WHERE Nom="Heure_ete" ';
|
|
res = bdd.requete_unique(req);
|
|
shipheart_heure_ete = Number(res[0]);
|
|
|
|
// Récupération de l'unité de volumes à utiliser :
|
|
req = 'SELECT Valeur FROM TB_Configuration WHERE Nom="Unite_volume" ';
|
|
res = bdd.requete_unique(req);
|
|
shipheart_unite_volume = Number(res[0]);
|
|
shipheart_unite_volume_symbole = Fonctions_localisation.symbole_unite_volume(shipheart_unite_volume);
|
|
|
|
// Récupération de l'unité de températures à utiliser :
|
|
req = 'SELECT Valeur FROM TB_Configuration WHERE Nom="Unite_temperature" ';
|
|
res = bdd.requete_unique(req);
|
|
shipheart_unite_temperature = Number(res[0]);
|
|
shipheart_unite_temperature_symbole = Fonctions_localisation.symbole_unite_temperature(shipheart_unite_temperature);
|
|
|
|
// Récupération de la période d'obsolescence des capteurs NMEA :
|
|
req = 'SELECT Valeur FROM TB_Configuration WHERE Nom="Periode_obsolescence_capteur_nmea" ';
|
|
res = bdd.requete_unique(req);
|
|
shipheart_periode_obsolescence_capteur_nmea = Number(res[0]);
|
|
|
|
// Récupération du time-out de l'économiseur :
|
|
// req = 'SELECT Valeur FROM TB_Configuration WHERE Nom LIKE="Time_out_economiseur" '; // SDIR #328
|
|
req = 'SELECT Valeur FROM TB_Configuration WHERE Nom="Time_out_economiseur" '; // SDIR #328
|
|
res = bdd.requete_unique(req);
|
|
shipheart_time_out_economiseur = Number(res[0]);
|
|
|
|
// Récupération du paramètres de bips audio :
|
|
req = 'SELECT Valeur FROM TB_Configuration WHERE Nom="Bips" ';
|
|
res = bdd.requete_unique(req);
|
|
shipheart_bips = res[0];
|
|
|
|
// Remise à Normal de la LED enface avant :
|
|
req = "UPDATE TB_Modules_config SET New_cde='" + shipheart_commande_module_etat_systeme + "/" + shipheart_commande_module_etat_systeme_normal + "' WHERE Adresse_k_bus=0 ";
|
|
bdd.requete_unique(req);
|
|
|
|
/* // Récupération du nombre maxi de répétitions d'un message utilisateur :
|
|
req = 'SELECT Valeur FROM TB_Configuration WHERE Nom="Nb_maxi_reports_message_user" ';
|
|
res = bdd.requete_unique(req);
|
|
shipheart_message_users_max_nombre_reports = Number(res[0]);
|
|
*/
|
|
reload_economiseur(); // Permet d'avoir une première tempo. Sinon, il faudrait attendre le premier clic pour que la tempo soit chargée...
|
|
mise_en_veille(0); // Par défaut, on affiche la page au démarrage...
|
|
shipheart_niveau_home = stackView.depth - 1; // Permet de stocker le niveau de la page dans la Stackview
|
|
}
|
|
|
|
|
|
//=================================================================================================
|
|
// Fonction : Met à jour les champs utilisé dans les différents affichages de la page. Elle n'est
|
|
// appelée que lorsque aucune interction n'est en cours sur l'écran (appui en cours,
|
|
// balayage, etc...
|
|
// Impact : Environ 20ms (chaque 1s) mesuré via QML Profiler et mesure de temps d'exec. le 01/02/2022
|
|
//=================================================================================================
|
|
function mise_a_jour()
|
|
{
|
|
var req, res;
|
|
var nb;
|
|
var i;
|
|
var cde, adresse;
|
|
|
|
//console.time('mise_a_jour_protegee')
|
|
|
|
//-----------------------------------------
|
|
// Mise à jour des circuits, réservoirs et batteries :
|
|
mise_a_jour_circuits();
|
|
mise_a_jour_onglets_circuits();
|
|
mise_a_jour_reservoirs();
|
|
mise_a_jour_onglets_reservoirs();
|
|
mise_a_jour_batteries();
|
|
mise_a_jour_onglets_batteries();
|
|
mise_a_jour_capteurs();
|
|
mise_a_jour_onglets_capteurs();
|
|
|
|
//-----------------------------------------
|
|
// Etat des connexions :
|
|
//shipheart_generation_shipbase = shipheart_generation_shipbase_v1;
|
|
if (shipheart_generation_shipbase < shipheart_generation_shipbase_v2)
|
|
{
|
|
//-----------------------------------------
|
|
// Etat GNSS :
|
|
req = 'SELECT Valeur FROM TB_Systeme WHERE Nom="Etat_gnss" ';
|
|
res = bdd.requete_unique(req);
|
|
switch(Number(res[0]))
|
|
{
|
|
default:
|
|
case 0: image_etat_connexion_1 = "/images/gnss_off.png"; break;
|
|
case 1: image_etat_connexion_1 = "/images/gnss_on.png"; break;
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Etat 4G-LTE :
|
|
req = 'SELECT Valeur FROM TB_Systeme WHERE Nom="Etat_4g_lte" ';
|
|
res = bdd.requete_unique(req);
|
|
switch(Number(res[0]))
|
|
{
|
|
default:
|
|
case 0: image_etat_connexion_2 = "/images/4g_lte_off.png"; break;
|
|
case 1: image_etat_connexion_2 = "/images/4g_lte_on_1.png"; break;
|
|
case 2: image_etat_connexion_2 = "/images/4g_lte_on_2.png"; break;
|
|
case 3: image_etat_connexion_2 = "/images/4g_lte_on_3.png"; break;
|
|
case 4: image_etat_connexion_2 = "/images/4g_lte_on_4.png"; break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//-----------------------------------------
|
|
// Etat GNSS :
|
|
req = 'SELECT Valeur FROM TB_Systeme WHERE Nom="Etat_gnss" ';
|
|
res = bdd.requete_unique(req);
|
|
switch(Number(res[0]))
|
|
{
|
|
default:
|
|
case 0: image_etat_connexion_1 = "/images/gnss_off.png"; break;
|
|
case 1: image_etat_connexion_1 = "/images/gnss_on.png"; break;
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Etat Ethernet :
|
|
req = 'SELECT Valeur FROM TB_Systeme WHERE Nom="Adresse_ip_ethernet" ';
|
|
res = bdd.requete_unique(req);
|
|
if (res[0] === shipheart_adresse_ip_inconnue) image_etat_connexion_2 = "/images/ethernet_off.png";
|
|
else image_etat_connexion_2 = "/images/ethernet_on.png";
|
|
|
|
//-----------------------------------------
|
|
// Etat Wifi Sta :
|
|
req = 'SELECT Valeur FROM TB_Configuration WHERE Nom="Wifi_sta_cde" ';
|
|
res = bdd.requete_unique(req);
|
|
cde = Number(res[0]);
|
|
|
|
req = 'SELECT Valeur FROM TB_Systeme WHERE Nom="Adresse_ip_wifi_sta" ';
|
|
res = bdd.requete_unique(req);
|
|
adresse = res[0];
|
|
|
|
if ((adresse === shipheart_adresse_ip_inconnue) || (cde === 0)) image_etat_connexion_3 = "/images/wifi_sta_off.png";
|
|
else image_etat_connexion_3 = "/images/wifi_sta_on.png";
|
|
|
|
//-----------------------------------------
|
|
// Etat Wifi Ap :
|
|
req = 'SELECT Valeur FROM TB_Systeme WHERE Nom="Adresse_ip_wifi_ap" ';
|
|
res = bdd.requete_unique(req);
|
|
adresse = res[0];
|
|
|
|
req = 'SELECT Valeur FROM TB_Configuration WHERE Nom="Wifi_ap_cde" ';
|
|
res = bdd.requete_unique(req);
|
|
cde = Number(res[0]);
|
|
|
|
if ((adresse === shipheart_adresse_ip_inconnue) || (cde === 0)) image_etat_connexion_4 = "/images/wifi_ap_off.png";
|
|
else image_etat_connexion_4 = "/images/wifi_ap_on.png";
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Etat config K-bus :
|
|
req = 'SELECT Valeur FROM TB_Systeme WHERE Nom="Defaut_config_k_bus" ';
|
|
res = bdd.requete_unique(req);
|
|
shipheart_defaut_config_k_bus = Number(res[0]);
|
|
|
|
//-----------------------------------------
|
|
if (message_users_code === shipheart_message_users_code_aucun) lecture_messages_users(); // On ne lit d'éventuels nouveaux messages que si aucun n'est en cour
|
|
|
|
//-----------------------------------------
|
|
// Calcul de la date et de l'heure + mise en forme
|
|
var date = Fonctions_date_heure.date_courante(null, shipheart_fuseau_horaire, shipheart_heure_ete);
|
|
var suffixe_nom_jour;
|
|
|
|
switch(shipheart_langue)
|
|
{
|
|
default:
|
|
case shipheart_langue_fr:
|
|
case shipheart_langue_es:
|
|
case shipheart_langue_pt:
|
|
case shipheart_langue_nl:
|
|
case shipheart_langue_it:
|
|
case shipheart_langue_lv:
|
|
case shipheart_langue_ca:
|
|
suffixe_nom_jour = " ";
|
|
break;
|
|
case shipheart_langue_en:
|
|
suffixe_nom_jour = ", ";
|
|
break;
|
|
case shipheart_langue_de:
|
|
suffixe_nom_jour = ", den ";
|
|
break;
|
|
}
|
|
|
|
date_courante = Fonctions_date_heure.chaine_jour_semaine(date) + suffixe_nom_jour + Fonctions_date_heure.chaine_date_longue(date, shipheart_langue)
|
|
heure_courante = Fonctions_date_heure.chaine_heure(date);
|
|
|
|
//console.timeEnd('mise_a_jour_protegee')
|
|
|
|
}
|
|
|
|
//=================================================================================================
|
|
// Fonction :
|
|
// - mise à jour de l'onglet en cours en vérifiant que l'ID en cours existe bien dans la table des familles,
|
|
// - vérifie que le modèle d'onglets a la même taille que la table des familles.
|
|
// - si Oui, mise à jour du nom et de l'état actif de chaque entrée du modèle et vérification que l'ordre du modèle égale celui de la table
|
|
// - Si Non (ou si l'ordre de la table n'est plus conforme au modèle), Raz du modèle est remplissage.
|
|
// - Création du modèle de circuits correspondant à l'onglet en cours
|
|
// NB : il n'est pas utile d'appeler la fonction 'mise_a_jour_circuits()' après car le modèle de circuits
|
|
// venant d'être créé, il est forcément à jour...
|
|
//=================================================================================================
|
|
function init_circuits()
|
|
{
|
|
var req, res;
|
|
var nb;
|
|
var i;
|
|
var actif;
|
|
|
|
|
|
// Mise à jour de l'onglet en cours :
|
|
req = 'SELECT COUNT(*) FROM TB_Familles WHERE Type_source=' + shipheart_type_source_circuits + ' AND Cle_primaire=' + id_groupe_circuits + ' ';
|
|
res = bdd.requete_unique(req);
|
|
//console.log("Requête = [ " + req + "; ]");
|
|
if (Number(res[0]) !== 1) // Si l'ID en cours n'existe pas dans la BDD (à l'init notamment mais aussi si suppression de famille par exemple)
|
|
{
|
|
req = 'SELECT Cle_primaire FROM TB_Familles WHERE Type_source=' + shipheart_type_source_circuits + ' ORDER BY Priorite_affichage LIMIT 1'; // Choix de la première famille par ordre de priorité
|
|
res = bdd.requete_unique(req);
|
|
//console.log("Requête = [ " + req + "; ]");
|
|
id_groupe_circuits = Number(res[0]);
|
|
}
|
|
|
|
// Mise à jour du modèle d'onglets :
|
|
var flag_init_onglets_necessaire = false;
|
|
req = 'SELECT Cle_primaire, Nom FROM TB_Familles WHERE Type_source=' + shipheart_type_source_circuits + ' ORDER BY Priorite_affichage '
|
|
//console.log("Requête = [" + req + "]");
|
|
nb = bdd.requete(req);
|
|
|
|
if (nb === modele_onglets_circuits.count) // Si on a supprimé ou ajouté des familles, on va devoir reconstruire le modèle d'onglets :
|
|
{
|
|
for (i = 0; i < nb; i ++)
|
|
{
|
|
res = bdd.lecture_ligne();
|
|
if (!res.isEmpty)
|
|
{
|
|
// On teste que l'ordre des familles n'a pas changé depuis la création du modèle :
|
|
if (Number(res[0]) !== modele_onglets_circuits.get(i).id)
|
|
{
|
|
flag_init_onglets_necessaire = true; // S'il a changé (ou si ajout/suppression de familles avec des clés différentes), on arrête et on demande une reconstruction complète du modèle.
|
|
break;
|
|
}
|
|
|
|
// Détection du groupe en cours :
|
|
if (id_groupe_circuits === Number(res[0])) actif = true;
|
|
else actif = false;
|
|
|
|
// Mise à jour du flag 'actif' pour chaque onglet :
|
|
modele_onglets_circuits.set(i, {"libelle": res[1], "actif": actif}); // On met à jour le nom au passage pour prendre en compte les éventuelles modifs de nom.
|
|
}
|
|
}
|
|
}
|
|
else flag_init_onglets_necessaire = true;
|
|
|
|
// Création du modèle d'onglets si cela est nécessaire :
|
|
if (flag_init_onglets_necessaire)
|
|
{
|
|
modele_onglets_circuits.clear();
|
|
|
|
nb = bdd.requete(req); // La requete est toujours correcte mais le résultat a pu commncer a être utilisé : il faut donc la rééxécuter.
|
|
for (i = 0; i < nb; i ++)
|
|
{
|
|
res = bdd.lecture_ligne();
|
|
if (!res.isEmpty)
|
|
{
|
|
if (id_groupe_circuits === Number(res[0])) actif = true;
|
|
else actif = false;
|
|
|
|
modele_onglets_circuits.append({"libelle": res[1], "id": Number(res[0]), "actif": actif, "etat": 0 });
|
|
}
|
|
}
|
|
}
|
|
|
|
// création du modèle des circuits de l'onglet en cours :
|
|
modele_circuits.clear();
|
|
req = 'SELECT ';
|
|
req += ' Cle_primaire, ';
|
|
req += ' Etat_systeme, ';
|
|
req += ' Nom, ';
|
|
req += ' Etat_commande_carte, ';
|
|
req += ' Mode_commande, ';
|
|
req += ' Etat, ';
|
|
req += ' Consigne, ';
|
|
req += ' Old_consigne, ';
|
|
req += ' Mode_test, ';
|
|
req += ' Tension, ';
|
|
req += ' Intensite, ';
|
|
req += ' Frequence, ';
|
|
req += ' (SELECT Type FROM TB_Modules_config WHERE Adresse_k_bus=TB_Circuits.Adresse_module) AS type_circuit, ';
|
|
req += ' No_circuit, ';
|
|
req += ' (SELECT COUNT(*) FROM TB_Events WHERE Validite=1 AND Visibilite=1 AND (Action_circuits LIKE CONCAT(TB_Circuits.Cle_primaire,"/%") OR Action_circuits LIKE CONCAT("%;", TB_Circuits.Cle_primaire,"/%") ) ) AS nb_events, ';
|
|
req += ' Validation_cdes_events, ';
|
|
req += ' (SELECT COUNT(*) FROM TB_Events WHERE Validite=1 AND Type_source=' + shipheart_source_mesure_circuit + ' AND Alarme_source>0 AND Etat_test=1 AND ID_Source=TB_Circuits.Cle_primaire) AS Nb_alarmes';
|
|
req += ' FROM TB_Circuits ';
|
|
req += ' WHERE Priorite_affichage_accueil>0 ';
|
|
req += ' AND ID_Famille=' + id_groupe_circuits + ' ';
|
|
req += ' ORDER BY Priorite_affichage_accueil, Cle_primaire';
|
|
//console.log("Requête = [ " + req + "; ]");
|
|
nb = bdd.requete(req);
|
|
|
|
for (i = 0; i < nb; i ++)
|
|
{
|
|
res = bdd.lecture_ligne();
|
|
if (!res.isEmpty)
|
|
{
|
|
modele_circuits.append({
|
|
"Cle_primaire": Number(res[0]),
|
|
"Etat_systeme": Number(res[1]),
|
|
"Nom": res[2],
|
|
"Etat_commande_carte": Number(res[3]),
|
|
"Mode_commande": Number(res[4]),
|
|
"Etat_circuit": Number(res[5]),
|
|
"Consigne": Number(res[6]),
|
|
"Old_consigne": Number(res[7]),
|
|
"Mode_test": Number(res[8]),
|
|
"Tension": Number(res[9]),
|
|
"Intensite": Number(res[10]),
|
|
"Frequence": Number(res[11]),
|
|
"Type_circuit": Number(res[12]),
|
|
"No_circuit": Number(res[13]),
|
|
"Validation_cdes_events": (Number(res[14]) === 0) ? -1 : Number(res[15]),
|
|
"Etat_events": Number(res[16]) });
|
|
}
|
|
}
|
|
}
|
|
|
|
//=======================================================================================================
|
|
// Fonction : Met à jour l'état de chaque onglet à partir de la synthès des circuits de l'onglet
|
|
//=======================================================================================================
|
|
function mise_a_jour_onglets_circuits()
|
|
{
|
|
var req, res;
|
|
var nb;
|
|
var i, j;
|
|
var etat_circuit;
|
|
|
|
|
|
for (i = 0; i < modele_onglets_circuits.count; i ++)
|
|
{
|
|
modele_onglets_circuits.set(i, {"etat": 0} ); // Valeur minimale par défaut
|
|
|
|
// Détection d'alarmes provenant d'un évènement :
|
|
req = 'SELECT COUNT(*) ';
|
|
req += ' FROM TB_Events ';
|
|
req += ' WHERE Type_source=' + shipheart_source_mesure_circuit + ' ';
|
|
req += ' AND Validite=1 ';
|
|
req += ' AND Alarme_source>0 ';
|
|
req += ' AND Etat_test=1 ';
|
|
req += ' AND ID_Source IN (SELECT Cle_primaire FROM TB_Circuits WHERE ID_Famille=' + modele_onglets_circuits.get(i).id + ' )';
|
|
//console.log("Requête = [" + req + "]");
|
|
res = bdd.requete_unique(req);
|
|
|
|
if (Number(res[0]) > 0) modele_onglets_circuits.set(i, {"etat": 1} ); // Coin orange
|
|
|
|
|
|
// Mise à jour de l'état de chaque onglet à partir de la synthèse des circuits de l'onglet :
|
|
req = 'SELECT Etat, Etat_commande_carte, Etat_systeme FROM TB_Circuits WHERE ID_Famille=' + modele_onglets_circuits.get(i).id + ' AND Priorite_affichage_accueil>0 ';
|
|
//console.log("Requête = [ " + req + "; ]");
|
|
nb = bdd.requete(req);
|
|
for (j = 0; j < nb; j ++)
|
|
{
|
|
res = bdd.lecture_ligne();
|
|
if (!res.isEmpty)
|
|
{
|
|
if ((Number(res[2]) !== 0) // Si on a une ERREUR_SYSTEME_CONFIG ou ERREUR_SYSTEME_RESEAU sur ce circuit, on met l'onglet en rouge...
|
|
|| (Number(res[0]) === shipheart_etat_circuit_limitation)
|
|
|| (Number(res[0]) === shipheart_etat_circuit_protection)
|
|
|| (Number(res[0]) === shipheart_etat_circuit_disjonte)
|
|
|| (Number(res[0]) === shipheart_etat_circuit_absence_terre)
|
|
|| (Number(res[0]) === shipheart_etat_circuit_absence_masse)) etat_circuit = 2; // Coin rouge
|
|
else if ((Number(res[1]) !== shipheart_etat_commande_module_ok)
|
|
|| (Number(res[0]) !== shipheart_etat_circuit_ok)) etat_circuit = 1; // Coin orange
|
|
else etat_circuit = 0;
|
|
|
|
if (etat_circuit > modele_onglets_circuits.get(i).etat) modele_onglets_circuits.set(i, {"etat": etat_circuit});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//=======================================================================================================
|
|
// Fonction : Récupère l'état de tous les circuits valides dans la BDD et met à jour le modele_circuits
|
|
// Impact : Environ 10ms (chaque 1s) mesuré via QML Profiler et mesure de temps d'exec. le 01/02/2022
|
|
//=======================================================================================================
|
|
function mise_a_jour_circuits()
|
|
{
|
|
var req, res;
|
|
var nb;
|
|
var i, j;
|
|
|
|
req = 'SELECT ';
|
|
req += ' Cle_primaire, ';
|
|
req += ' Etat_systeme, ';
|
|
req += ' Nom, ';
|
|
req += ' Etat_commande_carte, ';
|
|
req += ' Mode_commande, ';
|
|
req += ' Etat, ';
|
|
req += ' Consigne, ';
|
|
req += ' Old_consigne, ';
|
|
req += ' Mode_test, ';
|
|
req += ' Tension, ';
|
|
req += ' Intensite, ';
|
|
req += ' Frequence, ';
|
|
req += ' (SELECT Type FROM TB_Modules_config WHERE Adresse_k_bus=TB_Circuits.Adresse_module) AS type_circuit, ';
|
|
req += ' No_circuit, ';
|
|
req += ' (SELECT COUNT(*) FROM TB_Events WHERE Validite=1 AND Visibilite=1 AND (Action_circuits LIKE CONCAT(TB_Circuits.Cle_primaire,"/%") OR Action_circuits LIKE CONCAT("%;", TB_Circuits.Cle_primaire,"/%") ) ) AS nb_events, ';
|
|
req += ' Validation_cdes_events, ';
|
|
req += ' (SELECT COUNT(*) FROM TB_Events WHERE Validite=1 AND Type_source=' + shipheart_source_mesure_circuit + ' AND Alarme_source>0 AND Etat_test=1 AND ID_Source=TB_Circuits.Cle_primaire) AS Nb_alarmes';
|
|
req += ' FROM TB_Circuits ';
|
|
req += ' WHERE Priorite_affichage_accueil>0 ';
|
|
req += ' AND ID_Famille=' + id_groupe_circuits + ' ';
|
|
req += ' ORDER BY Priorite_affichage_accueil, Cle_primaire';
|
|
//console.log("Requête = [ " + req + "; ]");
|
|
nb = bdd.requete(req);
|
|
|
|
for (i = 0; i < nb; i ++)
|
|
{
|
|
res = bdd.lecture_ligne();
|
|
if (!res.isEmpty)
|
|
{
|
|
for (j = 0; j < modele_circuits.count; j ++)
|
|
{
|
|
if (Number(res[0]) === modele_circuits.get(j).Cle_primaire)
|
|
{
|
|
modele_circuits.set(j, {
|
|
"Etat_systeme": Number(res[1]),
|
|
"Nom": res[2],
|
|
"Etat_commande_carte": Number(res[3]),
|
|
"Mode_commande": Number(res[4]),
|
|
"Etat_circuit": Number(res[5]),
|
|
"Consigne": Number(res[6]),
|
|
"Old_consigne": Number(res[7]),
|
|
"Mode_test": Number(res[8]),
|
|
"Tension": Number(res[9]),
|
|
"Intensite": Number(res[10]),
|
|
"Frequence": Number(res[11]),
|
|
"Type_circuit": Number(res[12]),
|
|
"No_circuit": Number(res[13]),
|
|
"Validation_cdes_events": (Number(res[14]) === 0) ? -1 : Number(res[15]),
|
|
"Etat_events": Number(res[16]) });
|
|
break; // Si on a trouvé l'entrée du modèle correspondant au circuit en cours de traitement depuis la BDD, on sort de la boucle sur le modèle (mais on continue la boucle sur les résultats de la requete !)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//=================================================================================================
|
|
// Fonction :
|
|
// - mise à jour de l'onglet en cours en vérifiant que l'ID en cours existe bien dans la table des familles,
|
|
// - vérifie que le modèle d'onglets a la même taille que la table des familles.
|
|
// - si Oui, mise à jour du nom et de l'état actif de chaque entrée du modèle et vérification que l'ordre du modèle égale celui de la table
|
|
// - Si Non (ou si l'ordre de la table n'est plus conforme au modèle), Raz du modèle est remplissage.
|
|
// - Création du modèle de réservoirs correspondant à l'onglet en cours
|
|
// NB : il n'est pas utile d'appeler la fonction 'mise_a_jour_reservoirs()' après car le modèle de réservoirs
|
|
// venant d'être créé, il est forcément à jour...
|
|
//=================================================================================================
|
|
function init_reservoirs()
|
|
{
|
|
var req, res;
|
|
var nb;
|
|
var i;
|
|
var actif;
|
|
|
|
|
|
// Mise à jour de l'onglet en cours :
|
|
req = 'SELECT COUNT(*) FROM TB_Familles WHERE Cle_primaire=' + id_groupe_reservoirs + ' ';
|
|
res = bdd.requete_unique(req);
|
|
if (Number(res[0]) !== 1) // Si l'ID en cours n'existe pas dans la BDD (à l'init notamment mais aussi si suppression de famille par exemple)
|
|
{
|
|
req = 'SELECT Cle_primaire FROM TB_Familles WHERE Type_source=' + shipheart_type_source_reservoirs + ' ORDER BY Priorite_affichage LIMIT 1'; // Choix de la première famille par ordre de priorité
|
|
res = bdd.requete_unique(req);
|
|
id_groupe_reservoirs = Number(res[0]);
|
|
}
|
|
|
|
// Mise à jour du modèle d'onglets :
|
|
var flag_init_onglets_necessaire = false;
|
|
req = 'SELECT Cle_primaire, Nom FROM TB_Familles WHERE Type_source=' + shipheart_type_source_reservoirs + ' ORDER BY Priorite_affichage ';
|
|
//console.log("Requête = [" + req + "]");
|
|
nb = bdd.requete(req);
|
|
|
|
if (nb === modele_onglets_reservoirs.count) // Si on a supprimé ou ajouté des familles, on va devoir reconstruire le modèle d'onglets :
|
|
{
|
|
for (i = 0; i < nb; i ++)
|
|
{
|
|
res = bdd.lecture_ligne();
|
|
if (!res.isEmpty)
|
|
{
|
|
// On teste que l'ordre des familles n'a pas changé depuis la création du modèle :
|
|
if (Number(res[0]) !== modele_onglets_reservoirs.get(i).id)
|
|
{
|
|
flag_init_onglets_necessaire = true; // S'il a changé (ou si ajout/suppression de familles avec des clés différentes), on arrête et on demande une reconstruction complète du modèle.
|
|
break;
|
|
}
|
|
|
|
// Détection du groupe en cours :
|
|
if (id_groupe_reservoirs === Number(res[0])) actif = true;
|
|
else actif = false;
|
|
|
|
// Mise à jour du flag 'actif' pour chaque onglet :
|
|
modele_onglets_reservoirs.set(i, {"libelle": res[1], "actif": actif}); // On met à jour le nom au passage pour prendre en compte les éventuelles modifs de nom.
|
|
}
|
|
}
|
|
}
|
|
else flag_init_onglets_necessaire = true;
|
|
|
|
// Création du modèle d'onglets si cela est nécessaire :
|
|
if (flag_init_onglets_necessaire)
|
|
{
|
|
modele_onglets_reservoirs.clear();
|
|
|
|
nb = bdd.requete(req); // La requete est toujours correcte mais le résultat a pu commncer a être utilisé : il faut donc la rééxécuter.
|
|
for (i = 0; i < nb; i ++)
|
|
{
|
|
res = bdd.lecture_ligne();
|
|
if (!res.isEmpty)
|
|
{
|
|
if (id_groupe_reservoirs === Number(res[0])) actif = true;
|
|
else actif = false;
|
|
|
|
modele_onglets_reservoirs.append({"libelle": res[1], "id": Number(res[0]), "actif": actif, "etat": 0});
|
|
}
|
|
}
|
|
}
|
|
|
|
// création du modèle des réservoirs de l'onglet en cours :
|
|
modele_reservoirs.clear();
|
|
|
|
req = 'SELECT Cle_primaire, ';
|
|
req += ' Nom, ';
|
|
req += ' Etat_systeme, ';
|
|
req += ' ID_Famille, ';
|
|
req += ' Niveau, ';
|
|
req += ' Capacite, ';
|
|
req += ' Logique, ';
|
|
req += ' (SELECT COUNT(*) FROM TB_Events WHERE Validite=1 AND Type_source=' + shipheart_source_mesure_reservoir + ' AND Alarme_source>0 AND Etat_test=1 AND ID_Source=TB_Reservoirs.Cle_primaire) AS Nb_alarmes, '
|
|
req += ' Etat_entrees ';
|
|
req += ' FROM TB_Reservoirs ';
|
|
req += ' WHERE ID_Famille= ' + id_groupe_reservoirs + ' ';
|
|
req += ' ORDER BY Priorite_affichage_accueil';
|
|
//console.log("Requête = [ " + req + "; ]");
|
|
nb = bdd.requete(req);
|
|
|
|
for (i = 0; i < nb; i ++)
|
|
{
|
|
res = bdd.lecture_ligne();
|
|
if (!res.isEmpty)
|
|
{
|
|
modele_reservoirs.append({
|
|
"Cle_primaire": Number(res[0]),
|
|
"Nom": res[1],
|
|
"Etat_systeme": Number(res[2]),
|
|
"ID_Famille": Number(res[3]),
|
|
"Niveau": Number(res[4]),
|
|
"Capacite": Number(res[5]),
|
|
"Logique": Number(res[6]),
|
|
"Etat": ( (Number(res[2]) < 0) // Etat_systeme = ERREUR_SYSTEME_CONFIG ou ERREUR_SYSTEME_RESEAU
|
|
|| (Number(res[8]) > 0)) // Etat_entrees = 1 = Defaut ordre des sondes AUX
|
|
? 2
|
|
: ( Number(res[7]) > 0 // Au moins une alerte sur Event
|
|
? 1
|
|
: 0 ) });
|
|
}
|
|
}
|
|
}
|
|
|
|
//=======================================================================================================
|
|
// Fonction : Met à jour l'état de chaque onglet à partir de la synthès des réservoirs de l'onglet
|
|
//=======================================================================================================
|
|
function mise_a_jour_onglets_reservoirs()
|
|
{
|
|
var req, res;
|
|
var nb;
|
|
var i, j;
|
|
|
|
|
|
// Mise à jour de l'état de chaque onglet à partir de la synthèse des réservoirs de l'onglet :
|
|
// En pratique, seuls les réservoirs à électrodes plongées génèrent des Etats != 0....
|
|
for (i = 0; i < modele_onglets_reservoirs.count; i ++)
|
|
{
|
|
modele_onglets_reservoirs.set(i, {"etat": 0});
|
|
|
|
// Détection d'alarmes provenant d'un évènement :
|
|
req = 'SELECT COUNT(*) ';
|
|
req += ' FROM TB_Events ';
|
|
req += ' WHERE Type_source=' + shipheart_source_mesure_reservoir + ' ';
|
|
req += ' AND Validite=1 ';
|
|
req += ' AND Alarme_source>0 ';
|
|
req += ' AND Etat_test=1 ';
|
|
req += ' AND ID_Source IN (SELECT Cle_primaire FROM TB_Reservoirs WHERE ID_Famille=' + modele_onglets_reservoirs.get(i).id + ' )';
|
|
//console.log("Requête = [ " + req + "; ]");
|
|
res = bdd.requete_unique(req);
|
|
|
|
if (Number(res[0]) > 0) modele_onglets_reservoirs.set(i, {"etat": 1} ); // Coin orange
|
|
|
|
|
|
// Mise à jour de l'état de chaque onglet à partir de la synthèse des réservoirs de l'onglet :
|
|
req = 'SELECT Etat_entrees, Etat_systeme FROM TB_Reservoirs WHERE ID_Famille=' + modele_onglets_reservoirs.get(i).id + ' AND Priorite_affichage_accueil>0 ';
|
|
//console.log("Requête = [ " + req + "; ]");
|
|
nb = bdd.requete(req);
|
|
for (j = 0; j < nb; j ++)
|
|
{
|
|
res = bdd.lecture_ligne();
|
|
if (!res.isEmpty)
|
|
{
|
|
// if (Number(res[0]) > modele_onglets_reservoirs.get(i).etat) modele_onglets_reservoirs.set(i, {"etat": Number(res[0])}); // SDIR #285
|
|
if ((Number(res[0]) > 0) // Si Défaut_capteur = 1 (ordre des sondes AUX inversées
|
|
|| (Number(res[1]) !== 0) ) // Si ERREUR_SYSTEME_CONFIG ou ERREUR_SYSTEME_RESEAU
|
|
{
|
|
if (modele_onglets_reservoirs.get(i).etat < 2) modele_onglets_reservoirs.set(i, {"etat": 2}); // SDIR #285
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//===========================================================================================================
|
|
// Fonction : Récupère l'état de tous les réservoirs valides dans la BDD et met à jour le modele_reservoirs
|
|
//===========================================================================================================
|
|
function mise_a_jour_reservoirs()
|
|
{
|
|
var req, res;
|
|
var nb;
|
|
var i, j;
|
|
|
|
req = 'SELECT Cle_primaire, ';
|
|
req += ' Nom, ';
|
|
req += ' Etat_systeme, ';
|
|
req += ' ID_Famille, ';
|
|
req += ' Niveau, ';
|
|
req += ' Capacite, ';
|
|
req += ' Logique, ';
|
|
req += ' (SELECT COUNT(*) FROM TB_Events WHERE Validite=1 AND Type_source=' + shipheart_source_mesure_reservoir + ' AND Alarme_source>0 AND Etat_test=1 AND ID_Source=TB_Reservoirs.Cle_primaire) AS Nb_alarmes, '
|
|
req += ' Etat_entrees ';
|
|
req += ' FROM TB_Reservoirs ';
|
|
req += ' WHERE ID_Famille= ' + id_groupe_reservoirs + ' ';
|
|
req += ' ORDER BY Priorite_affichage_accueil';
|
|
//console.log("Requête = [ " + req + "; ]");
|
|
nb = bdd.requete(req);
|
|
|
|
for (i = 0; i < nb; i ++)
|
|
{
|
|
res = bdd.lecture_ligne();
|
|
if (!res.isEmpty)
|
|
{
|
|
for (j = 0; j < modele_reservoirs.count; j ++)
|
|
{
|
|
if (Number(res[0]) === modele_reservoirs.get(j).Cle_primaire)
|
|
{
|
|
modele_reservoirs.set(j, {
|
|
"Nom": res[1],
|
|
"Etat_systeme": Number(res[2]),
|
|
"ID_Famille": Number(res[3]),
|
|
"Niveau": Number(res[4]),
|
|
"Capacite": Number(res[5]),
|
|
"Logique": Number(res[6]),
|
|
"Etat": ( (Number(res[2]) < 0) // Etat_systeme = ERREUR_SYSTEME_CONFIG ou ERREUR_SYSTEME_RESEAU
|
|
|| (Number(res[8]) > 0)) // Etat_entrees = 1 = Defaut ordre des sondes AUX
|
|
? 2
|
|
: ( Number(res[7]) > 0 // Au moins une alerte sur Event
|
|
? 1
|
|
: 0 ) });
|
|
break; // Si on a trouvé l'entrée du modèle correspondant au réservoir en cours de traitement depuis la BDD, on sort de la boucle sur le modèle (mais on continue la boucle sur les résultats de la requete !)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//=================================================================================================
|
|
// Fonction :
|
|
// - mise à jour de l'onglet en cours en vérifiant que l'ID en cours existe bien dans la table des familles,
|
|
// - vérifie que le modèle d'onglets a la même taille que la table des familles.
|
|
// - si Oui, mise à jour du nom et de l'état actif de chaque entrée du modèle et vérification que l'ordre du modèle égale celui de la table
|
|
// - Si Non (ou si l'ordre de la table n'est plus conforme au modèle), Raz du modèle est remplissage.
|
|
// - Création du modèle de batteries correspondant à l'onglet en cours
|
|
// NB : il n'est pas utile d'appeler la fonction 'mise_a_jour_batteries()' après car le modèle de batteries
|
|
// venant d'être créé, il est forcément à jour...
|
|
//=================================================================================================
|
|
function init_batteries()
|
|
{
|
|
var req, res;
|
|
var nb;
|
|
var i;
|
|
var actif;
|
|
|
|
// Mise à jour de l'onglet en cours :
|
|
req = 'SELECT COUNT(*) FROM TB_Familles WHERE Cle_primaire=' + id_groupe_batteries + ' ';
|
|
res = bdd.requete_unique(req);
|
|
if (Number(res[0]) !== 1) // Si l'ID en cours n'existe pas dans la BDD (à l'init notamment mais aussi si suppression de famille par exemple)
|
|
{
|
|
req = 'SELECT Cle_primaire FROM TB_Familles WHERE Type_source=' + shipheart_type_source_batteries + ' ORDER BY Priorite_affichage LIMIT 1'; // Choix de la première famille par ordre de priorité
|
|
res = bdd.requete_unique(req);
|
|
id_groupe_batteries = Number(res[0]);
|
|
}
|
|
|
|
// Mise à jour du modèle d'onglets :
|
|
var flag_init_onglets_necessaire = false;
|
|
req = 'SELECT Cle_primaire, Nom FROM TB_Familles WHERE Type_source=' + shipheart_type_source_batteries + ' ORDER BY Priorite_affichage ';
|
|
//console.log("Requête = [" + req + "]");
|
|
nb = bdd.requete(req);
|
|
|
|
if (nb === modele_onglets_batteries.count) // Si on a supprimé ou ajouté des familles, on va devoir reconstruire le modèle d'onglets :
|
|
{
|
|
for (i = 0; i < nb; i ++)
|
|
{
|
|
res = bdd.lecture_ligne();
|
|
if (!res.isEmpty)
|
|
{
|
|
// On teste que l'ordre des familles n'a pas changé depuis la création du modèle :
|
|
if (Number(res[0]) !== modele_onglets_batteries.get(i).id)
|
|
{
|
|
flag_init_onglets_necessaire = true; // S'il a changé (ou si ajout/suppression de familles avec des clés différentes), on arrête et on demande une reconstruction complète du modèle.
|
|
break;
|
|
}
|
|
|
|
// Détection du groupe en cours :
|
|
if (id_groupe_batteries === Number(res[0])) actif = true;
|
|
else actif = false;
|
|
|
|
// Mise à jour du flag 'actif' pour chaque onglet :
|
|
modele_onglets_batteries.set(i, {"libelle": res[1], "actif": actif}); // On met à jour le nom au passage pour prendre en compte les éventuelles modifs de nom.
|
|
}
|
|
}
|
|
}
|
|
else flag_init_onglets_necessaire = true;
|
|
|
|
// Création du modèle d'onglets si cela est nécessaire :
|
|
if (flag_init_onglets_necessaire)
|
|
{
|
|
modele_onglets_batteries.clear();
|
|
|
|
nb = bdd.requete(req); // La requete est toujours correcte mais le résultat a pu commncer a être utilisé : il faut donc la rééxécuter.
|
|
for (i = 0; i < nb; i ++)
|
|
{
|
|
res = bdd.lecture_ligne();
|
|
if (!res.isEmpty)
|
|
{
|
|
if (id_groupe_batteries === Number(res[0])) actif = true;
|
|
else actif = false;
|
|
|
|
modele_onglets_batteries.append({"libelle": res[1], "id": Number(res[0]), "actif": actif, "etat": 0 });
|
|
}
|
|
}
|
|
}
|
|
|
|
// création du modèle des batteries de l'onglet en cours :
|
|
modele_batteries.clear();
|
|
|
|
req = 'SELECT Cle_primaire, ';
|
|
req += ' Etat_systeme, ';
|
|
req += ' Nom, ';
|
|
req += ' Type, ';
|
|
req += ' Soc, ';
|
|
req += ' Tension, ';
|
|
req += ' Tension_nominale, ';
|
|
req += ' (SELECT COUNT(*) FROM TB_Events WHERE Validite=1 AND Type_source=' + shipheart_source_mesure_batterie + ' AND Alarme_source>0 AND Etat_test=1 AND ID_Source=TB_Batteries.Cle_primaire) AS Nb_alarmes';
|
|
req += ' FROM TB_Batteries ';
|
|
req += ' WHERE ID_Famille=' + id_groupe_batteries + ' ';
|
|
req += ' ORDER BY Priorite_affichage_accueil';
|
|
//console.log("Requête = [" + req + "]");
|
|
nb = bdd.requete(req);
|
|
|
|
for (i = 0; i < nb; i ++)
|
|
{
|
|
res = bdd.lecture_ligne();
|
|
if (!res.isEmpty)
|
|
{
|
|
modele_batteries.append({
|
|
"Cle_primaire": Number(res[0]),
|
|
"Etat_systeme": Number(res[1]),
|
|
"Nom": res[2],
|
|
"Type": res[3],
|
|
"Niveau": Number(res[4]),
|
|
"Tension": Number(res[5]),
|
|
"Tension_nominale": Number(res[6]),
|
|
"Etat": Number(res[7]) });
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//=======================================================================================================
|
|
// Fonction : Met à jour l'état de chaque onglet à partir de la synthès des batteries de l'onglet
|
|
//=======================================================================================================
|
|
function mise_a_jour_onglets_batteries()
|
|
{
|
|
var req, res;
|
|
var nb;
|
|
var i, j;
|
|
|
|
// Détection d'alarmes sur les différents onglets :
|
|
for (i = 0; i < modele_onglets_batteries.count; i ++)
|
|
{
|
|
modele_onglets_batteries.set(i, {"etat": 0} );
|
|
|
|
// Détection d'alarmes provenant d'un évènement :
|
|
req = 'SELECT COUNT(*) ';
|
|
req += ' FROM TB_Events ';
|
|
req += ' WHERE Type_source=' + shipheart_source_mesure_batterie + ' ';
|
|
req += ' AND Validite=1 ';
|
|
req += ' AND Alarme_source>0 ';
|
|
req += ' AND Etat_test=1 ';
|
|
req += ' AND ID_Source IN (SELECT Cle_primaire FROM TB_Batteries WHERE ID_Famille=' + modele_onglets_batteries.get(i).id + ' )';
|
|
//console.log("Requête = [" + req + "]");
|
|
res = bdd.requete_unique(req);
|
|
|
|
if (Number(res[0]) > 0) modele_onglets_batteries.set(i, {"etat": 1} ); // Coin orange
|
|
|
|
|
|
// Mise à jour de l'état de chaque onglet à partir de la synthèse des batteries de l'onglet :
|
|
req = 'SELECT Etat_systeme FROM TB_Batteries WHERE ID_Famille=' + modele_onglets_batteries.get(i).id + ' AND Priorite_affichage_accueil>0 ';
|
|
//console.log("Requête = [ " + req + "; ]");
|
|
nb = bdd.requete(req);
|
|
for (j = 0; j < nb; j ++)
|
|
{
|
|
res = bdd.lecture_ligne();
|
|
if (!res.isEmpty)
|
|
{
|
|
if (Number(res[0]) !== 0) // Si ERREUR_SYSTEME_CONFIG ou ERREUR_SYSTEME_RESEAU
|
|
{
|
|
if (modele_onglets_batteries.get(i).etat < 2) modele_onglets_batteries.set(i, {"etat": 2}); // Coin rouge
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//=========================================================================================================
|
|
// Fonction : Récupère l'état de toutes les batteries valides dans la BDD et met à jour le modele_batteries
|
|
//=========================================================================================================
|
|
function mise_a_jour_batteries()
|
|
{
|
|
var req, res;
|
|
var nb;
|
|
var i, j;
|
|
|
|
// Mise à jour des valeurs des batteries du groupe :
|
|
req = 'SELECT Cle_primaire, ';
|
|
req += ' Etat_systeme, ';
|
|
req += ' Nom, ';
|
|
req += ' Type, ';
|
|
req += ' Soc, ';
|
|
req += ' Tension, ';
|
|
req += ' Tension_nominale, ';
|
|
req += ' (SELECT COUNT(*) FROM TB_Events WHERE Validite=1 AND Type_source=' + shipheart_source_mesure_batterie + ' AND Alarme_source>0 AND Etat_test=1 AND ID_Source=TB_Batteries.Cle_primaire) AS Nb_alarmes';
|
|
req += ' FROM TB_Batteries ';
|
|
req += ' WHERE ID_Famille=' + id_groupe_batteries + ' ';
|
|
req += ' ORDER BY Priorite_affichage_accueil';
|
|
//console.log("Requête = [" + req + "]");
|
|
nb = bdd.requete(req);
|
|
|
|
for (i = 0; i < nb; i ++)
|
|
{
|
|
res = bdd.lecture_ligne();
|
|
if (!res.isEmpty)
|
|
{
|
|
for (j = 0; j < modele_batteries.count; j ++)
|
|
{
|
|
if (Number(res[0]) === modele_batteries.get(j).Cle_primaire)
|
|
{
|
|
modele_batteries.set(j, {
|
|
"Etat_systeme": Number(res[1]),
|
|
"Nom": res[2],
|
|
"Type": res[3],
|
|
"Niveau": Number(res[4]),
|
|
"Tension": Number(res[5]),
|
|
"Tension_nominale": Number(res[6]),
|
|
"Etat" : Number(res[7]) });
|
|
break; // Si on a trouvé l'entrée du modèle correspondant au réservoir en cours de traitement depuis la BDD, on sort de la boucle sur le modèle (mais on continue la boucle sur les résultats de la requete !)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//=================================================================================================
|
|
// Fonction :
|
|
// - mise à jour de l'onglet en cours en vérifiant que l'ID en cours existe bien dans la table des familles,
|
|
// - vérifie que le modèle d'onglets a la même taille que la table des familles.
|
|
// - si Oui, mise à jour du nom et de l'état actif de chaque entrée du modèle et vérification que l'ordre du modèle égale celui de la table
|
|
// - Si Non (ou si l'ordre de la table n'est plus conforme au modèle), Raz du modèle est remplissage.
|
|
// - Création du modèle de capteurs correspondant à l'onglet en cours
|
|
// NB : il n'est pas utile d'appeler la fonction 'mise_a_jour_capteurs()' après car le modèle de capteurs
|
|
// venant d'être créé, il est forcément à jour...
|
|
//=================================================================================================
|
|
function init_capteurs()
|
|
{
|
|
var req, res;
|
|
var sous_res;
|
|
var nb;
|
|
var i;
|
|
var actif;
|
|
var nouvelle_unite
|
|
var symbole_unite
|
|
var type_unite;
|
|
var flag_obsolete;
|
|
|
|
// Mise à jour de l'onglet en cours :
|
|
req = 'SELECT COUNT(*) FROM TB_Familles WHERE Cle_primaire=' + id_groupe_capteurs + ' ';
|
|
res = bdd.requete_unique(req);
|
|
if (Number(res[0]) !== 1) // Si l'ID en cours n'existe pas dans la BDD (à l'init notamment mais aussi si suppression de famille par exemple)
|
|
{
|
|
req = 'SELECT Cle_primaire FROM TB_Familles WHERE Type_source=' + shipheart_type_source_capteurs + ' ORDER BY Priorite_affichage LIMIT 1'; // Choix de la première famille par ordre de priorité
|
|
res = bdd.requete_unique(req);
|
|
id_groupe_capteurs = Number(res[0]);
|
|
}
|
|
|
|
// Mise à jour du modèle d'onglets :
|
|
var flag_init_onglets_necessaire = false;
|
|
req = 'SELECT Cle_primaire, Nom FROM TB_Familles WHERE Type_source=' + shipheart_type_source_capteurs + ' ORDER BY Priorite_affichage ';
|
|
//console.log("Requête = [" + req + "]");
|
|
nb = bdd.requete(req);
|
|
|
|
if (nb === modele_onglets_capteurs.count) // Si on a supprimé ou ajouté des familles, on va devoir reconstruire le modèle d'onglets :
|
|
{
|
|
for (i = 0; i < nb; i ++)
|
|
{
|
|
res = bdd.lecture_ligne();
|
|
if (!res.isEmpty)
|
|
{
|
|
// On teste que l'ordre des familles n'a pas changé depuis la création du modèle :
|
|
if (Number(res[0]) !== modele_onglets_capteurs.get(i).id)
|
|
{
|
|
flag_init_onglets_necessaire = true; // S'il a changé (ou si ajout/suppression de familles avec des clés différentes), on arrête et on demande une reconstruction complète du modèle.
|
|
break;
|
|
}
|
|
|
|
// Détection du groupe en cours :
|
|
if (id_groupe_capteurs === Number(res[0])) actif = true;
|
|
else actif = false;
|
|
|
|
// Mise à jour du flag 'actif' pour chaque onglet :
|
|
modele_onglets_capteurs.set(i, {"libelle": res[1], "actif": actif}); // On met à jour le nom au passage pour prendre en compte les éventuelles modifs de nom.
|
|
}
|
|
}
|
|
}
|
|
else flag_init_onglets_necessaire = true;
|
|
|
|
// Création du modèle d'onglets si cela est nécessaire :
|
|
if (flag_init_onglets_necessaire)
|
|
{
|
|
modele_onglets_capteurs.clear();
|
|
|
|
nb = bdd.requete(req); // La requete est toujours correcte mais le résultat a pu commncer a être utilisé : il faut donc la rééxécuter.
|
|
for (i = 0; i < nb; i ++)
|
|
{
|
|
res = bdd.lecture_ligne();
|
|
if (!res.isEmpty)
|
|
{
|
|
if (id_groupe_capteurs === Number(res[0])) actif = true;
|
|
else actif = false;
|
|
|
|
modele_onglets_capteurs.append({"libelle": res[1], "id": Number(res[0]), "actif": actif, "etat": 0 });
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// création du modèle des capteurs de l'onglet en cours :
|
|
modele_capteurs.clear();
|
|
|
|
req = ' SELECT Cle_primaire, ';
|
|
req += ' Etat_systeme, ';
|
|
req += ' Nom, ';
|
|
req += ' Type_entrees, ';
|
|
req += ' Entrees, ';
|
|
req += ' ID_Variable, ';
|
|
req += ' Etat, ';
|
|
req += ' (SELECT COUNT(*) FROM TB_Events WHERE Validite=1 AND Type_source=' + shipheart_source_mesure_capteur + ' AND Alarme_source>0 AND Etat_test=1 AND ID_Source=TB_Capteurs.Cle_primaire) AS Nb_alarmes, '
|
|
req += ' Valeur, ';
|
|
req += ' Precision_affichage_accueil, ';
|
|
req += ' Liste_valeurs_textes, ';
|
|
req += ' IF ( (Type_entrees=' + shipheart_capteur_type_entrees_nmea + '), ';
|
|
req += ' ( SELECT ( UNIX_TIMESTAMP() - UNIX_TIMESTAMP(Date_maj) ) ';
|
|
req += ' FROM TB_Nmea2000 WHERE ';
|
|
req += ' Pgn=SUBSTRING_INDEX(Entrees, \':\', 1) AND Field=SUBSTRING_INDEX(Entrees, \':\', -1) ), ';
|
|
// req += ' (UNIX_TIMESTAMP() - UNIX_TIMESTAMP(Date_maj)) )'; // SDIR #336
|
|
req += ' 0 )'; // SDIR #336
|
|
req += ' AS Age ';
|
|
req += ' FROM TB_Capteurs WHERE ID_Famille=' + id_groupe_capteurs + ' ';
|
|
req += ' AND Priorite_affichage_accueil>0 ';
|
|
req += ' ORDER BY Priorite_affichage_accueil, Nom';
|
|
//console.log("Requête = [ " + req + "; ]");
|
|
nb = bdd.requete(req);
|
|
|
|
for (i = 0; i < nb; i ++)
|
|
{
|
|
res = bdd.lecture_ligne();
|
|
if (!res.isEmpty)
|
|
{
|
|
flag_obsolete = false;
|
|
|
|
// Recherche des infos stockées dans la Variable pointée par ID_Variable :
|
|
sous_res = bdd.requete_unique('SELECT Unite, Conversion_unite FROM TB_Variables WHERE Cle_primaire="' + Number(res[5]) + '" ');
|
|
|
|
// Traitement des conversions d'unités :
|
|
switch(Number(sous_res[1]))
|
|
{
|
|
case shipheart_type_unite_volume:
|
|
nouvelle_unite = shipheart_unite_volume;
|
|
symbole_unite = shipheart_unite_volume_symbole;
|
|
type_unite = shipheart_type_unite_volume;
|
|
break;
|
|
case shipheart_type_unite_temperature:
|
|
nouvelle_unite = shipheart_unite_temperature;
|
|
symbole_unite = shipheart_unite_temperature_symbole;
|
|
type_unite = shipheart_type_unite_temperature;
|
|
break;
|
|
case shipheart_type_unite_latitude:
|
|
nouvelle_unite = 0;
|
|
symbole_unite = "";
|
|
type_unite = shipheart_type_unite_latitude;
|
|
break;
|
|
case shipheart_type_unite_longitude:
|
|
nouvelle_unite = 0;
|
|
symbole_unite = "";
|
|
type_unite = shipheart_type_unite_longitude;
|
|
break;
|
|
default:
|
|
nouvelle_unite = 0;
|
|
type_unite = 0;
|
|
symbole_unite = sous_res[0];
|
|
break;
|
|
}
|
|
|
|
// Cas spécifiques en fonction du type de capteur :
|
|
var chaine_valeur = Fonctions.conversion_unites( Number(res[8]), nouvelle_unite, "", Number(res[9]), type_unite);
|
|
switch(Number(res[3]))
|
|
{
|
|
//-----------------------------------------------------------------
|
|
case shipheart_capteur_type_entrees_aux:
|
|
case shipheart_capteur_type_entrees_calculee_booleen:
|
|
|
|
// Traitement des listes :
|
|
var chaines_valeurs_textes = res[10].split(';');
|
|
for (let chaine_valeur_texte of chaines_valeurs_textes)
|
|
{
|
|
var chaine = chaine_valeur_texte.split('/');
|
|
if (chaine.length === 2) // Evite de traiter les cas invalides (notamment, une chaine totalement vide qui arrive ici avec un length de 1...)
|
|
{
|
|
if (Number(res[8]) === Number(chaine [0])) // Si l'une des valeurs de la liste correspond à la valeur actuelle :
|
|
{
|
|
chaine_valeur = chaine[1]; // La valeur affichée sera le texte correspondant.
|
|
break; // Et il est inutile de chercher d'autres valeurs...
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
//-----------------------------------------------------------------
|
|
case shipheart_capteur_type_entrees_level_sensor:
|
|
break;
|
|
|
|
//-----------------------------------------------------------------
|
|
case shipheart_capteur_type_entrees_ow:
|
|
break;
|
|
|
|
//-----------------------------------------------------------------
|
|
case shipheart_capteur_type_entrees_predefinie:
|
|
break;
|
|
|
|
//-----------------------------------------------------------------
|
|
case shipheart_capteur_type_entrees_nmea:
|
|
if (Number(res[11]) > shipheart_periode_obsolescence_capteur_nmea) flag_obsolete = true;
|
|
|
|
break;
|
|
|
|
//-----------------------------------------------------------------
|
|
default :
|
|
break;
|
|
}
|
|
|
|
modele_capteurs.append({
|
|
"Cle_primaire": Number(res[0]),
|
|
"Etat_systeme": Number(res[1]),
|
|
"Nom": res[2],
|
|
"Valeur": chaine_valeur +"", // Le ' + "" ' permet de s'assurer que c'est toujours une STRING, même quand c'est une valeur numérique (le modèle n'accepte pas d'avoir un coup des STRING, un coup des NUM...)
|
|
"Unite": symbole_unite,
|
|
"Obsolete": flag_obsolete,
|
|
"Etat": Number(res[7]), // Events
|
|
"Etat_capteur": Number(res[6]) }); // 'Etat' du capteur (entre 0 et 2)
|
|
}
|
|
}
|
|
}
|
|
|
|
//=======================================================================================================
|
|
// Fonction : Met à jour l'état de chaque onglet à partir de la synthès des capteurs de l'onglet
|
|
//=======================================================================================================
|
|
function mise_a_jour_onglets_capteurs()
|
|
{
|
|
var req, res;
|
|
var nb;
|
|
var i, j;
|
|
|
|
// Mise à jour de l'état de chaque onglet à partir de la synthèse des capteurs de l'onglet :
|
|
// En pratique, seuls les capteurs OW génèrent des Etats != 0....
|
|
for (i = 0; i < modele_onglets_capteurs.count; i ++)
|
|
{
|
|
modele_onglets_capteurs.set(i, {"etat": 0} );
|
|
|
|
// Détection d'alarmes sur les différents onglets :
|
|
req = 'SELECT COUNT(*) ';
|
|
req += ' FROM TB_Events ';
|
|
req += ' WHERE Type_source=' + shipheart_source_mesure_capteur + ' ';
|
|
req += ' AND Validite=1 ';
|
|
req += ' AND Alarme_source>0 ';
|
|
req += ' AND Etat_test=1 ';
|
|
req += ' AND ID_Source IN (SELECT Cle_primaire FROM TB_Capteurs WHERE ID_Famille=' + modele_onglets_capteurs.get(i).id + ' )';
|
|
//console.log("Requête = [" + req + "]");
|
|
res = bdd.requete_unique(req);
|
|
|
|
if (Number(res[0]) > 0) modele_onglets_capteurs.set(i, {"etat": 1} ); // Coin orange
|
|
|
|
// Mise à jour de l'état de chaque onglet à partir de la synthèse des batteries de l'onglet :
|
|
req = ' SELECT Etat, ';
|
|
req += ' Etat_systeme, ';
|
|
req += ' IF ( (Type_entrees=' + shipheart_capteur_type_entrees_nmea + '), ';
|
|
req += ' ( SELECT ( UNIX_TIMESTAMP() - UNIX_TIMESTAMP(Date_maj) ) ';
|
|
req += ' FROM TB_Nmea2000 WHERE ';
|
|
req += ' Pgn=SUBSTRING_INDEX(Entrees, \':\', 1) AND Field=SUBSTRING_INDEX(Entrees, \':\', -1) ), ';
|
|
// req += ' (UNIX_TIMESTAMP() - UNIX_TIMESTAMP(Date_maj)) )'; // SDIR #336
|
|
req += ' 0 )'; // SDIR #336
|
|
req += ' AS Age ';
|
|
req += ' FROM TB_Capteurs ';
|
|
req += ' WHERE ID_Famille=' + modele_onglets_capteurs.get(i).id + ' ';
|
|
req += ' AND Priorite_affichage_accueil>0 ';
|
|
//console.log("Requête = [ " + req + "; ]");
|
|
nb = bdd.requete(req);
|
|
for (j = 0; j < nb; j ++)
|
|
{
|
|
res = bdd.lecture_ligne();
|
|
if (!res.isEmpty)
|
|
{
|
|
// Obsolescence des capteurs NMEA :
|
|
if (Number(res[2]) > shipheart_periode_obsolescence_capteur_nmea)
|
|
{
|
|
if (modele_onglets_capteurs.get(i).etat < 1) modele_onglets_capteurs.set(i, {"etat": 1}); // Coin orange
|
|
}
|
|
|
|
// Défaut capteur ou défaut système :
|
|
if ( (Number(res[0]) > 0) // Défaut de capteur
|
|
|| (Number(res[1]) !== 0) ) // Si ERREUR_SYSTEME_CONFIG ou ERREUR_SYSTEME_RESEAU
|
|
{
|
|
if (modele_onglets_capteurs.get(i).etat < 2) modele_onglets_capteurs.set(i, {"etat": 2}); // Coin rouge
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//=========================================================================================================
|
|
// Fonction : Récupère l'état de tous les capteurs valides dans la BDD et met à jour le modele_capteurs
|
|
//=========================================================================================================
|
|
function mise_a_jour_capteurs()
|
|
{
|
|
var req, res;
|
|
var sous_res;
|
|
var nb;
|
|
var i, j;
|
|
var actif;
|
|
var nouvelle_unite
|
|
var symbole_unite
|
|
var type_unite;
|
|
var flag_obsolete;
|
|
|
|
req = ' SELECT Cle_primaire, '; // Note : la requete est utilisée identique à la 'page_personnalisee.qml'@453 pour faciliter la recopie... Penser à porter les modifs là-bas aussi !
|
|
req += ' Etat_systeme, ';
|
|
req += ' Nom, ';
|
|
req += ' Type_entrees, ';
|
|
req += ' Entrees, ';
|
|
req += ' ID_Variable, ';
|
|
req += ' Etat, ';
|
|
req += ' (SELECT COUNT(*) FROM TB_Events WHERE Validite=1 AND Type_source=' + shipheart_source_mesure_capteur + ' AND Alarme_source>0 AND Etat_test=1 AND ID_Source=TB_Capteurs.Cle_primaire) AS Nb_alarmes, '
|
|
req += ' Valeur, ';
|
|
req += ' Precision_affichage_accueil, ';
|
|
req += ' Liste_valeurs_textes, ';
|
|
req += ' IF ( (Type_entrees=' + shipheart_capteur_type_entrees_nmea + '), ';
|
|
req += ' ( SELECT ( UNIX_TIMESTAMP() - UNIX_TIMESTAMP(Date_maj) ) ';
|
|
req += ' FROM TB_Nmea2000 WHERE ';
|
|
req += ' Pgn=SUBSTRING_INDEX(Entrees, \':\', 1) AND Field=SUBSTRING_INDEX(Entrees, \':\', -1) ), ';
|
|
// req += ' (UNIX_TIMESTAMP() - UNIX_TIMESTAMP(Date_maj)) )'; // SDIR #336
|
|
req += ' 0 )'; // SDIR #336
|
|
req += ' AS Age ';
|
|
req += ' FROM TB_Capteurs WHERE ID_Famille=' + id_groupe_capteurs + ' ';
|
|
req += ' AND Priorite_affichage_accueil>0 ';
|
|
req += ' ORDER BY Priorite_affichage_accueil, Nom';
|
|
//console.log("Requête = [ " + req + "; ]");
|
|
nb = bdd.requete(req);
|
|
|
|
for (i = 0; i < nb; i ++)
|
|
{
|
|
res = bdd.lecture_ligne();
|
|
if (!res.isEmpty)
|
|
{
|
|
flag_obsolete = false;
|
|
|
|
// Recherche des infos stockées dans la Variable pointée par ID_Variable :
|
|
sous_res = bdd.requete_unique('SELECT Unite, Conversion_unite FROM TB_Variables WHERE Cle_primaire="' + Number(res[5]) + '" ');
|
|
|
|
// Traitement des conversions d'unités :
|
|
switch(Number(sous_res[1]))
|
|
{
|
|
case shipheart_type_unite_volume:
|
|
nouvelle_unite = shipheart_unite_volume;
|
|
symbole_unite = shipheart_unite_volume_symbole;
|
|
type_unite = shipheart_type_unite_volume;
|
|
break;
|
|
case shipheart_type_unite_temperature:
|
|
nouvelle_unite = shipheart_unite_temperature;
|
|
symbole_unite = shipheart_unite_temperature_symbole;
|
|
type_unite = shipheart_type_unite_temperature;
|
|
break;
|
|
case shipheart_type_unite_latitude:
|
|
nouvelle_unite = 0;
|
|
symbole_unite = "";
|
|
type_unite = shipheart_type_unite_latitude;
|
|
break;
|
|
case shipheart_type_unite_longitude:
|
|
nouvelle_unite = 0;
|
|
symbole_unite = "";
|
|
type_unite = shipheart_type_unite_longitude;
|
|
break;
|
|
default:
|
|
nouvelle_unite = 0;
|
|
type_unite = 0;
|
|
symbole_unite = sous_res[0];
|
|
break;
|
|
}
|
|
|
|
// Cas spécifiques en fonction du type de capteur :
|
|
var chaine_valeur = Fonctions.conversion_unites( Number(res[8]), nouvelle_unite, "", Number(res[9]), type_unite);
|
|
switch(Number(res[3]))
|
|
{
|
|
//-----------------------------------------------------------------
|
|
case shipheart_capteur_type_entrees_aux:
|
|
case shipheart_capteur_type_entrees_calculee_booleen:
|
|
|
|
// Traitement des listes :
|
|
var chaines_valeurs_textes = res[10].split(';');
|
|
for (let chaine_valeur_texte of chaines_valeurs_textes)
|
|
{
|
|
var chaine = chaine_valeur_texte.split('/');
|
|
if (chaine.length === 2) // Evite de traiter les cas invalides (notamment, une chaine totalement vide qui arrive ici avec un length de 1...)
|
|
{
|
|
if (Number(res[8]) === Number(chaine [0])) // Si l'une des valeurs de la liste correspond à la valeur actuelle :
|
|
{
|
|
chaine_valeur = chaine[1]; // La valeur affichée sera le texte correspondant.
|
|
break; // Et il est inutile de chercher d'autres valeurs...
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
//-----------------------------------------------------------------
|
|
case shipheart_capteur_type_entrees_level_sensor:
|
|
break;
|
|
|
|
//-----------------------------------------------------------------
|
|
case shipheart_capteur_type_entrees_ow:
|
|
break;
|
|
|
|
//-----------------------------------------------------------------
|
|
case shipheart_capteur_type_entrees_predefinie:
|
|
break;
|
|
|
|
//-----------------------------------------------------------------
|
|
case shipheart_capteur_type_entrees_nmea:
|
|
//console.log("Capteur " + res[2] + " : durée = " + Number(res[11]) + "s (maxi = " + shipheart_periode_obsolescence_capteur_nmea + ") ")
|
|
if (Number(res[11]) > shipheart_periode_obsolescence_capteur_nmea) flag_obsolete = true;
|
|
|
|
break;
|
|
|
|
//-----------------------------------------------------------------
|
|
default :
|
|
break;
|
|
}
|
|
|
|
for (j = 0; j < modele_capteurs.count; j ++)
|
|
{
|
|
if (Number(res[0]) === modele_capteurs.get(j).Cle_primaire)
|
|
{
|
|
modele_capteurs.set(j, {
|
|
"Etat_systeme": Number(res[1]),
|
|
"Nom": res[2],
|
|
"Valeur": chaine_valeur +"", // Le ' + "" ' permet de s'assurer que c'est toujours une STRING, même quand c'est une valeur numérique (le modèle n'accepte pas d'avoir un coup des STRING, un coup des NUM...)
|
|
"Unite": symbole_unite,
|
|
"Obsolete": flag_obsolete,
|
|
"Etat": Number(res[7]),
|
|
"Etat_capteur": Number(res[6]) });
|
|
break; // Si on a trouvé l'entrée du modèle correspondant au capteur en cours de traitement depuis la BDD, on sort de la boucle sur le modèle (mais on continue la boucle sur les résultats de la requete !)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//=================================================================================================
|
|
// Fonction : mise à jour du modèle des onglets de pages
|
|
//=================================================================================================
|
|
function init_pages()
|
|
{
|
|
var req, res;
|
|
var nb;
|
|
var i;
|
|
|
|
modele_onglets_pages.clear();
|
|
|
|
req = 'SELECT Cle_primaire, Nom, type FROM TB_Pages WHERE Priorite_affichage>0 ORDER BY Priorite_affichage ';
|
|
//console.log("Requête = [" + req + "]");
|
|
nb = bdd.requete(req);
|
|
for (i = 0; i < nb; i ++)
|
|
{
|
|
res = bdd.lecture_ligne();
|
|
if (!res.isEmpty)
|
|
{
|
|
modele_onglets_pages.append({
|
|
"libelle": res[1],
|
|
"id": Number(res[0]),
|
|
"type": Number(res[2]),
|
|
"actif": false,
|
|
"etat": 0 });
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//=========================================================================================================
|
|
// Fonction : Récupère l'état des réseaux et formate le message à afficher dans la boite de dialogue
|
|
//=========================================================================================================
|
|
function maj_message_reseaux()
|
|
{
|
|
var req, res;
|
|
var nb;
|
|
var i;
|
|
var msg = "";
|
|
var etat_gnss;
|
|
var siv; // Satellites in view
|
|
var adresse;
|
|
var cde;
|
|
var bssid;
|
|
var nom;
|
|
var canal;
|
|
var qualite;
|
|
|
|
|
|
// msg += "<table border='1' width='100%'>";
|
|
msg += "<table width='100%'>";
|
|
msg += "<tbody>";
|
|
|
|
//-----------------------------------------------------------------------
|
|
// GNSS :
|
|
req = 'SELECT Valeur FROM TB_Systeme WHERE Nom="Etat_gnss" ';
|
|
res = bdd.requete_unique(req);
|
|
etat_gnss = Number(res[0]);
|
|
|
|
req = 'SELECT Valeur FROM TB_Capteurs WHERE Adresse_module=0 AND ';
|
|
req += ' Type_entrees=' + shipheart_capteur_type_entrees_predefinie + ' ';
|
|
req += ' AND Entrees=' + shipheart_capteur_predefini_siv + ' ';
|
|
res = bdd.requete_unique(req);
|
|
siv = Number(res[0]);
|
|
|
|
msg += "<tr>";
|
|
|
|
msg += "<td width='35%'>";
|
|
msg += "GNSS :";
|
|
msg += "</td>";
|
|
|
|
msg += "<td>";
|
|
if (etat_gnss === 0) msg += qsTr("Déconnecté");
|
|
else msg += qsTr("Nombre de satellites visibles");
|
|
msg += "</td>";
|
|
|
|
msg += "<td align='center'>";
|
|
if (etat_gnss !== 0) msg += siv;
|
|
msg += "</td>";
|
|
|
|
msg += "</tr>";
|
|
//-----------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------
|
|
msg += "<tr></tr>";
|
|
//-----------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------
|
|
// Ethernet :
|
|
req = 'SELECT Valeur FROM TB_Systeme WHERE Nom="Adresse_ip_ethernet" ';
|
|
res = bdd.requete_unique(req);
|
|
adresse = res[0];
|
|
|
|
msg += "<tr>";
|
|
|
|
msg += "<td>";
|
|
msg += "Ethernet :";
|
|
msg += "</td>";
|
|
|
|
msg += "<td>";
|
|
if (adresse === shipheart_adresse_ip_inconnue)
|
|
{
|
|
msg += qsTr("Déconnecté");
|
|
}
|
|
else
|
|
{
|
|
msg += qsTr("Connecté");
|
|
}
|
|
msg += "</td>";
|
|
|
|
msg += "<td align='center'>";
|
|
msg += adresse;
|
|
msg += "</td>";
|
|
|
|
msg += "</tr>";
|
|
//-----------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------
|
|
msg += "<tr></tr>";
|
|
//-----------------------------------------------------------------------
|
|
|
|
|
|
//-----------------------------------------------------------------------
|
|
// Wifi STA :
|
|
req = 'SELECT Valeur FROM TB_Configuration WHERE Nom="Wifi_sta_cde" ';
|
|
res = bdd.requete_unique(req);
|
|
cde = Number(res[0]);
|
|
|
|
req = 'SELECT Valeur FROM TB_Configuration WHERE Nom="BSSID_Wifi_sta" ';
|
|
res = bdd.requete_unique(req);
|
|
bssid = res[0];
|
|
|
|
req = 'SELECT Valeur FROM TB_Systeme WHERE Nom="Adresse_ip_wifi_sta" ';
|
|
res = bdd.requete_unique(req);
|
|
adresse = res[0];
|
|
|
|
req = 'SELECT Nom, Canal, Qualite FROM TB_Wifi_sta WHERE Bssid="' + bssid + '" ';
|
|
res = bdd.requete_unique(req);
|
|
nom = res[0];
|
|
canal = Number(res[1]);
|
|
qualite = Number(res[2]);
|
|
|
|
msg += "<tr>";
|
|
|
|
msg += "<td>";
|
|
msg += "Wifi (STAtion) :";
|
|
msg += "</td>";
|
|
|
|
msg += "<td>";
|
|
if (cde === 0)
|
|
{
|
|
msg += qsTr("OFF");
|
|
}
|
|
else
|
|
{
|
|
if (adresse === shipheart_adresse_ip_inconnue)
|
|
{
|
|
msg += qsTr("ON") + "<br />"; // Si on est Connecté, on affiche pas le ON...
|
|
}
|
|
else
|
|
{
|
|
msg += qsTr("Connecté") + "<br />";
|
|
}
|
|
msg += nom + "<br />";
|
|
msg += ((canal < 20) ? "2.4GHz" : "5GHz") + " - Channel " + canal + "<br />";
|
|
msg += qsTr("Niveau ") + qualite + " %";
|
|
}
|
|
msg += "</td>";
|
|
|
|
msg += "<td align='center'>";
|
|
if (cde !== 0) // Si la commande est OFF, on n'affiche rien dans la colonne d'adresses
|
|
{
|
|
if (adresse === shipheart_adresse_ip_inconnue) msg += qsTr("Déconnecté");
|
|
else msg += adresse;
|
|
}
|
|
msg += "</td>";
|
|
|
|
msg += "</tr>";
|
|
//-----------------------------------------------------------------------
|
|
|
|
|
|
//-----------------------------------------------------------------------
|
|
msg += "<tr></tr>";
|
|
//-----------------------------------------------------------------------
|
|
|
|
|
|
//-----------------------------------------------------------------------
|
|
// Wifi AP :
|
|
req = 'SELECT Valeur FROM TB_Configuration WHERE Nom="Wifi_ap_cde" ';
|
|
res = bdd.requete_unique(req);
|
|
cde = Number(res[0]);
|
|
|
|
req = 'SELECT Valeur FROM TB_Configuration WHERE Nom="Wifi_ap_ssid" ';
|
|
res = bdd.requete_unique(req);
|
|
nom = res[0];
|
|
|
|
req = 'SELECT Valeur FROM TB_Configuration WHERE Nom="Wifi_ap_canal" ';
|
|
res = bdd.requete_unique(req);
|
|
canal = res[0];
|
|
|
|
req = 'SELECT Valeur FROM TB_Systeme WHERE Nom="Adresse_ip_wifi_ap" ';
|
|
res = bdd.requete_unique(req);
|
|
adresse = res[0];
|
|
|
|
msg += "<tr>";
|
|
|
|
msg += "<td>";
|
|
msg += "Wifi (Access Point) :";
|
|
msg += "</td>";
|
|
|
|
msg += "<td>";
|
|
if (cde === 0)
|
|
{
|
|
msg += qsTr("OFF");
|
|
}
|
|
else
|
|
{
|
|
if (adresse === shipheart_adresse_ip_inconnue)
|
|
{
|
|
msg += qsTr("ON") + "<br />"; // Si on est Connecté, on affiche pas le ON...
|
|
}
|
|
else
|
|
{
|
|
msg += qsTr("Actif") + "<br />";
|
|
}
|
|
msg += nom + "<br />";
|
|
msg += ((canal < 20) ? "2.4GHz" : "5GHz") + " - Channel " + canal + "<br />";
|
|
}
|
|
msg += "</td>";
|
|
|
|
msg += "<td align='center'>";
|
|
if (cde !== 0) // Si la commande est OFF, on n'affiche rien dans la colonne d'adresses
|
|
{
|
|
if (adresse === shipheart_adresse_ip_inconnue) msg += qsTr("Inactif");
|
|
else msg += adresse;
|
|
}
|
|
msg += "</td>";
|
|
|
|
msg += "</tr>";
|
|
//-----------------------------------------------------------------------
|
|
|
|
|
|
msg += "</tbody>";
|
|
msg += "</table>";
|
|
|
|
return(msg);
|
|
}
|
|
|
|
|
|
//=================================================================================================
|
|
// Fonction : Vérifie si un message utilisateur valide existe dans la table TB_Messages_users. Si oui,
|
|
// la fonction appelle la boite de dialogue correspondant à ce message et attend une action
|
|
// de l'utilisateur en fonction du type de message.
|
|
//=================================================================================================
|
|
function lecture_messages_users()
|
|
{
|
|
var req, res;
|
|
var i, nb;
|
|
var flag_ouverture_boite_dialogue;
|
|
|
|
req = 'SELECT Cle_primaire, Code, Parametres, Niveau FROM TB_Messages_users ';
|
|
req += ' WHERE Date_validite<=NOW() AND Nb_reports<' + shipheart_message_users_max_nombre_reports + ' ';
|
|
req += ' ORDER BY Niveau DESC, Cle_primaire DESC LIMIT 1';
|
|
res = bdd.requete_unique(req); // L'utilisation de 'requete_unique' est possible puisqu'elle contient LIMIT 1.
|
|
|
|
id_message_users = Number(res[0]);
|
|
message_users_code = Number(res[1]);
|
|
boite_message_user.niveau = Number(res[3]);
|
|
|
|
boite_message_user.message = maj_texte_messages_users(message_users_code, res[2]);
|
|
|
|
// Valeurs par défaut :
|
|
boite_message_user.boutonOk = true; // On est obligé de le mettre à jour après avant chaque appel car il a pû être mis à faux dans certains cas auparavant
|
|
boite_message_user.progressBarValid = false; // Même commentaire...
|
|
flag_ouverture_boite_dialogue = true; // Plus facile à coder...
|
|
|
|
// Valeurs spécifiques au message en cours :
|
|
switch(message_users_code)
|
|
{
|
|
//-----------------------------------------------------------------------------------------
|
|
case shipheart_message_users_code_aucun:
|
|
flag_ouverture_boite_dialogue = false;
|
|
break;
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
case shipheart_message_users_code_fin_minuteur:
|
|
boite_message_user.imageTitreSource = "/images/sablier.png"
|
|
break;
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
case shipheart_message_users_code_reveil:
|
|
boite_message_user.imageTitreSource = "/images/reveil.png"
|
|
break;
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
case shipheart_message_users_code_maj_en_cours:
|
|
boite_message_user.imageTitreSource = "/images/cycle.png"
|
|
boite_message_user.progressBarValid = true;
|
|
boite_message_user.progressBarValue = 0;
|
|
boite_message_user.boutonOk = false;
|
|
break;
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
case shipheart_message_users_code_redemarrage:
|
|
boite_message_user.imageTitreSource = "/images/reset.png"
|
|
boite_message_user.boutonOk = false;
|
|
break;
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
case shipheart_message_users_code_nouvelle_version_detectee:
|
|
boite_message_user.imageTitreSource = "/images/ampoule.png"
|
|
break;
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
case shipheart_message_users_code_defaut_config_k_bus:
|
|
boite_message_user.imageTitreSource = "/images/attention.png"
|
|
break;
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
case shipheart_message_users_code_declenchement_event:
|
|
boite_message_user.imageTitreSource = "/images/event.png"
|
|
break;
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
default :
|
|
console.log("Message reçu inconnu (code = " + message_users_code + ")");
|
|
flag_ouverture_boite_dialogue = false;
|
|
break;
|
|
}
|
|
|
|
if (flag_ouverture_boite_dialogue)
|
|
{
|
|
mise_en_veille(0); // Si un message user arrive, on sort de veille (utile si on y était...)
|
|
boite_message_user.open();
|
|
}
|
|
}
|
|
|
|
|
|
//=================================================================================================
|
|
// Fonction : Met à jour les paramètres du message user lorsqu'il est en cours d'affichage
|
|
//=================================================================================================
|
|
function maj_messages_users()
|
|
{
|
|
var req, res, nb;
|
|
var i;
|
|
|
|
// Lecture de l'état actuel du message :
|
|
req = 'SELECT Parametres, Niveau FROM TB_Messages_users WHERE Cle_primaire='+ id_message_users + ' ';
|
|
nb = bdd.requete(req);
|
|
|
|
// Mise à jour du message :
|
|
if (nb > 0) // Si le message existe toujours :
|
|
{
|
|
res = bdd.lecture_ligne(); // Lecture des données
|
|
boite_message_user.niveau = Number(res[1]);
|
|
boite_message_user.message = maj_texte_messages_users(message_users_code, res[0]);
|
|
boite_message_user.progressBarValue = maj_progressbar_message_users(message_users_code, res[0]);
|
|
}
|
|
else // Si le message a été supprimé (cas de l'appli, juste avant redémarrage)
|
|
{
|
|
message_users_code = shipheart_message_users_code_aucun;
|
|
boite_message_user.progressBarValid = false; // Dans le doute, pour que le prochain appel n'affiche pas la ProgressBar si elle n'est pas demandée...
|
|
boite_message_user.close();
|
|
}
|
|
}
|
|
|
|
|
|
//=================================================================================================
|
|
// Fonction : Calcule le texte à afficher en fonction du code du message et de la valeur courante
|
|
// de ses paramètres.
|
|
//=================================================================================================
|
|
function maj_texte_messages_users(code, parametres)
|
|
{
|
|
var texte = "";
|
|
var params;
|
|
var req, res;
|
|
|
|
switch(code)
|
|
{
|
|
//-----------------------------------------------------------------------------------------
|
|
case shipheart_message_users_code_aucun:
|
|
break;
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
case shipheart_message_users_code_fin_minuteur:
|
|
texte = qsTr("<b>%1</b>").arg(parametres);
|
|
break;
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
case shipheart_message_users_code_reveil:
|
|
texte = qsTr("<b>%1</b>").arg(parametres);
|
|
break;
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
case shipheart_message_users_code_maj_en_cours: // Valeur = 2
|
|
params = parametres.split(';'); // Paramètres = 'no_module';'avancement_en_%' (no_module: -1=démarrage, 0-N=No_module en cours, -2=fin)
|
|
|
|
switch (Number(params[0]))
|
|
{
|
|
//----------------------
|
|
// Début de chargement :
|
|
case -1:
|
|
texte = qsTr("Démarrage");
|
|
break;
|
|
|
|
//----------------------------------
|
|
// Chargement en cours d'un module :
|
|
default:
|
|
|
|
// Récupération du type de carte à partir de son adresse reçue depuis l'Appli :
|
|
var libelle_module;
|
|
req = 'SELECT Type FROM TB_Modules_physiques WHERE Adresse_k_bus=' + Number(params[0]) + ' ';
|
|
res = bdd.requete_unique(req);
|
|
|
|
switch(Number(res[0]))
|
|
{
|
|
case shipheart_type_module_shipbase:
|
|
libelle_module = qsTr("Firmware de <b>ShipBase</b>");
|
|
break;
|
|
case shipheart_type_module_shippower812:
|
|
libelle_module = qsTr("Firmware du <b>ShipPower812</b> à l'adresse <b>%1</b>").arg(Number(params[0]));
|
|
break;
|
|
case shipheart_type_module_shipBS:
|
|
libelle_module = qsTr("Firmware du <b>ShipBS</b> à l'adresse <b>%1</b>").arg(Number(params[0]));
|
|
break;
|
|
case shipheart_type_module_shippower4AC:
|
|
libelle_module = qsTr("Firmware du <b>ShipPower4AC</b> à l'adresse <b>%1</b>").arg(Number(params[0]));
|
|
break;
|
|
case shipheart_type_module_shippower8DC:
|
|
libelle_module = qsTr("Firmware du <b>ShipPower8DC</b> à l'adresse <b>%1</b>").arg(Number(params[0]));
|
|
break;
|
|
default:
|
|
libelle_module = qsTr("Firmware du module à l'adresse <b>%1</b>").arg(Number(params[0]));
|
|
break;
|
|
}
|
|
|
|
// Génération du texte du message :
|
|
texte = libelle_module + "<br />";
|
|
// if (Number(params[1]) === 0) texte += qsTr("Démarrage"); // SDIR #257
|
|
|
|
// Ajout de la seconde partie du texte, commune à tous les cas :
|
|
texte += qsTr("Merci de patienter et de ne rien débrancher<br />avant la fin de la mise à jour.");
|
|
break;
|
|
|
|
//---------------------
|
|
// Fin de chargement :
|
|
case -2:
|
|
boite_message_user.progressBarValid = false; // Suppression de la barre de progression
|
|
|
|
texte = qsTr("Chargement des mises à jour effectué avec succès !<br /><br />L'activation des nouvelles version est en cours sur tous les modules concernés.<br /><br />Merci de patienter encore quelques secondes...");
|
|
break;
|
|
}
|
|
break;
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
case shipheart_message_users_code_redemarrage:
|
|
texte = qsTr("ShipHeart va redémarrer.<br /><br />Cette opération va prendre quelques dizaines de secondes.<br />Merci de patienter...");
|
|
break;
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
case shipheart_message_users_code_nouvelle_version_detectee:
|
|
let versions = parametres.split(';'); // Séparation de l'ancienne et de la nouvelle version
|
|
texte = qsTr("Votre système ShipHeart est dorénavant équipé de la version<br /><br /><b>%1</b><br /><br />(la version précédente était la %2)").arg(versions[1]).arg(versions[0]);
|
|
break;
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
case shipheart_message_users_code_defaut_config_k_bus:
|
|
params = parametres.split(';'); // Séparation de 'adresse_k_bus du premier module Nok';'Type_module_physique à cette adresse (yc -1 pour type inconnu)';'Type module configuré'
|
|
|
|
if (Number(params[1]) === shipheart_type_module_inconnu) // A priori, le réseau ext 'coupé' juste avant ADRESSE
|
|
{
|
|
var emplacement_1 = ""
|
|
req = 'SELECT Type, Emplacement FROM TB_Modules_config WHERE Adresse_k_bus=' + (Number(params[0]) - 1) + ' ';
|
|
//console.log("Requête = [" + req + "]");
|
|
res = bdd.requete_unique(req);
|
|
var type_1 = Fonctions.nom_type_module(Number(res[0]));
|
|
if (typeof res[1] !== 'undefined') emplacement_1 = res[1];
|
|
|
|
|
|
var emplacement_2 = ""
|
|
req = 'SELECT Type, Emplacement FROM TB_Modules_config WHERE Adresse_k_bus=' + Number(params[0]) + ' ';
|
|
//console.log("Requête = [" + req + "]");
|
|
res = bdd.requete_unique(req);
|
|
var type_2 = Fonctions.nom_type_module(Number(params[2]));
|
|
if (typeof res[1] !== 'undefined') emplacement_2 = res[1];
|
|
|
|
texte = qsTr("Le nombre de modules détectés sur le réseau ShipHeart est insuffisant par rapport à la configuration du bateau.<br /><br />Vérifiez les connexions entre le module <b>%1</b> à la <b>position @%2</b> %3 et le module <b>%4</b> suivant%5<br /><br />Vous pouvez visualiser l'état complet du réseau ShipHeart et les anomalies détectées dans le menu 'Réseau > ShipHeart' dans les Paramètres Avancés").arg(type_1).arg(Number(params[0]) - 1).arg(emplacement_1 === "" ? "" : "[" + emplacement_1 + "]").arg(type_2).arg(emplacement_2 === "" ? "." : " [" + emplacement_2 + "]");
|
|
}
|
|
else
|
|
{
|
|
texte = qsTr("Le modules détecté en <b>position @%1</b> est un <b>%2</b>. Cela ne correspond pas à la configuration actuelle du bateau (<b>%3</b>).<br /><br />Cela peut provenir de l'ajout, de la suppression ou d'un déplacement de module.<br /><br />Vous pouvez visualiser toutes les anomalies détectées et les corriger dans le menu 'Réseau > ShipHeart' dans les Paramètres Avancés").arg(Number(params[0])).arg(Fonctions.nom_type_module(Number(params[1]))).arg(Fonctions.nom_type_module(Number(params[2])));
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
case shipheart_message_users_code_declenchement_event:
|
|
|
|
req = 'SELECT Nom, Texte_message FROM TB_Events WHERE Cle_primaire=' + Number(parametres) + ' ';
|
|
//console.log("Requête = [" + req + "]");
|
|
res = bdd.requete_unique(req);
|
|
|
|
texte = qsTr("<b>%1</b>").arg(res[0]);
|
|
if (res[1] !== "") texte += "<br /><br />" + res[1];
|
|
|
|
break;
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
default :
|
|
texte = qsTr("Code inconnu");
|
|
break;
|
|
}
|
|
return (texte);
|
|
}
|
|
|
|
|
|
//=================================================================================================
|
|
// Fonction : Calcule les paramètres de la barre d'avancement du message user.
|
|
//=================================================================================================
|
|
function maj_progressbar_message_users(code, parametres)
|
|
{
|
|
var valeur = 0;
|
|
var params;
|
|
|
|
switch(code)
|
|
{
|
|
//-----------------------------------------------------------------------------------------
|
|
case shipheart_message_users_code_maj_en_cours:
|
|
params = parametres.split(';'); // Paramètres = 'no_module';'avancement_en_%' (no_module: -1=démarrage, 0-N=No_module en cours, -2=fin)
|
|
valeur = Number(params[1]) / 100 ;
|
|
//console.log("Nouvelle valeur de Progress Bar = " + valeur);
|
|
|
|
break;
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
case shipheart_message_users_code_aucun:
|
|
case shipheart_message_users_code_fin_minuteur:
|
|
case shipheart_message_users_code_reveil:
|
|
case shipheart_message_users_code_redemarrage:
|
|
case shipheart_message_users_code_nouvelle_version_detectee:
|
|
case shipheart_message_users_code_defaut_config_k_bus:
|
|
case shipheart_message_users_code_declenchement_event:
|
|
default :
|
|
|
|
break;
|
|
}
|
|
|
|
return(valeur);
|
|
}
|
|
|
|
|
|
//=================================================================================================
|
|
// Fonction : Appelée lorsque l'utilisateur à cliqué dans l'un des boutons de la boite de dialogue.
|
|
//=================================================================================================
|
|
function acquittement_message_users(retour)
|
|
{
|
|
var req, res;
|
|
var i, nb;
|
|
var duree_report;
|
|
|
|
// Note : l'acquittement d'une boite de dialogue se fait en cliquant sur l'un de ses boutons.
|
|
// Ce clic génère un bip (cf 'Shipheart_boite_dialogue.qml' ==> 'shipheart_clic()' ==> 'emission_bip()')
|
|
// Ce bip annule la séquence sonore en cours.
|
|
// Lors de l'acquittement d'une message user, il n'est donc pas nécessaire de demander la fin d'une
|
|
// éventuelle boucle sonore car elle est, dans tous les cas arrêtée...
|
|
|
|
switch(message_users_code)
|
|
{
|
|
//-----------------------------------------------------------------------------------------
|
|
case shipheart_message_users_code_aucun:
|
|
break;
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
case shipheart_message_users_code_fin_minuteur:
|
|
case shipheart_message_users_code_reveil:
|
|
case shipheart_message_users_code_maj_en_cours:
|
|
case shipheart_message_users_code_redemarrage:
|
|
case shipheart_message_users_code_nouvelle_version_detectee:
|
|
case shipheart_message_users_code_defaut_config_k_bus:
|
|
case shipheart_message_users_code_declenchement_event:
|
|
switch(retour)
|
|
{
|
|
//......................................
|
|
case shipheart_boite_dialogue_bouton_1:
|
|
// Suppression du message :
|
|
req = 'DELETE FROM TB_Messages_users WHERE Cle_primaire=' + id_message_users + ' ';
|
|
//console.log("Requête = [" + req + "]");
|
|
bdd.requete_unique(req);
|
|
|
|
// Dans le doute, remise à Normal l'état de la LED enface avant :
|
|
req = "UPDATE TB_Modules_config SET New_cde='" + shipheart_commande_module_etat_systeme + "/" + shipheart_commande_module_etat_systeme_normal + "' WHERE Adresse_k_bus=0 ";
|
|
bdd.requete_unique(req);
|
|
|
|
break;
|
|
|
|
//......................................
|
|
default:
|
|
console.log("Valeur de retour de la boite de dialogue invalide [ " + retour + "]. Aucun traitement n'est effectué");
|
|
break;
|
|
}
|
|
break;
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
default:
|
|
console.log("Valeur de 'message_user_code' invalide [" + message_users_code + "]. La valeur est remise à AUCUN");
|
|
break;
|
|
}
|
|
|
|
message_users_code = shipheart_message_users_code_aucun;
|
|
}
|
|
|
|
//=================================================================================================
|
|
// Fonction appelée lorsque le minuteur a décompté la totalité de sa temporisation
|
|
//=================================================================================================
|
|
function traitement_fin_minuteur()
|
|
{
|
|
var req, res;
|
|
var libelle_compteur_initial;
|
|
|
|
etat_minuteur = 0; // Permet de remettre le minuteur en attente d'une prochaine commande
|
|
|
|
libelle_compteur_initial = Math.trunc(compteur_initial_minuteur / (60 * 60)).toString().padStart(2, '0')
|
|
+ ":" + Math.trunc((compteur_initial_minuteur / 60) % 60).toString().padStart(2, '0')
|
|
+ ":" + Math.trunc(compteur_initial_minuteur % 60).toString().padStart(2, '0');
|
|
|
|
req = "INSERT INTO TB_Messages_users (Code, Parametres, Niveau) VALUES (" + shipheart_message_users_code_fin_minuteur + ", '" + libelle_compteur_initial + "', 1)";
|
|
bdd.requete_unique(req);
|
|
|
|
compteur_initial_minuteur = 0; // Pour prochaine utilisation
|
|
|
|
// req = "UPDATE TB_Systeme SET Valeur='button-35.mp3/5/15/20' WHERE Nom='New_bip'"; // 20 x 1.5s = 30s
|
|
// req = "UPDATE TB_Systeme SET Valeur='button-32.mp3/2/50/6' WHERE Nom='New_bip'"; // 6 x 5.0s = 30s
|
|
req = "UPDATE TB_Systeme SET Valeur='beep-027.mp3/2/10/30' WHERE Nom='New_bip'"; // 30 x 1.0s = 30s
|
|
// req = "UPDATE TB_Systeme SET Valeur='beep-28.mp3/6/20/15' WHERE Nom='New_bip'"; // 20 x 1.5s = 30s
|
|
bdd.requete_unique(req);
|
|
//console.log("Requête = " + req)
|
|
synchro_bdd(shipheart_type_synchro_data);
|
|
//console.log("Requête = " + req)
|
|
|
|
}
|
|
|
|
//=================================================================================================
|
|
// Fonction appelée lorsqu'un réveil se déclenche
|
|
//=================================================================================================
|
|
function traitement_declenchement_reveil(jour_semaine, heure, minute)
|
|
{
|
|
var req;
|
|
|
|
|
|
req = 'INSERT INTO TB_Messages_users (Code, Parametres, Niveau) VALUES (';
|
|
req += ' ' + shipheart_message_users_code_reveil + ', ';
|
|
req += ' "' + Fonctions_date_heure.nom_jour_semaine(jour_semaine) + "<br /><br />" + Fonctions_date_heure.nom_heure(heure, minute) + '", ';
|
|
req += ' 1)';
|
|
//console.log("Requête = " + req)
|
|
bdd.requete_unique(req);
|
|
|
|
req = "UPDATE TB_Systeme SET Valeur='button-35.mp3/5/15/20' WHERE Nom='New_bip'"; // 20 x 1.5s = 30s
|
|
// req = "UPDATE TB_Systeme SET Valeur='button-32.mp3/2/50/6' WHERE Nom='New_bip'"; // 6 x 5.0s = 30s
|
|
// req = "UPDATE TB_Systeme SET Valeur='beep-027.mp3/2/10/30' WHERE Nom='New_bip'"; // 30 x 1.0s = 30s
|
|
// req = "UPDATE TB_Systeme SET Valeur='beep-28.mp3/6/20/15' WHERE Nom='New_bip'"; // 20 x 1.5s = 30s
|
|
bdd.requete_unique(req);
|
|
//console.log("Requête = " + req)
|
|
synchro_bdd(shipheart_type_synchro_data);
|
|
//console.log("Requête = " + req)
|
|
|
|
}
|
|
|
|
|
|
//=================================================================================================
|
|
// Fonction de tâche de fond, appelée chaque seconde, quelle que soit la page affichée.
|
|
// Cette fonction étant toujours active, même quand la page n'est pas affichée, fait qu'il est prudent
|
|
// de ne pas trop la charger...
|
|
//=================================================================================================
|
|
function tache_de_fond()
|
|
{
|
|
|
|
//----------------------------------------------------
|
|
// Chaque seconde :
|
|
//----------------------------------------------------
|
|
|
|
//------------------------------------------------
|
|
// Message de console toutes les secondes (debug) :
|
|
let date = new Date().toLocaleString();
|
|
let msg = "[" + date + "] ";
|
|
msg += "Prof. stackView = " + stackView.depth;
|
|
msg += ", compt. économiseur = " + shipheart_compteur_economiseur;
|
|
msg += ", compt. TO niv. acces = " + shipheart_compteur_time_out_niveau_acces;
|
|
//msg += ", niv. acces en cours = " + shipheart_niveau_acces_en_cours;
|
|
//msg += ", TO niv. acces = " + shipheart_time_out_niveau_acces;
|
|
console.log(msg);
|
|
|
|
|
|
//----------------------------------------------------
|
|
// Chaque minute (synchronisé sur un nombre défini de secondes) :
|
|
//----------------------------------------------------
|
|
if (flag_init_tache_de_fond) // Exécuté une seule fois, au démarrage, pour ne pas avoir à attendre [0; 59s] avant de traiter les taches de fond...
|
|
{
|
|
tache_de_fond_30(); // Il est important que le traitement @30s soit fait AVANT celui @00 car il met à jour les heures solaires dont 'check_reveils()' a besoin.
|
|
tache_de_fond_00();
|
|
flag_init_tache_de_fond = false; // Ce flag n'est utilisé qu'une fois au démarrage
|
|
}
|
|
else // Cas normal :
|
|
{
|
|
var now_systeme = new Date;
|
|
if (now_systeme.getSeconds() === 0) tache_de_fond_00();
|
|
else if (now_systeme.getSeconds() === 30) tache_de_fond_30();
|
|
}
|
|
}
|
|
|
|
|
|
//=================================================================================================
|
|
// Fonction appelée chaque minute par la tâche de fond, à xx minutes et 00 secondes.
|
|
//=================================================================================================
|
|
function tache_de_fond_00()
|
|
{
|
|
var req, res;
|
|
var commande;
|
|
|
|
//console.log("Traitement de la tâche de fond 00")
|
|
|
|
// Traitement des réveils :
|
|
check_reveils();
|
|
// ATTENTION : appeler cette fonction AVANT la mise à jour de l'heure qui suit car celle-ci peut générer des écarts de 1 seconde
|
|
// et faire déclencher en double des réveils. En effet, le déclenchement de la minute ci-dessus donne par exemple 14:42:00 et
|
|
// le calcul dans 'check_reveils()' peut donner (après mise à jour ci-dessous) 14:41:59. Dans un tel cas, le réveil qui déclenche
|
|
// à 14:41 sera traité deux fois (à 14:41:00 et 14:41:59).
|
|
|
|
// Fonction de mise à l'heure (pour ShipRs seulement) : SDIR #210
|
|
if (shipheart_type_installation !== shipheart_type_installation_shipbase)
|
|
{
|
|
req = 'SELECT Date_maj FROM TB_Systeme WHERE Nom="Heart_beat" ';
|
|
res = bdd.requete_unique(req);
|
|
commande = 'sudo date -s "' + res[0] + '" ';
|
|
systeme.commande_shell(commande, "");
|
|
//console.log("Commande shell : [" + commande + "]");
|
|
}
|
|
}
|
|
|
|
//=================================================================================================
|
|
// Fonction appelée chaque minute par la tâche de fond, à xx minutes et 30 secondes.
|
|
//=================================================================================================
|
|
function tache_de_fond_30()
|
|
{
|
|
var req, res;
|
|
var altitude = 0;
|
|
|
|
//console.log("Traitement de la tâche de fond 30")
|
|
|
|
//------------------------------------------------
|
|
// Récupération de la position du bateau :
|
|
// Latitude :
|
|
req = 'SELECT Valeur, Precision_affichage_accueil FROM TB_Capteurs WHERE Adresse_module=0 AND ';
|
|
req += ' Type_entrees=' + shipheart_capteur_type_entrees_predefinie + ' ';
|
|
req += ' AND Entrees=' + shipheart_capteur_predefini_lat + ' ';
|
|
res = bdd.requete_unique(req);
|
|
shipheart_latitude = Number(res[0]);
|
|
|
|
// Longitude :
|
|
req = 'SELECT Valeur, Precision_affichage_accueil FROM TB_Capteurs WHERE Adresse_module=0 AND ';
|
|
req += ' Type_entrees=' + shipheart_capteur_type_entrees_predefinie + ' ';
|
|
req += ' AND Entrees=' + shipheart_capteur_predefini_lon + ' ';
|
|
res = bdd.requete_unique(req);
|
|
shipheart_longitude = Number(res[0]);
|
|
|
|
//------------------------------------------------
|
|
// Mise à jour des heures solaires :
|
|
var sun_times = Suncalc.SunCalc.getTimes(Fonctions_date_heure.date_courante(null, shipheart_fuseau_horaire, shipheart_heure_ete), shipheart_latitude, shipheart_longitude, altitude);
|
|
|
|
// Aube nautique :
|
|
shipheart_heure_aube_nautique = Fonctions_date_heure.conversion_heure_minutes_locales(sun_times.nauticalDawn.getHours(), sun_times.nauticalDawn.getMinutes(), shipheart_fuseau_horaire, shipheart_heure_ete)
|
|
req = 'UPDATE TB_Systeme SET Valeur="' + shipheart_heure_aube_nautique + '" WHERE Nom="Aube_nautique" ';
|
|
//console.log("Requête = [" + req + "]");
|
|
bdd.requete_unique(req);
|
|
|
|
// Lever_soleil :
|
|
shipheart_heure_lever_soleil = Fonctions_date_heure.conversion_heure_minutes_locales(sun_times.sunrise.getHours(), sun_times.sunrise.getMinutes(), shipheart_fuseau_horaire, shipheart_heure_ete)
|
|
req = 'UPDATE TB_Systeme SET Valeur="' + shipheart_heure_lever_soleil + '" WHERE Nom="Lever_soleil" ';
|
|
//console.log("Requête = [" + req + "]");
|
|
bdd.requete_unique(req);
|
|
|
|
// Zenith :
|
|
shipheart_heure_zenith = Fonctions_date_heure.conversion_heure_minutes_locales(sun_times.solarNoon.getHours(), sun_times.solarNoon.getMinutes(), shipheart_fuseau_horaire, shipheart_heure_ete)
|
|
req = 'UPDATE TB_Systeme SET Valeur="' + shipheart_heure_zenith + '" WHERE Nom="Zenith" ';
|
|
//console.log("Requête = [" + req + "]");
|
|
bdd.requete_unique(req);
|
|
|
|
// Coucher_soleil :
|
|
shipheart_heure_coucher_soleil = Fonctions_date_heure.conversion_heure_minutes_locales(sun_times.sunset.getHours(), sun_times.sunset.getMinutes(), shipheart_fuseau_horaire, shipheart_heure_ete)
|
|
req = 'UPDATE TB_Systeme SET Valeur="' + shipheart_heure_coucher_soleil + '" WHERE Nom="Coucher_soleil" ';
|
|
//console.log("Requête = [" + req + "]");
|
|
bdd.requete_unique(req);
|
|
|
|
// Crepuscule_nautique :
|
|
shipheart_heure_crepuscule_nautique = Fonctions_date_heure.conversion_heure_minutes_locales(sun_times.nauticalDusk.getHours(), sun_times.nauticalDusk.getMinutes(), shipheart_fuseau_horaire, shipheart_heure_ete)
|
|
req = 'UPDATE TB_Systeme SET Valeur="' + shipheart_heure_crepuscule_nautique + '" WHERE Nom="Crepuscule_nautique" ';
|
|
//console.log("Requête = [" + req + "]");
|
|
bdd.requete_unique(req);
|
|
|
|
//------------------------------------------------
|
|
// Demande de reconnaissance réseau OW :
|
|
req = 'UPDATE TB_Systeme SET Valeur=1 WHERE Nom="Demande_decouverte_ow" ';
|
|
//console.log("req =" + req);
|
|
bdd.requete_unique(req);
|
|
}
|
|
|
|
|
|
//=================================================================================================
|
|
// Fonction appelée chaque minute par la tâche de fond.
|
|
// Charge la valeur de 'TB_Configuration.Reveils' et compare chacune de ses entrées avec l'heure en cours.
|
|
// Si une condition de match est trouvée, un message et un son dédié sont créés.
|
|
//=================================================================================================
|
|
function check_reveils()
|
|
{
|
|
var req, res;
|
|
var i;
|
|
var conditions;
|
|
var condition
|
|
var jour;
|
|
var heure;
|
|
var minute;
|
|
var validite;
|
|
|
|
reveils_next_jour = 0;
|
|
|
|
req = 'SELECT Valeur FROM TB_Configuration WHERE Nom="Reveils" ';
|
|
//console.log("Requête = [ " + req + '; ]')
|
|
res = bdd.requete_unique(req);
|
|
var conditions_horaires = res[0];
|
|
|
|
if (conditions_horaires !== "")
|
|
{
|
|
// Calcul des valeurs du moment dès lors qu'on a au moins une condition à analyser :
|
|
var now = Fonctions_date_heure.date_courante(null, shipheart_fuseau_horaire, shipheart_heure_ete);
|
|
var now_jour = now.getDay();
|
|
if (now_jour === 0) now_jour = 7;
|
|
var now_heure = now.getHours();
|
|
var now_minute = now.getMinutes();
|
|
|
|
// Découpage des conditions :
|
|
conditions = conditions_horaires.split(';');
|
|
|
|
// Bucle sur toutes les conditions :
|
|
for (i = 0; i < conditions.length; i ++)
|
|
{
|
|
// Découpage des 4 champs de la condition :
|
|
condition = conditions[i].split('/');
|
|
|
|
if (condition.length === 4) // Si le format de la condition n'est pas valide, on ne la traite pas...
|
|
{
|
|
//console.log("Now : "+now_jour+"/"+now_heure+"/"+now_minute+" - valeur en cours : "+Number(condition[0])+"/"+Number(condition[1])+"/"+Number(condition[2])+" et validite="+Number(condition[3]))
|
|
jour = Number(condition[0]);
|
|
heure = Number(condition[1]);
|
|
minute = Number(condition[2]);
|
|
validite = Number(condition[3]);
|
|
|
|
if (validite !== 0)
|
|
{
|
|
// Adaptation aux heures spéciales :
|
|
if (heure > 23)
|
|
{
|
|
switch(heure)
|
|
{
|
|
case shipheart_heure_speciale_aube_nautique :
|
|
heure = Number(shipheart_heure_aube_nautique[0] + shipheart_heure_aube_nautique[1]);
|
|
minute = Number(shipheart_heure_aube_nautique[3] + shipheart_heure_aube_nautique[4]);
|
|
break;
|
|
|
|
case shipheart_heure_speciale_lever_soleil :
|
|
heure = Number(shipheart_heure_lever_soleil[0] + shipheart_heure_lever_soleil[1]);
|
|
minute = Number(shipheart_heure_lever_soleil[3] + shipheart_heure_lever_soleil[4]);
|
|
break;
|
|
|
|
case shipheart_heure_speciale_zenith :
|
|
heure = Number(shipheart_heure_zenith[0] + shipheart_heure_zenith[1]);
|
|
minute = Number(shipheart_heure_zenith[3] + shipheart_heure_zenith[4]);
|
|
break;
|
|
|
|
case shipheart_heure_speciale_coucher_soleil :
|
|
heure = Number(shipheart_heure_coucher_soleil[0] + shipheart_heure_coucher_soleil[1]);
|
|
minute = Number(shipheart_heure_coucher_soleil[3] + shipheart_heure_coucher_soleil[4]);
|
|
break;
|
|
|
|
case shipheart_heure_speciale_crepuscule_nautique :
|
|
heure = Number(shipheart_heure_crepuscule_nautique[0] + shipheart_heure_crepuscule_nautique[1]);
|
|
minute = Number(shipheart_heure_crepuscule_nautique[3] + shipheart_heure_crepuscule_nautique[4]);
|
|
break;
|
|
|
|
case shipheart_heure_speciale_fin_nuit :
|
|
case shipheart_heure_speciale_aube :
|
|
case shipheart_heure_speciale_crepuscule :
|
|
case shipheart_heure_speciale_debut_nuit :
|
|
default:
|
|
break; // On garde l'heure existante, sachant qu'elle ne sera jamais déclenchée car > 23...
|
|
}
|
|
}
|
|
|
|
// Calcul de la date du prochain déclenchement et de sa "distance" par rapport à maintenant :
|
|
var next = prochain_declenchement_condition(now_jour, now_heure, now_minute, jour, heure, minute);
|
|
|
|
//console.log("Prochain déclenchement = "+next['jour']+"-"+next['heure']+":"+next['minute'])
|
|
|
|
// Mise à jour du prochain déclenchement parmi toutes les conditions actuellement valides :
|
|
if ( (reveils_next_jour === 0) // Permet d'identifier qu'aucun NEXT n'a encore été enregistré...
|
|
|| (next['distance'] < reveils_next_distance)) // ... ou la nouvelle condition se déclenchera avant le NEXT déjà enregistré
|
|
{
|
|
reveils_next_jour = next['jour'];
|
|
reveils_next_heure = next['heure'];
|
|
reveils_next_minute = next['minute'];
|
|
reveils_next_distance = next['distance'];
|
|
}
|
|
|
|
// Test du déclenchement MAINTENANT :
|
|
if ((jour !== now_jour) && (jour !== 8)) continue;
|
|
if (heure !== now_heure) continue;
|
|
if (minute !== now_minute) continue;
|
|
|
|
// Déclenchement réveil :
|
|
traitement_declenchement_reveil(jour, heure, minute);
|
|
break; // Inutile d'aller plus loin si on a décleché une fois
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//=================================================================================================
|
|
// Fonction calculant la date (jour de la semaine, heure et minute) du prochain déclenchement d'une condition horaire.
|
|
// La fonction calcule également la "distance" (en minutes) entre maintenant et la date de déclenchement trouvée.
|
|
// Reçoit : le jour de la semaine, l'heure et les minutes de MAINTENANT et de la condition.
|
|
// Retour : le jour de la semaine, l'heure et minute du prochain déclenchement + la distance du déclenhement vs maintenant.
|
|
//=================================================================================================
|
|
function prochain_declenchement_condition(now_jour, now_heure, now_minute, jour, heure, minute)
|
|
{
|
|
var next_jour;
|
|
var next_heure;
|
|
var next_minute;
|
|
var distance;
|
|
|
|
//------------------------------------------------------------------------
|
|
// Détermination de la date du prochain déclenchement :
|
|
if (jour === 8) // Si c'est TOUS LES JOURS :
|
|
{
|
|
next_jour = now_jour; // Aujourd'hui par défaut
|
|
if ( (heure < now_heure) || // Sauf si l'heure est passée...
|
|
((heure === now_heure) && (minute < now_minute)) ) // ... ou si on est sur l'heure en cours et les minutes sont passées :
|
|
{
|
|
if (++ next_jour > 7) next_jour = 1; // dans ce cas, on passe à Demain
|
|
}
|
|
}
|
|
else next_jour = jour; // Si c'est un jour de semaine particulier, on n'a pas le choix
|
|
|
|
next_heure = heure;
|
|
next_minute = minute;
|
|
|
|
//------------------------------------------------------------------------
|
|
// Calcul de la distance entre le prochain déclenchement et MAINTENANT :
|
|
if (next_jour > now_jour)
|
|
{
|
|
distance = (60 - now_minute) // Minutes entre maintenant et fin de l'heure en cours
|
|
+ ((24 - now_heure -1) * 60) // Heures entières entre fin de l'heure en cours et ce soir minuit
|
|
+ ((next_jour - now_jour - 1) * (24*60)) // Jours entiers séparant les 2 jours
|
|
+ (heure * 60) // Heures entre 0h du jour de déclenchement et l'heure entière de déclenchement
|
|
+ (minute) // Minutes entre l'heure entière de déclenchement et le déclenchement
|
|
}
|
|
|
|
else if (next_jour < now_jour)
|
|
{
|
|
distance = (60 - now_minute) // Minutes entre maintenant et fin de l'heure en cours
|
|
+ ((24 - now_heure -1) * 60) // Heures entières entre fin de l'heure en cours et ce soir minuit
|
|
+ ((7 - now_jour) * (24*60)) // Jours entiers entre ce soir minuit et dimanche soir minuit
|
|
+ ((next_jour - 1) * (24*60)) // Jours entiers entre lundi 0h et minuit le jour précédent le déclenchement
|
|
+ (heure * 60) // Heures entre 0h du jour de déclenchement et l'heure entière de déclenchement
|
|
+ (minute) // Minutes entre l'heure entière de déclenchement et le déclenchement
|
|
}
|
|
|
|
else // next_jour = now_jour
|
|
{
|
|
if (heure > now_heure)
|
|
{
|
|
distance = (60 - now_minute) // Minutes entre maintenant et fin de l'heure en cours
|
|
+ ((heure - now_heure -1) * 60) // Heures entières entre fin de l'heure en cours et l'heure entière de déclenchement
|
|
+ (minute) // Minutes entre l'heure entière de déclenchement et le déclenchement
|
|
}
|
|
|
|
else if (heure < now_heure)
|
|
{
|
|
distance = (60 - now_minute) // Minutes entre maintenant et fin de l'heure en cours
|
|
+ ((24 - now_heure -1) * 60) // Heures entières entre fin de l'heure en cours et ce soir minuit
|
|
+ ((7 - now_jour) * (24*60)) // Jours entiers entre ce soir minuit et dimanche soir minuit
|
|
+ ((next_jour - 1) * (24*60)) // Jours entiers entre lundi 0h et minuit le jour précédent le déclenchement
|
|
+ (heure * 60) // Heures entre 0h du jour de déclenchement et l'heure entière de déclenchement
|
|
+ (minute) // Minutes entre l'heure entière de déclenchement et le déclenchement
|
|
}
|
|
|
|
else // heure = now_heure
|
|
{
|
|
if (minute > now_minute)
|
|
{
|
|
distance = (minute - now_minute) // Minutes entre maintenant et le déclenchement
|
|
}
|
|
else if (minute < now_minute)
|
|
{
|
|
distance = (60 - now_minute) // Minutes entre maintenant et fin de l'heure en cours
|
|
+ ((24 - now_heure -1) * 60) // Heures entières entre fin de l'heure en cours et ce soir minuit
|
|
+ ((7 - now_jour) * (24*60)) // Jours entiers entre ce soir minuit et dimanche soir minuit
|
|
+ ((next_jour - 1) * (24*60)) // Jours entiers entre lundi 0h et minuit le jour précédent le déclenchement
|
|
+ (heure * 60) // Heures entre 0h du jour de déclenchement et l'heure entière de déclenchement
|
|
+ (minute) // Minutes entre l'heure entière de déclenchement et le déclenchement
|
|
}
|
|
else distance = 0;
|
|
}
|
|
}
|
|
|
|
return( {"jour": next_jour, "heure": next_heure, "minute": next_minute, "distance": distance } );
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|