Interface Gainable en Qt sur RPi

non juste faire une interface avec l'affichage des temperatures , voir fond d'ecran ,bouton Valid , bouton Menu , bouton Moins et bouton plus) comme mon menu sur wokwi .
ou un moment je lance la fonction gainable via le bouton valid

apres je verrais pour ajouter des chose , je pense que c'est un bon debut pour apprendre

Dans ce cas, pourquoi cherches tu as faire une application Qt ?

car je trouve cela propre et apres ci il yas d'autre solutions ! je suis preneur

Ouai mais du coup, une interface graphique sympa en C pure ou en C++ sans classes, ca ne cours pas les rues, ni les tiroirs des bricoleurs.
Donc si tu veux faire du Qt, il faut que tu programmes dans le langage utilisé par Qt.

Ce que tu annonces n'est pas simplement l'affichage de hello word dans une fenêtre

Un exemple concret affichage de l'heure (juste un extrait)

MainWindow::MainWindow(QWidget *parent)
    :QWidget (parent)    
{
//création de la fenêtre
    baseWindow =new QWidget;
    baseWindow →setFixedSize(1920,1080);

//mise en page faite dans un fichier ressource de Qt où entre autre une image de fond sera insérée
    baseWindow →setObjectName("fond");
    QFile file(":css/feuille_mw.qss");
    file.open(QFile::ReadOnly);
    QString styleSheet = QString::fromLatin1(file.readAll());
    baseWindow ->setStyleSheet(styleSheet);
    file.close();

//configuration des Gpio pour commander ici une pompe à eau à partir d’un bouton
    pinMode(PIN_CONTROL_WATERPUMP, OUTPUT); //control waterpump
    digitalWrite(PIN_CONTROL_WATERPUMP, HIGH); //control waterpump on

//création d’un objet DigitalClock
    lcdHeure = new DigitalClock(baseWindow);

Et tout DigitalClock, qui dans le cas présent gére son propre affichage, mis en page également dans un fichier ressource de Qt. Juste une fonction pour faire que l'heure système affichée soit dans un format précis

#include <QtWidgets>
#include "digital_clock.h"
DigitalClock::DigitalClock(QWidget *parent)
    :QWidget(parent)
{
    QFile file(":css/feuille_dc.qss");
    file.open( QFile::ReadOnly );
    QString styleSheet =QString::fromLatin1(file.readAll());
    this ->setStyleSheet(styleSheet);
    file.close();
    heure =new QLCDNumber(this);
    heure ->setObjectName("heure");
    heure ->setGeometry (50,40,150,60);
    heure ->setDigitCount(5);
    QTimer *timer = new QTimer(this);
    connect(timer,&QTimer::timeout,[this](){showTime();});
    timer ->start(300);
}
void DigitalClock::showTime()
{
    QTime time = QTime::currentTime();
    QString text = time.toString("hh:mm");
    heure ->display(text);
}

Cet exemple n'est pas anodin. Il contient beaucoup des bases du C++ et l'exception Qt avec connect

oui c'est pour ce la qu'il faut que j'etudie les classes , pour pouvoir reussir qu'elle que chose de sympa

J'ai fait cela à distance via VNC et un copier coller dans un terminal.. il se peut que je n'ai pas bien copié le contenu de mon fichier et un passage à la ligne a été introduit.

essayez

#include <QApplication>
#include <QWidget>
#include <QVBoxLayout>
#include <QPushButton>
#include <QLineEdit>
#include <QLabel>
#include <QThread>
#include <QTimer>
#include <QMessageBox>
#include <random>

class RandomNumberThread : public QThread {
    Q_OBJECT

  signals:
    void valeurGeneree(int valeur);

  protected:
    void run() override {
      std::random_device rd;
      std::mt19937 gen(rd());
      std::uniform_int_distribution<> dis(1, 100);

      while (!isInterruptionRequested()) {
        int valeur = dis(gen);
        emit valeurGeneree(valeur);
        sleep(2);
      }
    }
};

class TestApp : public QWidget {
    Q_OBJECT

  public:
    TestApp(QWidget *parent = nullptr) : QWidget(parent) {
      QVBoxLayout *layout = new QVBoxLayout(this);

      QPushButton *bouton1 = new QPushButton("Bouton 1", this);
      layout->addWidget(bouton1);

      QPushButton *bouton2 = new QPushButton("Bouton 2", this);
      layout->addWidget(bouton2);

      QLabel *label = new QLabel("Valeur :", this);
      layout->addWidget(label);

      QLineEdit *lineEdit = new QLineEdit(this);
      layout->addWidget(lineEdit);

      connect(bouton1, &QPushButton::clicked, this, [this]() {
        afficherMessage("Appui bouton 1");
      });

      connect(bouton2, &QPushButton::clicked, this, [this]() {
        afficherMessage("Appui bouton 2");
      });

      connect(&randomNumberThread, &RandomNumberThread::valeurGeneree, this, [lineEdit](int valeur) {
        lineEdit->setText(QString::number(valeur));
      });

      randomNumberThread.start();

      setLayout(layout);
    }

    void afficherMessage(const QString &message) {
      QMessageBox::information(this, "Information", message);
    }

  private:
    RandomNumberThread randomNumberThread;
};

int main(int argc, char *argv[]) {
  QApplication app(argc, argv);
  TestApp testApp;
  testApp.show();
  return app.exec();
}

#include "Test.moc"

@le_viking
il me semble que le souci de @ludomac c'est que sa machine à état doit tourner même si on ne clique sur aucun bouton et réagir ainsi aux solicitations externes.

C'est pour cela que j'ai mis un thread séparé, mais capable d'afficher quelque chose dans l'interface.

Je n'ai pas bien compris comment vous proposez de gérer cela ?

Au repos j’afficherai un écran « arrêt » ( avec fond d’écran ect , par la suite ) on clic sur bouton menu j’afficherai « démarrer ? » si pendant cette affichage on appuie sur les deux boutons moins et plus ce la démarre la fonction test ( relais ) et les consignes de réglage de température ect . et si appuie sur le bouton valid on démarrer la fonction de La machine à état ! Après l’affichage récupéreras toute les températures des sondes et dans le futur ou je serai à l’aise je pourrais faire comme dans l’exemple plus haut !

Si vous êtes sur l’écran du RPI, faites un menu /bouton préférences… ne vous ennuyez pas avec des commandes cachées, c’est contre intuitif. Sur arduino éventuellement on limite les boutons physiques mais là c’est que du virtuel.

Ok ! Merci de votre conseil ! Je vais essayer le bout de code que vous m’avez transmis ! Demain matin ! Grand merci à tous

Il faudrait que je reprenne au début les demandes de @ludomac mais je ne comprend pas quel est problème. On peut très bien afficher en même temps la température et
la contrôler, changer la couleur des boutons en fonction de la température, modifier la consigne de température dans une autre fenêtre voire plusieurs sans interrompre pour cela l'affichage et le contrôle de la température

Ça fait une éternité que je n’ai pas joué avec Qt mais de mémoire l’appel à app.exec() etait bloquant. C’est la loop de gestion de l’IHM qui reçoit les événements standards,

Comment intégrez vous dans le code (sans que l’utilisateur ne clique sur quoi que ce soit) un bout de code qui surveille un capteur, fait clignoter des leds etc si vous n’avez pas un autre thread ?

Dans le main on instancie une Qapplication

QApplication app(argc, argv);

On instancie la classe de base de son soft, généralement une MainWindow puis on l'affiche avec show (qui crée une boucle non modal)

    MaFenetreDeBase base;
    base.show();

enfin on retourne l'instance de QApplication avec la méthode exec (qui crée une boucle modal)

Il suffit donc d'instancier dans MainWindow la classe qui gère le capteur, les relais et autres pour qu'ils tournent dans la même boucle. C'est ce que je fait dans l'exemple que j'ai donné en instanciant DigitalClock pour afficher l'heure, dans ce cas, dans la fenêtre principale, faute de paramètres il aurait créé une seconde fenêtre au dessus de la première

Les boucles dont vous parlez sont inactives par défaut et vous ne répondez qu’aux sollicitations de l’utilisateur - Je me demandais juste comment vous vouliez activer la machine à états.

➜ je n’avais pas vu (je lis sur l’iPhone)

vous n’avez qu’un seul thread mais vous utilisez un timer pour appeler de temps en temps showTime()

C’est donc un peu équivalent non ? (Vous gérez vous meme l’allocation du temps CPU a une fonction au lieu de laisser l’OS affecter du temps à un thread).

J’ai l’habitude du multitâche (c’est aussi ce que je fais avec Python dans mon tuto de communication avec un Arduino) dans les apps sur un OS moderne mais c’est peut être effectivement plus simple à coder et comprendre avec un timer du moment que l’application n’a besoin de vérifier des états que de temps en temps et n’a pas besoin d’un process « toujours » disponible et à l’écoute.

Non, c'est QApplication qui gère le flux d'application. J'ai plus plus d'une dizaine de fenêtres insérées dans mon MainWindow. Pour cette fenêtre, je me contente juste d'appeler la méthode display avec un timer il est inutile que l'affichage soit mis à jour à chaque tour de boucle puisqu'il sera inchangé. Je pourrais même augmenter ce temps puisqu'il n'affiche que les minutes

en faite quand je fait le code pour test

#include <QApplication>
#include <QPushButton>

int main(int argc, char *argv[])
{
  
  QApplication app(argc, argv);
  QWidget fenetre;
  fenetre.setFixedSize(1200,600);
      
  QPushButton bouton1("BoutonMenu", &fenetre); // la fenêtre est le parent du bouton 
  bouton1.setText("Menu"); // le nouveau texte 
  bouton1.setToolTip("Texte d'aide"); // info bulle 
  bouton1.setFont(QFont("Comic Sans MS", 14)); // nouvelle police
  bouton1.setCursor(Qt::PointingHandCursor);
  bouton1.setGeometry(60, 50, 180, 70);

  QPushButton bouton2("BoutonValid", &fenetre); // la fenêtre est le parent du bouton 
  bouton2.setText("Valid"); // le nouveau texte 
  bouton2.setToolTip("Texte d'aide"); // info bulle 
  bouton2.setFont(QFont("Comic Sans MS", 14)); // nouvelle police
  bouton2.setCursor(Qt::PointingHandCursor);
  bouton2.setGeometry(300, 50, 180, 70);
  

  QPushButton bouton3("BoutonMoins", &fenetre); // la fenêtre est le parent du bouton 
  bouton3.setText("Moins"); // le nouveau texte 
  bouton3.setToolTip("Texte d'aide"); // info bulle 
  bouton3.setFont(QFont("Comic Sans MS", 14)); // nouvelle police
  bouton3.setCursor(Qt::PointingHandCursor);
  bouton3.setGeometry(700, 50, 180, 70);

  QPushButton bouton4("BoutonPlus", &fenetre); // la fenêtre est le parent du bouton 
  bouton4.setText("Plus"); // le nouveau texte 
  bouton4.setToolTip("Texte d'aide"); // info bulle 
  bouton4.setFont(QFont("Comic Sans MS", 14)); // nouvelle police
  bouton4.setCursor(Qt::PointingHandCursor);
  bouton4.setGeometry(960, 50, 180, 70);

  fenetre.show();

  return app.exec();
}

cela fonctionne bien

et je voit pas comment incorporer ma machine a etat a ce code sans que j'ai un blocage : de la machine a etat .

code avec machine a etat :

#include <QApplication>
#include <QPushButton>
#include <QAction>
#include <QLabel>
#include <QPixmap>

#include "gainable.hpp"
#include "BB_DS18B20.hpp"
#include "gpioPin.hpp"
#include "lectureTemps.hpp"
#include "ecritTemps.hpp"
#include "vitesseVentilateurs.hpp"
#include "relais.hpp"
#include "commandes.hpp"
#include "affichageTerminal.hpp"

BB_DS18B20 * ds18b20;

void my_ctrl_c_handler(int s) {
  desactiveTousRelais();
  digitalWrite (relaiEteHiver,HIGH);
  delete ds18b20;
  release_gpiod();
  exit (0);
}

// les autres fonctions
void fonctionsDivers () {
  consigneDelta = tempExtLue - delta;
  consigneVentIntCa = consigneDelta + 2;
  commandeFroid();
  commandeChauffage();
  commandeCanicule();
  hysteresisTempVitesseIntCa();
  hysteresisTempVitesseExtFroid();
  hysteresisTempVitesseIntFroid();
  hysteresisTempVitesseExtChauf();
  hysteresisTempVitesseIntChauf();
  signal (SIGINT, my_ctrl_c_handler);
}

int main(int argc, char *argv[]) {
  
  QApplication app(argc, argv);
  QWidget fenetre;
  fenetre.setFixedSize(1200,600);
  
  //QLabel label(&fenetre);
  //label.setPixmap(QPixmap("/home/ludo/Pictures/IMG_0611.JPG"));
  //label.show();

  //return app.exec();
  
    /******  ceci est le setup  ******/

// les pins
  pinMode (relaiEteHiver, OUTPUT);
  digitalWrite (relaiEteHiver, HIGH);
  pinMode (relaiComp, OUTPUT);
  digitalWrite (relaiComp, HIGH);
  pinMode (relaiV4V, OUTPUT);
  digitalWrite (relaiV4V, HIGH);
  pinMode (relaiVitesseVentExt, OUTPUT);
  digitalWrite (relaiVitesseVentExt, HIGH);
  pinMode (relaiPetiteVitesseInt, OUTPUT);
  digitalWrite (relaiPetiteVitesseInt, HIGH);
  pinMode (relaiGrandeVitesseInt, OUTPUT);
  digitalWrite (relaiGrandeVitesseInt, HIGH);

  pinMode (thermostats, INPUT_PULLUP);
  pinMode (capteurFiltre, INPUT_PULLUP);

// pin Sondes ds18b20
  int DS_PIN = 4;
  pinMode (DS_PIN, OPENDRAIN_PULLUP);
  ds18b20 = new BB_DS18B20 (gpioline[DS_PIN]);
  
// le fichier ID sur les ds18b20
  loadDSConfig ("DS18B20.conf", ds_ID);
  // charge info sur les ds18b20
  char  ficConf[654] = "DS18B20.conf";
  FILE * confHan = fopen(ficConf, "r");
  if (NULL == confHan) {
    cout << "Le fichier de configuration \n" << ficConf << "\n doit exister\n";
    return (111);
  }
  fclose(confHan);
  loadDSConfig("DS18B20.conf", ds_ID); // protégé contre le cas où il est absent 
  cout << "\n configure\n";
  if (ds_ID.size() < 2) {
    cout << "\nVous devez avoir au moins un thermomètre\n";
    return(112);
  }
  
// créer  le vecteur contenant la température des DS18b20
  for (uint loop = 0; loop < ds_ID.size(); loop++)
    ds_temperature.push_back (
      -9999.9); //  enregistre une information invalide pour commencer

  /****** ceci est la loop  *****/

// la loop
  while (1) {
    
    QPushButton bouton1("BoutonMenu", &fenetre); // la fenêtre est le parent du bouton 
    bouton1.setText("Menu"); // le nouveau texte 
    bouton1.setToolTip("Texte d'aide"); // info bulle 
    bouton1.setFont(QFont("Comic Sans MS", 14)); // nouvelle police
    bouton1.setCursor(Qt::PointingHandCursor);
    bouton1.setGeometry(60, 50, 180, 70);

    QPushButton bouton2("BoutonValid", &fenetre); // la fenêtre est le parent du bouton 
    bouton2.setText("Valid"); // le nouveau texte 
    bouton2.setToolTip("demarage?"); // info bulle 
    bouton2.setFont(QFont("Comic Sans MS", 14)); // nouvelle police
    bouton2.setCursor(Qt::PointingHandCursor);
    bouton2.setGeometry(300, 50, 180, 70);

    QPushButton bouton3("BoutonMoins", &fenetre); // la fenêtre est le parent du bouton 
    bouton3.setText("Moins"); // le nouveau texte 
    bouton3.setToolTip("Texte d'aide"); // info bulle 
    bouton3.setFont(QFont("Comic Sans MS", 14)); // nouvelle police
    bouton3.setCursor(Qt::PointingHandCursor);
    bouton3.setGeometry(700, 50, 180, 70);

    QPushButton bouton4("BoutonPlus", &fenetre); // la fenêtre est le parent du bouton 
    bouton4.setText("Plus"); // le nouveau texte 
    bouton4.setToolTip("Texte d'aide"); // info bulle 
    bouton4.setFont(QFont("Comic Sans MS", 14)); // nouvelle police
    bouton4.setCursor(Qt::PointingHandCursor);
    bouton4.setGeometry(960, 50, 180, 70);

    fenetre.show();
    
    lireDS18B20();
    ecritTemps();
    gainable();
    fonctionsDivers();
    affichageTerminal();
    time_t rawtime;
    time ( & rawtime);
    cout << ctime ( & rawtime) << endl;
    
    return app.exec();
  }
  delete ds18b20;
  return 0;
}

j'ai essayer dans pas mal de sens et soit j'ai le contour de la fenetre et la machine tourne ou soit j'ai toute l'interface et la machine bloque !

il fonctionne , merci

j'ai fait cela et ca fonctionne :crazy_face:


      connect(bouton1, &QPushButton::clicked, this, [this]() {
        afficherMessage("Appui bouton 1");
        relaiTestOn();
      });

      connect(bouton2, &QPushButton::clicked, this, [this]() {
        afficherMessage("Appui bouton 2");
        relaiTestOff();
      });