salut a vous ,
donc j'ai recommencer a zero , j'ai recreer un git :
https://github.com/ludoiphone/gainable-en-fabrication
je vais me pencher sur les temporisations .
Version imprimable
salut a vous ,
donc j'ai recommencer a zero , j'ai recreer un git :
https://github.com/ludoiphone/gainable-en-fabrication
je vais me pencher sur les temporisations .
Attention :
Code:
1
2
3
4
5
6 class Chauffage { public: void chauffage(); };
Code:
1
2
3
4
5
6 #include "chauffage.h" void Chauffage::chauffage() { cout << "fabrication du chauffage" << endl << endl; }
S'il s'agit ici d'un constructeur, celui-ci doit porter exactement le nom de la classe… en respectant la casse ! Il faut mettre une majuscule à la lettre C du nom de la classe et celui de la fonction-membre, ou ne pas en mettre du tout.
Et en conséquence, comme un constructeur est forcément void par nature, cela est implicite. Il faudra donc retirer la qualification de type aussi bien dans la déclaration de la classe qu'à la définition de la fonction.
Pourquoi "tempExtLue, tempUnitExtLue, tempEchExtLue, tempUnitIntLue, tempEchIntLue" comme membre de la classe "DS18B20".
Idem pour "buffer" ou "end".
Pourquoi ce mélange de fichier en ".h" et en ".hpp".
La fonction de chaque classe me semble pas claire, surtout la classe "Modes".
Pourquoi l'objet "modes" ne peut-il pas être autonome et aller lui-même demander la température ???Citation:
Code:modes.SetTemperatureExt(temperatureExt.GetTempExt());
Pourquoi faire une boucle active "à fond les ballons" avec ce ridicule "sleep(1)" ?Code:
1
2
3
4
5
6
7
8
9 DS18B20 temperatureExt; Modes modes(temperatureExt); ... if (time(nullptr) - chrono >= deltaT) { modes.productions(); chrono = time(nullptr); }
Vous n'avez toujours pas appliqué nos "conseilles" de codage.
La temporisation semble centrale dans votre projet mais je ne vois rien de concret sur le sujet dans vote prototype.
C'est maintenant que vous devez évaluer les alternatives d'implémentation pour connaitre si elles correspondent à vos besoins.
std::async ne convient pas ? https://en.cppreference.com/w/cpp/thread/async.html
Il semble toujours que la distinction classe/objet ne soit pas claire, cf. "const int thermostats = 17;"
pour le chauffage je mettais tromper ; j'ai rectifier dans github.
c'etait bien une fonction mais mal ecrite desolé.
Pourquoi "tempExtLue, tempUnitExtLue, tempEchExtLue, tempUnitIntLue, tempEchIntLue" comme membre de la classe "DS18B20".
car j'ai 5 sondes dans un fichier et elles ont leur propre fichier (adresse Ds18b20).
Code:
1
2
3 /sys/bus/w1/devices/28-3ce1e3804835/temperature = sonde Ext /sys/bus/w1/devices/28-3ce1e3809744/temperature = sonde UnitExt ...
pour le hpp, je sais pas trop car c'est une class que l'on ma fourni . je pense que c'est pour stipuler que c'est du c++, h++.
pour modes.SetTemperatureExt(temperatureExt.GetTempExt()); je ne savait pas trop comment faire ; je suis debutant :oops:
en gros l'ideal en que je doit mettre DS18B20 dans Modes ??
le sleep me sert a voir ce qu'il ce passe , si non cela vas trop vite , il sera retirer a la fin .
les temporisations , oui sont tres important car elle servent pour actionner les diferents relais et controler les temperatures en fonction de l'etat ou le programme vas ce trouver a un temp donner .
et apres pour mettre a jour les temperatures sur l'ecran . mais pour l'instant avec vos conseilles est de construire le code metier et apres la partie ecran.
j'avais un peux compris les thread sur Qt ; mais en c++ ??
la class sert a creer un objet .
et j'avoue que ce n'ai pas si evident que cela !
j'essais de faire de mon mieux pour tous comprendre du au de mes 45 ans en sachant que je travaille sur ce projet que qu'elle que heure par jours , avec 6 gamins en plus a la maison
je vous dit pas que je suis toujours soliciter (crit , bagarre, pleure) mais bon !
merci a vous de donner votre precieux temps .
Citation:
pour le chauffage je mettais tromper ; j'ai rectifier dans github.
Je ne vois pas comment correctement utiliser cette classe. Je trouve qu'elle manque d'affordance (https://fr.wikipedia.org/wiki/Affordance).Citation:
Code:
1
2
3
4
5
6
7
8
9 #include <iostream> using namespace std; class Chauffage { public: void fonctionChauffage(); };
Code:
1
2
3
4
5
6
7
8
9
10
11 #include "chauffage.h" void Chauffage::fonctionChauffage() { cout << "fabrication du chauffage" << endl << endl; } Chauffage::~Chauffage() { cout << "destructeur Chauffage" << endl; }
Je trouve que la classe suivante est "facile" à comprendre :
On peut appeler "marche" et "arret" sur un objet "Chauffage". On ne peut pas le construire "ex nihilo" (utilisation de DP pour construire correctement l'ensemble des objets de type "Chauffafe" en fonction de comment ils doivent être créés et "accédés").Code:
1
2
3
4
5
6
7
8 class Chauffage { protected : Chauffage(); public: void marche(); void arret(); }
Si on n'a besoin de plus d'action possible sur un objet "Chauffage", il faut juste l'ajouter à la classe les fonctions qui vont bien.
On n'inclus que les .h nécessaire à la compréhension du .h par le compilateur.Citation:
Code:#include <iostream>
Ici, le compilateur n'a pas besoin de "iostream" pour comprendre ce qu'il y a dans le .h.
Jamais de "using namespace" en globale dans un .h, et encore moins "using namespace std".Citation:
Code:using namespace std;
Déjà dans un .cpp, ça se justifie difficilement, alors dans un .h !!! :aie:
Je vous est déjà dit que ces "print coucou" sont largement substituables par des "break point" du débogueur.Citation:
Code:cout << "fabrication du chauffage" << endl << endl;
Si vous voulez des traces fonctionnelles, utilisez une MACRO ou un framework de trace, mais ne truffez pas votre code de "cout <<..." à la con.
Pourquoi un destructeur ? Vous comptez en faire une classe avec des classes filles ?
(Encore une fois, je pense que vous devriez prendre un peu de temps sur de "bons" cours de C++, qui abordent la notion de classes entité Vs classes "Valeurs")
Si vous commencez par pisser du code avant l'analyse, faites en sorte que votre code soit simple à comprendre et à utiliser au moins au départ.
Ça s'arrangera pas avec la progression du projet (sauf à faire des refactoring "douloureux").
Je pense que la lecture préalable d'un bon cours de C++ permettrait de plus facilement concevoir "correctement" des classes etc...
Il faut donc 5 objets/instances de classe "DS18B20" différent. Chacun initialisé avec une "adresse" différente.Citation:
car j'ai 5 sondes dans un fichier et elles ont leur propre fichier (adresse Ds18b20).
Code:
1
2
3
4
5 DS18B20 tempExt{"/sys/bus/w1/devices/28-3ce1e3804835/temperature"}; DS18B20 tempUnitExt{"/sys/bus/w1/devices/28-3ce1e3809744/temperature"}; DS18B20 tempEchExt{"/sys/bus/w1/devices/28-3ce1e38060ec/temperature"}; DS18B20 tempUnitInt{"/sys/bus/w1/devices/28-3ce1e3801251/temperature"}; DS18B20 tempEchInt{"/sys/bus/w1/devices/28-3ce1e3805e9f/temperature"};
Quand vous récupérez du code de l'"extérieur" assimilez-le, puis soit vous le transformez pour qu'il respecte vos conventions de codage, soit vous l'"isolé" dans des modules "externes".Citation:
pour le hpp, je sais pas trop car c'est une class que l'on ma fourni . je pense que c'est pour stipuler que c'est du c++, h++.
Ici, votre module "gpioPin" semble faire tampon entre votre code "métier" et le matériel.
Très souvent dans un projet informatique on sépare le code en 3 parties/couches : IHM, métier, data/matériel.
Ici, je pense que le module "gpioPin" est une partie de la couche "matérielle", car, si vous modifiez la partie physique du projet, cette partie du code devra être adaptée.
L'utilisation de "namespace" et de convention de codage différent entre les couches permet de mieux si retrouver.
Si un objet Modes a besoin de DS18B20 pour faire les services qu'il offre, oui, Modes soit avoir accès à des "DS18B20".Citation:
en gros l'ideal en que je doit mettre DS18B20 dans Modes ??
Mais je ne comprends pas vraiment ce qu'est concrètement ce "Modes".
C'est le meilleur moyen pour un faire truc qui ne fonctionne qu'avec ça présent et le jour où vous l'enlevez, c'est la catastrophe.Citation:
le sleep me sert a voir ce qu'il ce passe , si non cela vas trop vite , il sera retirer a la fin .
Ne truffez pas votre code de lignes inutiles, voire dangereuses. => Utilisez un débugueur.
Vous devez donc, avant de pisser du code pour votre projet, faire des POC avec les différent types de temporisation pour comprendre comment elles fonctionnent et donc correctement les utiliser pour la conception de votre projet.Citation:
les temporisations , oui sont tres important car elle servent pour actionner les diferents relais et controler les temperatures en fonction de l'etat ou le programme vas ce trouver a un temp donner .
Comme vous devez piloter du matériel, je vous conseille de commencer par des POC pour le pilotage de ce matériel.Citation:
et apres pour mettre a jour les temperatures sur l'ecran . mais pour l'instant avec vos conseilles est de construire le code metier et apres la partie ecran.
Votre code métier pourra utiliser les services offerts par cette couche matérielle.
La couche IHM utilisera la couche métier.
Non, elle sert à modéliser le comportement et les services offerts par un ensemble d'objets/instances.Citation:
la class sert a creer un objet .
C'est normal, ne vous inquiétez pas. faut que ça murisse.Citation:
et j'avoue que ce n'ai pas si evident que cela !
la je suis completement perdu !
pour chauffage , j'ai penser a un switch case pour passer d'un etat a un autre :
est ce une bonne idée?
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 #ifndef CHAUFFAGE_H #define CHAUFFAGE_H #include <cstdio> class Chauffage { enum { MARCHE_CHAUFFAGE, CONTROLE_TEMPERATURE_CHAUFFAGE, TEMPO_COMPRESSEUR_CHAUFFAGE, CONTROLE_TEMPERATURE_VENTILATION_INTERIEUR, TEMPO_DEGIVRAGE_CHAUFFAGE, MODE_DEGIVRAGE_CHAUFFAGE, TEMPO_DEGIVRAGE_V4V, TEMPO_DEGIVRAGE_COMPRESSEUR, CONTROLE_TEMPERATURE_DEGIVRAGE_ELECTRIC, DEGIVRAGE_NATUREL, EGOUTTAGE_CHAUFFAGE, FIN_EGOUTTAGE_CHAUFFAGE, ARRET_CHAUFFAGE, } etatsChauffage; public: Chauffage(); ~Chauffage(); void fonctionChauffage(); }; #endif //CHAUFFAGE_H
pour l'instant j'ai mis printf();Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72 #include "chauffage.h" Chauffage::Chauffage() { } void Chauffage::fonctionChauffage() { printf("fabrication du chauffage \n\n"); switch(etatsChauffage) { case MARCHE_CHAUFFAGE: break; case CONTROLE_TEMPERATURE_CHAUFFAGE: break; case TEMPO_COMPRESSEUR_CHAUFFAGE: break; case CONTROLE_TEMPERATURE_VENTILATION_INTERIEUR: break; case TEMPO_DEGIVRAGE_CHAUFFAGE: break; case MODE_DEGIVRAGE_CHAUFFAGE: break; case TEMPO_DEGIVRAGE_V4V: break; case TEMPO_DEGIVRAGE_COMPRESSEUR: break; case CONTROLE_TEMPERATURE_DEGIVRAGE_ELECTRIC: break; case DEGIVRAGE_NATUREL: break; case EGOUTTAGE_CHAUFFAGE: break; case FIN_EGOUTTAGE_CHAUFFAGE: break; case ARRET_CHAUFFAGE: break; } } Chauffage::~Chauffage() { }
j'aimerais comprendre , avec votre aide TRACE ou MACROS et de savoir le mieux pour vous pour mon style de projet ?
c'est surtout pour avoir des infos sur le terminal pendant l'excution du code.
pour les DS18B20 j'ai compris .
Modes est en faite la partie principale, il gere en fonction du thermostat et de la temperature le mode qu'il doit etablir (chauffage ou froid).
j'ai retirer le sleep!
pour les temporisations je suis a votre ecoute car je ne trouve pas grand chose sur POC sur google , sauf si je mi prend mal.
je vous avoue que je suis dans le brouillard total car en faites il ya vraiment tous et son contraire sur le net pour coder :mur:
Hello,
Un switch / case (gargantuesque) pour gérer les états, c'est très naïf, et à la longue pas maintenable.
Cet article peut t'intéresser:
https://www.aleksandrhovhannisyan.co...achine-in-cpp/
Concernant les operateurs new:
En C++ moderne, on aime pas cet opérateur.
D'une part, il requiert l'opération inverse (l'operateur delete), ainsi que les pointeurs nu dont on ne peut garantir la validité (l'objet pointé est-il toujours en vie ? Qui en est le propriétaire ?), autant de sources d'erreurs dependantes de la discipline du programmeur, en d'autre thermes: Incertaines.
C++ a introduit depuis la norme C++ 11 les pointeurs intelligents (std::unique_ptr, std::shared_ptr) qui gomment de nombreuses faiblesses des pointeurs nu, et permettent entre autre de se concentrer sur les comportement des classes plutôt que la gestion de la memoire.
Illustration avec les extrais de code suivant:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 // Avec l'operateur new #include <iostream> #include <new> #include <cstdlib> int main() { int* number; try { number = new int; std::cout << "New integer allocated" << *number << std::endl; } catch(std::bad_alloc& e) { std::cerr << "Memory allocation failed: " << e.what() << std::endl; return EXIT_FAILURE; } *number = 10; std::cout << "Value: " << *number << std::endl; delete *number; return EXIT_SUCCESS; }
Code:
1
2
3
4
5
6
7
8
9
10
11 // Avec les pointeurs intelligents #include <iostream> #include <memory> #include <cstdlib> int main() { std::unique_ptr<int> number{ std::make_unique<int>(10) }; std::cout << "New integer allocated, value: " << *number << std::endl; return EXIT_SUCCESS; }
Comme le montre la référence donnée par @deedolith, il est "facile" de trouver des solutions "clés en main" de problèmes "généraux" car le C++ est un langage très mature et donc sert souvent d'illustration à la résolution de ces problèmes.
Mais le Net est truffé de mauvais codes et de mauvais cours de C++, dû au manque de "sélection naturelle" de ce qui sort les recherches Google ou les IA génératives, et à l'évolution du langage depuis les années 1980.
Les vieux machins écris par des personnes venant du C ou qui ont une vue très superficielle des spécificités du C++ "moderne"(>=C++11, en 2011) "bien écris" squattent les référencements.
C'est pour cela qu'on vous recommande de lire un bon cours "à jours", comme celui de Zeste de Savoir, pour que vous puissiez rapidement évaluer si le code que vous trouvez sur le Net est merdique ou pas.
cf. les 2 paragraphes précédents.Citation:
je vous avoue que je suis dans le brouillard total car en faites il ya vraiment tous et son contraire sur le net pour coder :mur:
Je crois que @deedolith a déjà répondu.Citation:
pour chauffage , j'ai penser a un switch case pour passer d'un etat a un autre :
Vu la complexité du machin, il faudrait que vous dessiniez un schéma d'états : un schéma avec des ronds pour chaque état de l'objet et des flèches entre chaque état qui indique comment/pourquoi on passe d'un état à un autre.
Je serai très surpris que votre schéma d'états ne soit composé que de 13 ronds et de d'une flèche qui sort de chaque rond avec comme label "fonctionChauffage".
Construisez votre schéma sans rien codé, juste avec la "réalité".
Je pense qu'il y aura beaucoup moins que 13 états et qu'il y aura plus qu'une flèche par état.
Si votre schéma d'état est clair, le code qui l'implémentera sera bien plus simple à faire.
Votre enum est privé à votre classe. C'est logique si aucun autre élément de votre projet n'a à connaitre l'état du chauffage, mais est-ce vraiment le cas ?
Il est toujours préférable de commencer le plus "privé" possible, mais il faut que cela soit en accord avec votre conception.
Avant même de commencer à coder, vous devez déjà avoir répondu à ce type de question : "qui sait quoi".
"etatsChauffage" c'est UN état et il n'est connu que de la classe Chauffage, et l'enum est un type, pas un champ ou un autre type de variable.
Donc, c'est plus "logique" de nommer l'enum "StateType" et un champ dans la classe Chauffage de nom "state" et de type "StateType".
Le constructeur de votre classe Chauffage est public, vous faites donc de cette classe Chauffage une classe "Valeurs" ; moi, je pense que c'est plus une classe Entity car je ne vois pas l'intérêt de pouvoir "créer/cloner" un objet Chauffage à tout moment dans votre code. Ne devrait-il pas être privé ?Code:
1
2
3
4
5
6
7
8
9
10
11 class Chauffage{ enum{ ValeurParDefautDeLEtat, .... } StateType; StateType type; ... public: ... }
Idem pour le destructeur : Entité VS Valeurs.
Essayez de garder le code de vos constructeurs et destructeurs proches les uns des autres pour facilement respecter la règle des Cinq : https://www.geeksforgeeks.org/cpp/rule-of-five-in-cpp/
C'est toujours aussi peu pratique.Citation:
pour l'instant j'ai mis printf();
Exemple d'une MACRO "TRACE" qui permet d'automatiquement gérer du code ASCII/UNICODE et d'avoir accès au nom du fichier et la ligne du code qui a généré cette trace.
Ici, pas de gestion de niveau de trace mais ce que je vous demande c'est d'une, de ne pas mettre des traces inutiles/abscons n'importe où n'importe comment ; et d'utiliser des Framework de trace qui, eux, gèrent ces niveaux.Code:#define TRACE(sz) printf(_T("%Ts (%Ts:%d)\n"),_T(sz),_T(__FILE__), __LINE__)
Pour utiliser la MACRO :
Pour utiliser la MACRO, faut juste faire en sorte que le code qui l'utilise ajoute le #include du fichier qui définit la MACRO.Code:
1
2
3
4
5 void Chauffage::fonctionChauffage() { TRACE("fabrication du chauffage"); ... }
Comme je vous ai déjà indiqué qu'il vaudrait mieux "stratifier" votre code en "Hardware/Métier/IHM", vous pouvez très bien avoir une définition différente de cette MACRO en fonction de la couche.
Ainsi, il est très probable que les module de la couche "Hardware" qui doivent pouvoir fonctionner sur tous les systèmes capables d'héberger le hardware, même sans console, la trace n'utilisera préférentiellement pas "printf" mais des truc plus bas niveau, comme qemu.
Donc, arrêtez de faire des traces comme un poulet sans tête !!!
Si vous avez besoin de trace, utilisez un Framework de trace. Et vous êtes encore très loin d'en avoir besoin.
Le débugueur est vôtre ami.
Comme je l'ai déjà écrit ci-avant, il y a de grosses chances que chaque strate de votre projet est des besoins différents, donc potentiellement des Frameworks différents.Citation:
j'aimerais comprendre , avec votre aide TRACE ou MACROS et de savoir le mieux pour vous pour mon style de projet ?
Utilisez une MACRO proche de TRACE (en ajoutant des niveau de trace par exemple) dans chacune des couches de votre projet, pour pouvoir changer de Framework facilement, juste en modifiant la MACRO.
Vous allez surtout flooder votre terminal avec des "informations" totalement abscons.Citation:
c'est surtout pour avoir des infos sur le terminal pendant l'excution du code.
Il vaut mieux peu de traces pertinentes qu'une montagne de données sans aucun sens, vous n'êtes pas (encore?) une IA.
Réfléchissez "bien" à votre trace, au niveau de détails aux quel elle correspond, avec une mise en forme claire, cohérente, systématique => utilisez un Framework et arrêtez de faire du "bricolage".
Gérer 2 choses, c'est gérer 1 chose de trop. :aie:Citation:
Modes est en faite la partie principale, il gere en fonction du thermostat et de la temperature le mode qu'il doit etablir (chauffage ou froid).
Le Thermostat doit être gérer par un objet Thermostat.
Une température par un objet Températures.
Si c'est le système au complet, pourquoi ce n'est pas un objet de class "ThermalSystem" ??? (donc sans constructeur public, ok ? ;) )
Il faut que vos noms soient clairs, quitte à l'expliquer à un canard en plastique, ou à l'enfant le plus dissipé de l'adelphie.
"Modes", c'est pas clair.
POC, c'est Proof Of Concept. https://fr.wikipedia.org/wiki/Preuve_de_conceptCitation:
pour les temporisations je suis a votre ecoute car je ne trouve pas grand chose sur POC sur google , sauf si je mi prend mal.
Avant d'investir des heures, des années et des millions dans un projet sans savoir si c'est possible ou sans maitriser les concepts clés du projet, on fait des programme "jouet" pour valider chacun des trucs qu'il faut maitriser.
Avant de faire de la temporisation dans votre projet, faite des projets "jouet/d'exemple" pour tester comment fonctionnent les différents systèmes de temporisation.
Avec des programmes "jouet", vous pouvez facilement tester tous les cas nécessaires à votre compréhension des trucs, sans avoir à "saloper" votre projet pour faire des tests.
J'ai déjà mentionné "std::async", avez vous essayez ? Correspond-t-il à vos besoins ? (intéruptionnabilité ? multi-thread ou pas ? disponible sur votre plateforme de test ? de production ? etc...)Vous devez savoir de quoi vous avez besoin pour choisir le ou les bons systèmes de temporisation.
bonjour , j'ai fait mon diagramme , dite moi ce que vous en pensée et si c'est + parlant.
merciPièce jointe 669023
Ok, c'est comme ça que vous appréhendez le projet ?
C'est complexe de base.
Vous n'avez pas une approche "objet" ni "procédurale".
Pouvez-vous revoir ce diagramme avec une approche objet ou procédurale ?
Essayez de vous raccrocher aux composants logiciels que vous comptez utiliser. Pour éviter d'avoir à trop galérer avec.
Faites un prototype avec les fonctionnalités prioritaires.
un diagramme de ce style ? :
Pièce jointe 669045
Votre diagramme ressemble à un diagramme de classe, pas un diagramme d'objet ou à un cas d'usage.
La distinction classe/objet me semble toujours pas assimilée.
Dans un diagramme d'objets, il y a des objets qui ont souvent la même classe.
Donc si c'est un diagramme de classe : DS18B20 ne contiendra pas 5 attributs/champs "Sonde", la classe Temporisation n'aura pas 7 attributs/champs de type "temporisation" (???), etc...
Mais la classe DS18B20 aura UN attribut/champ "Sonde" (l'@ sur le bus ?) et la classe "Temporisation" un attribut/champ "Alive" et/ou un attribut/champ délai avant déclenchement.
Des champs qui permettent de faire avec des instances/objets de ces classes des choses "utiles".
Comme demander une température à une Sonde "DS18B20", ou dans combien de temps se déclenchera la temporisation, etc...
Avec les Frameworks de temporisation existants, je ne suis pas sûr qu'avoir sa propre classe de "Temporisation" soit très utile.
Des objets doivent regrouper des services qui fonctionnent ensemble.
Par exemple, dans votre diagramme, la classe "Gainable" (pensez à utiliser des conventions de codage comme les noms de classe/type commencent une majuscule et les noms d'objet/variables par des minuscules ( Oui, le C/C++ n'applique pas ces règles mais c'était dans les années 1970 :aie:)) est un très bon exemple de classe qui rend des services "clairs".
On peut lui demander de lancer ou d'arrêter le chauffage ou le froid et l'une des fonctionnalités qu'elle peut implémenter en interne est d'arrêt de chauffage automatiquement si on lui demande de lancer "le froid" (ou d'interdire le lancement du froid avant d'avoir éteint le chauffage, mais je trouve que ce type de service moins pratique).
Après, cette "synchronisation" entre le Froid et le chauffage, est-ce du ressort d'un objet "Gainable", qui me semble un machin physique, ou d'un objet purement logique/logiciel comme un "ThermalSystem" ?
Les noms des classes/variables etc..., c'est très important.
En regroupant des actions "logiquement" dans des "fonctions" des objets, vous devriez réduire considérablement la complexité d'un diagramme comme celui de https://www.developpez.net/forums/at...diagramme.pdf/.
La classe "thermostats" :
- préférerez mettre des majuscules pour les noms de types => "Thermostats"
- évitez d'utiliser des "s" terminaux pour distinguer les regroupements d'objets mais plutôt utilisez un suffixe qui correspond à l'API de regroupement qu'il implémente => "ThermostatArray" ou "ThermostatList" etc...
- Avoir un attribut/champ de même type que la classe, c'est assez rare : implémentation de liste chainée "old school" ou d'un singleton
mais c'est jamais du type "brut", pour une liste chainée, c'est avec des pointeurs (*Thermostats) et pour un singleton, ça serait une instance de classe/statique (Thermostats static getInstance()).
donc, essayez d'être explicite sur ces "décorations" (static, *, const, m_, s_ etc...), ça rend le schéma sera plus précis mais aussi bien plus clair.
- Les actions "arret" et "marche", si on interprète "Thermostats" comme un regroupement de "ThermostatS", l'action "xxx" propage l'action à l'ensemble des instances du groupe ???
Pour les action/opération, essayez de suivre une règle de codage type "nom commençant par un verbe d'action puis le périmètre de l'action":
Ici, ça donnerait des noms "Arreter" et "Demarrer", ou encore si c'est pour un termostat unique "ArreterUnThermostat(std::wstring key)" et "DemarrerUnThermostat(std::wstring key)", etc...
La classe Relai (relais?), c'est beaucoup beaucoup trop complexe et vague, vraisemblablement ambiguïté entre classe et instance/objet.
Essayez de lire un cours complet sur le C++ ou tout du moins la POO pour rendre ces diagrammes "clairs" et efficaces.
https://www.academie-francaise.fr/si...tions_1990.pdf
Malheureusement, il s'agit là d'une des catastrophes introduites par la réforme orthographique de 1990. :no:
J'étais personnellement en classe de 4ème quand elle a eu lieu et personne, ni élève ni enseignant, n'avait jamais eu l'idée d'appliquer ces recommandations. Il y avait même eu une opposition forte aussi bien des adultes que des jeunes à l'époque et personnellement, j'ai toujours préféré appliquer une orthographe aussi traditionnelle que possible.
Ce qui m'étonne, en revanche, c'était que j'étais resté persuadé que cela ne concernait que des détails mineurs et que l'on devait les horreurs telles que « relai » ou « ognon » (si, si) à une circulaire assez récente. C'est même à cette époque que les magasins « le relais », par exemple, sont devenus « relay » dans les aéroports et les gares, histoire de couper la poire en deux. Par contre, impossible de retrouver cette directive et après quelques années, il semble que les gens aient fini par l'abandonner d'eux-mêmes.
Ma remarque n'était pas liée aux "s" mais plus à la Case.
Et pour le coup, j'exècre l'approche Académie Française qui veut faire du Français un putain de Musée poussiéreux à centrifugeuses d'entre-soi intégrée.
Une langue qui n'évolue pas est une lague morte.
Donc "Vive Relai", même si, dans le diagramme du PO (Posteur Original), il fait bien trop de choses => "RelaySet" :aie:
P.S.: en 1990, je passais le BAC et bien formaté par cette éducation nationale "conservative" et "CSP reproductive", bien plus hussarde de "la bien-pensance bourgeoise" que de la "république".
Et les statistiques actuelles montrent que ça bien empiré depuis.
Sans la dernière réforme de l'orthographe du XIXème, "acceptée partiellement par l'académie", on serait toujours avec des "hostel" des "forest" des "estoit" (à la place d'était) des "sçavoir" (à la place de savoir), etc...(et ognon était déjà au programme mais les gardiens du Musée/académiciens aiment bien leurs horreurs logiques : on les remercie pour les 4 fois plus de dyslexique en France qu'en Italie ou en Espagne) .
Et on passera sur le foutage de gueule étymologique du "nénuphar" de Blanquer, c'est du farsi pas de grec, nénufar bordel !!!
Ca pique aussi pour moi. :aie:
Je suis d'un âge certain et ma plasticité mentale n'est plus. :fou:
Mais comme une classe "relais" surplombe une classe "thermostats" avec des machins pas clairs sur "groupement ou pas", c'est mon cerveau d'analyse codesque et pas mon cerveau traumatisé à grand coup de dictées de primaire qui est en charge de mon système 1 (automatisme énergético-économique). :lefou:
C'est aussi pour ça que programmer en anglais, c'est plus "simple". (malgré les wolf => wolves ou autres half => halves, etc... )
Désolé, je suis assez chatouilleux sur la "prescriptivité" des éditorialistes du Figaro sur cette panique morale de "tout fout le camp".
Merci pour ta bienveillance @Obsidian, malgré mon attitude de "tro* d* cu*". :oops:
@ludoiphone, les noms sont importants, mais la simplicité/logique surpasse "la grammatico-synthaxico-lexico-exactitude" des académiciens en carton. :king:
En effet, et c'est souvent beaucoup plus concis ! Et ça ne date pas d'hier. La langue est beaucoup plus ancienne que nous, naturellement, mais quand il fallait coder sur quarante colonnes et 64 Ko de mémoire, ça prenait tout son sens.
Tu mets aussi le doigt sur un point particulier : le choix du pluriel ou du singulier dans les conventions de nommage. Le bon sens « technique » nous suggère d'utiliser le singulier partout mais à l'usage, ça va souvent à l'encontre des habitudes lorsque le pluriel se justifierait dans le langage courant…
merci,
j'ai fais des modifications sur : https://github.com/ludoiphone/gainab...tion/tree/main
aprés c'est un peut le brouillard , je suis completement perdu .
j'ai tous le fonctionnement en tete (voir le diagramme : Diagramme.pdf)
mais le plus difficile est de le transformer en code et surtout dans les regles de l'art pour un debutant.
je sais plus par ou commencé !! et quoi utiliser , ca me deprime!
de lire les cours POO c'est toujour sur des traitement text mais jamais dans ce que je souhaite faire .
est que les class ne sont pas compatible avec mon projets ??
C'est normal de galérer, mais on voit que vous avez "fréquenté" de mauvaises sources d'information.Citation:
aprés c'est un peut le brouillard , je suis completement perdu .
Vous avez de "mauvaises habitudes" qu'il faudra combattre, malheureusement.
C'est pour cela que j'insiste pour que vous preniez un peu de temps pour lire un "bon" cours de C++ comme celui de Zeste de Savoir, rapidement.
Et c'est un très bon début.Citation:
j'ai tous le fonctionnement en tete (voir le diagramme : Diagramme.pdf)
Le problème, c'est qu'il faut faire comprendre à un truc aussi débile qu'un ordinateur ce fonctionnement "désiré".
(Il y a peut-être des "trous" dans la conception de votre diagramme, mais je n'ai pas les connaissances pour le savoir.)
La boutade du canard en plastique n'est pas qu'une simple plaisanterie, c'est une vraie méthode d'externalisation des problématiques de programmation.
Votre question initiale était liée à l'utilisation de Qt, qui est une librairie C++ qui utilise massivement la POO.
Nous avons donc répondu en faisant l'assertion de la "maitrise" de la POO.
Ce n'est vraisemblablement pas le cas.
Le C++ est un langage multiparadigme, on n'ai pas obligé de faire de la POO (contrairement à JAVA ou C#), mais beaucoup d'outils du C++ reposent plus ou moins sur la POO.
C'est donc assez compliqué de s'en passer.
Désolé si nos conseils font très "règles de l'art", mais ce n'est que des conseils pour vous "simplifier" l'utilisation des outils qui nous sont offerts.Citation:
mais le plus difficile est de le transformer en code et surtout dans les regles de l'art pour un debutant.
Commencez par des POC.Citation:
je sais plus par ou commencé !! et quoi utiliser , ca me deprime!
Des petits projets qui ont pour but de comprendre des choses de manière isolé.
- Récupérer une température
- Récupérer plusieurs températures
- Actionner un machin dans le système.
- Actionner un machin dans le système en fonction d'une température.
- Récupérer une température durant un certain temps à une cadence donnée.
- etc...
Il y a de grandes chances que vous ne récupériez pas le code créé pour ces POC mais vous aurez de bonnes bases pour commencer le "vrai" projet.
LOL, le "traitement de texte", c'est un cadre d'expérimentation créé par le "Gang of Four" (https://www.digitalocean.com/communi...esign-patterns) pour présenter dans les années 1990 différents Design Patterns, outils encore assez expérimentales à cette époque.Citation:
de lire les cours POO c'est toujour sur des traitement text mais jamais dans ce que je souhaite faire .
Quand vous faites un bouquin ou un cours, il est très attrayant de faire cela dans un "contexte" particulier, pour ne pas avoir à présenter un nouveau contexte pour chaque notion à aborder.
Ce contexte n'est là que pour créer un cadre d'expérimentation.
Celui du "traitement de texte" est clairement fait pour des personnes qui maitrise déjà assez bien la POO, lectorat cible du bouquin du "Gang of Four".
Dans ce forum, @koala01, un très gros intervenant ici, a écrit un bouquin sur comment bien écrire du code et a pris comme contexte la programmation d'un jeu d'échec, correspondant vraisemblablement au lectorat cible de son bouquin.
Vous devez être capable de vous "extraire" du contexte particulier d'un cours ou d'un bouquin. Ce n'est qu'une illustration de l'utilisation de concepts bien plus génériques que ce contexte particulier.
Oui, mais êtes-vous déjà compatible avec les classes ?Citation:
est que les class ne sont pas compatible avec mon projets ??
La POO a largement fait ces preuves depuis les années 60 (mais la conception objet a évoluée depuis, utilisez des sources récentes et de qualité, SVP).
Ce n'est pas forcément le paradigme de programmation le meilleur pour votre projet ou pour vous.
Mais en C++ il est central, bien que non nécessaire.
Essayez de faire de simples POCs, en vous passant de la POO, si nécessaire.
Vous n'avez pas appliqué nos conseils, pourtant assez directifs (trop directifs peut-être ?), comme le fait que DS18B20 fait trop de chose à la fois et mélange vraisemblablement classes et objets.
Que le constructeur de DS18B20 devrait avoir paramètre donnant le chemin vers la sonde.
Que le constructeur et le destructeur doivent être ensemble,
Que les variables globales, c'est mal.
Réduire au maximum le nombre d'include dans les .h
dans gpioPin.hpp, essayez d'utiliser le même niveau de "modernité" dans un même composant logiciel => utilisez "#pragma once" à la place de header guards "old school".Citation:
#pragma once
Dans "main.cpp", la variable "chrono" est utilisée avant d'être initialisée (votre compilateur aurait dû vous le signaler, non ?).
"production", c'est bizarre comme "Action" à faire.
Vous n'avez pas appliqué le conseil de "au lieu de faire des SetBidule partout, passez des objets qui permettent d'avoir l'information aux objets qui ont besoin de cette information".
Exemple :Citation:
Code:mode.SetTemperatureExt(sondeExt.GetTempExt());
Code:
1
2 DS18B20 temperatureExt; System system{temperatureExt};
Donc un "ContactThermostat", c'est un booléen ???Citation:
Code:bool GetContactThermostat
Je pense toujours que la lecture préalable d'un bon cours de C++ "moderne" serait très productif.
Coucou tout le monde :coucou:
Coucou bacelar ;)
Ta proposition de TRACE() avec _T est spécifique à Windows; or, je crois que le "poster" tourne sur "RPI", du Linux donc.
Ça fait très longtemps que je n'ai pas pratiqué, mais j'ai souvenir d'une bibliothèque multiplateforme qui fait le job, "spdlog".
Si l'on ne veut pas s'encombrer avec, voici une version sommaire et portable de "TRACE()". Elle s'activera lors d'un "Build" (construction) de type "Debug".
Je viens d'ajouté "sommaire" parce que tu as très justement abordé le problème du "flood" du terminal. À ce sujet, dans la version plus complète que j'avais écrite, il y avait du TRACE à toutes les sauces: TRACE_RED, TRACE_GREEN, etc., TRACE_LEVEL, TRACE_WARNING, TRACE_TITLE, TRACE_BEEP, etc., etc., et effectivement ça aide pas mal.
Mais encore une fois, "spdlog" peut faire le job.
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 //Overview of a C++ TRACE() implementation //This header must be included before all others in each source file. #pragma once #if ! defined NDEBUG #define DEBUG_MODE_ENABLED 1 #else #define DEBUG_MODE_ENABLED 0 #endif enum {debug_mode_enabled= DEBUG_MODE_ENABLED}; #include <cstdio> //Variadic Macros, officially since C++11 (and C99 for info), but maybe before as compiler extension #define TRACE(...) do {if (debug_mode_enabled) std::fprintf(stderr, __VA_ARGS__);} while(0) //Must be used like printf(), for example: //TRACE("Hello, %s!", "trace");
En tout cas c'est un comportement indéfini, et sur PC, généralement un segfault.
C'est peut être une coquille, mais je compte 4, voire 6 autres problèmes.
Aussi dans le deuxième code, std::make_unique peut lancer une exception. Mais, contrairement au premier, ce n'est pas souligné. Ça laisse croire que la gestion des exceptions devient inutile avec les "smart pointers". En l'état, les deux codes ne sont pas comparables.
L'appareil que j'utilise à cet instant ne permet pas la consultation des PDF en pièces jointes. Des images et du texte dans le corps des messages auraient été préférables.
Je ne vais pas épiloguer sur les difficultés du langage C++ mais il ne faut pas se priver d'en explorer d'autres. Plus on est à l'aise avec un langage et mieux c'est, si c'est un langage qu'on aime, c'est encore mieux.
Cela dit, le fait d'avoir déjà un projet est un atout. Il faut sélectionner une portion de C++ qui va bien, quelques briques logiciel, et ce sera sur les rails.
Mais ATTENTION!!! L'aspect sécurité des personnes est ici primordial. Si vous n'êtes pas en mesure de l'assurer côté matériel, ne vous engagez pas dans cette voie. Je passe sous silence les problèmes de normes, réglementations, certifications pour lesquels vous êtes certainement au fait. Mais surtout, pensez à bien vérifier votre marge de manoeuvre par rapport à votre contrat d'assurance habitation. Ce genre de négligence ne pardonne pas.
Pour en revenir à l'objet de la discussion, si je traduis bien, il y a deux systèmes chaud, froid, et le but est qu'ils ne fonctionnent pas en même temps. Ensuite apparaissent les soucis de la mise en forme de tout ça. J'y reviendrais.
Pour le premier point, le plus accessible pour un débutant c'est encore de coller à la réalité. Quand il y a un système de chauffage et un autre de climatisation, généralement, il y a un surensemble qui gère le tout, plus ou moins. Le "plus ou moins" c'est parce qu'il existe un troisième système asservi qui est le thermostat d'ambiance.
Son rôle est de réclamer la production de chaleur ou de fraicheur en fonction de sa programmation et des températures des milieux dont il a la charge.
Pour ce qui est du transport et de la distribution de cette énergie produite, les manières de faire sont tellement nombreuses que, dans les faits, ce n'est qu'une extension du système.
Bref, ce surensemble peut s'appeler une pompe à chaleur, un climatiseur réversible, une bouillote... qu'importe ...
Du point de vue du code, ça pourrait donner ce genre de composition: (c'est du vrac, une illustration)
Je fais l'effort d'y mettre un peu de français pour ne pas perdre l'intéressé.
Cette classe n'a pas besoin d'être plus fournie. Comme énoncé précédemment, j'ai anticipé le problème des "while (1)", de Qt (qui peut être invasif), et la façon dont l'intéressé aborde ces choses. En effet, il y a souci de partage des responsabilités et d'orchestration du tout.Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 class Froid; class Chaud; enum Mode {OFF, CHAUFFAGE, CLIM, AUTO, MAINTENANCE}; enum class Sub_Mode_Chauffage {ECO, COMFORT}; // dans l'optique du patron "stratégie" introduit par Bacelar //... class PAC // pompe à chaleur { public: void enable_chaud() {froid.disable(); chaud.enable();} void enable_froid() {chaud.disable(); froid.enable();} void disable() {froid.disable(); chaud.disable();} std::string get_status() const { return froid.get_status()+ " | "+ chaud.get_status();} //void set_mode(Mode m) {mode= m;} //... private: Chaud chaud; Froid froid; //integrated thermostat //Sonde exterieur{id_abc}; // //Sonte interieur{id_def}; //Sonde sejour{id_ghi}; //and/or maybe //Thermostat remote_thermostat; //... std::atomic<Mode> mode{OFF}; // => #include <atomic> };
Compte tenu des bouts de codes écrits par le "poster", je pense qu'il sera plus à l'aise avec une architecture MVC (model-view-controler, modèle-vue-contrôleur).
La vue, c'est l'interface utilisateur, le contrôleur, c'est l'objet PAC, le modèle serait une ou plusieurs structures/classes de données (), intégré à PAC, ou pas, alimenté par ce dernier, et utilisé par la machine à états.
Elle-même pourra y écrire des données qui seront lues par PAC, éventuellement aussi par un terminal de monitorage. Il y a de quoi faire, tout dépend du degré de sophistication recherché.
très schématiquement:
par exemple, PAC::Mode peut être considéré comme un modèle. (conf. la ligne avec Mode mode{OFF}; )Code:view(s) <-> controler(s) <-> model(s) <-> (finite-state) machine ( |hardware)
Cette fonction (qui s'appelle un arbre de décision), en même temps qu'elle s'allongera, vous ressentirez le besoin de factoriser.Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 void run_machine(const PAC& pac) { //may be (later) PAC member function: void PAC::run_machine() { // or void run_machine(const Model& model) { //Trace only when the state changes //something like: auto trace_condition{ __LINE__ }; // <= (reminiscence) TRACE_CONDITION_INIT(optional_condition_type(BASIC | TREE), opt_name, opt_condition); while (pac.get_mode() != SHUTDOWN) { //or (model.mode != SHUTDOWN) // or ( ! must_exit()) std::this_thread::sleep_for(std::chrono::seconds(1)|1s); //prevent high CPU load if (pac.termostat.wath_requested() == Request::heating) { if (pac.get_mode() == CHAUFFAGE) { //auto debug_mode_enabled= DEBUG_MODE_ENABLED & (__LINE__ != trace_condition); trace_condition= __LINE__; // <= TRACE_CONDITION_NOTRACE_ON_MATCH(..); _ON_MISMATCH(...); TRACE("Production et acheminement de la chaleur en cours...\n"); TRACE("Utilisation de l'algo %s...\n", (pac|termostat).get_sub_mode_chauffage_name()); } else { //TRACE_CONDITION_NOTRACE_ON_MATCH(..) TRACE("Production de chaleur requise par le thermostat, mais interdite par le PAC.\n"); } // .... } turn_off_hardward(); }
Il s'en dégagera très vite des unités logiques, que vous pourrez modéliser, dans de simples fonctions ou en classes pour avoir quelque chose de "SOLID" (conf. définition sur Wikipedia) suivant vos progrès, évidemment.
Par ailleurs, c'est aussi une forme simple de machine à états, elle permettra de faire comprendre votre raisonnement et à vous de vous organiser, avec l'impératif que la boucle doit tourner continuellement, donc pas d'autre "pause" que le seul std::this_thread::sleep_for déjà en place.
Une bibliothèque d'automate simple toute faite aurait été préférable, mais je n'en connais pas. Faute de mieux, vous pourrez au moins avancer sur votre projet.
Bon, il faut que j'abrège.
Peut-être un mot pour la temporisation, qui peut se faire avec un chronomètre
Pour avoir quelque chose de rapidement fonctionnel, utilisez les threads (fils d'exécutions) (c++20 std::jthread).Code:
1
2
3
4
5 start= std::chrono::steady_clock::now(); // => #include <chrono> ... if (this_state_is_in_progress()) { if (std::chrono::steady_clock::now() - start > tempo) {set_next_state();} } //
Éventuellement, des fonctions libres. Faites tout dans un seul et même fichier (.cpp) pour garder une vue d'ensemble.
Déplacez au fur et à mesure les blocs de code "matures" qui vous en empêchent.
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 void input(PAC& pac) { //input interface, std::cin, IHM: TUI (ncurses), GUI (frameworks Qt, wxWidgets, ImGUI), Interface-Machine-Machine (IPC...), RPC, ... while (wait_for_user_request && user_request != exit_request) { pac.deal_with(user_request); } //maybe at first: pac.set_mode(SHUTDOWN); } void output(const PAC& pac) { //ouput interface, std::cout, IHM widgets... while (waiting_for_signal, _for_callback or _for_countdown*) //* = polling (scrutation) output_interface(pac.get_status()); } int main() { PAC pac; auto machine{std::jthread{run_machine, std::ref(pac)}}; // => #include <thread> auto output_view{std::jthread{output, std::ref(pac)]}; input(pac); }
PS @Les-poteaux
Je viens de taper sur un minuscule clavier... donc, désolée pour les fautes...
Oui parce qu'à la base, je voulais juste faire un petit coucou ... ;)
Allez, @++
merci a vous tous ,
la comprehension de kaitlyn sur mon projet est au top ! merci.
apres , j'aimerai commencer peut-etre par revoir le code des DS18B20 pour comprendre petite a petit (doucement mais surement) .
au final j'ai changer la bibliotheque de mes pins , je vais utiliser WiringPi (tres connu).
puis la methode de TRACE me plait bien , mais en vous lisant j'ai essayer de l'inclure dans mon code , mais je ne vois pas trop comment faire pour le compiler avec cmake , si vous avez un exemple merci .
je vous remerci a tous du temps que vous m'accorder.
Salut tout le monde,
Pour intégrer TRACE() à ton projet, il suffit de copier le code correspondant dans un fichier d'entête (.h), ensuite d'inclure ce dernier dans tous tes fichiers sources (.cpp) et avant toutes les autres inclusions.
Code:
1
2
3
4
5
6
7 #include "le_fichier_de_trace.h" /* il contient le code précédemment présenté. */ #include <blablabla> //ect int main() { TRACE("je trace..."); }
Le fichier d'entête ne changera rien par rapport à CMake, ce n'est pas une source, il ne peut pas être compilé.
De même, je n'ai pas d'exemple de CMake à te fournir, car j'imagine que c'est en rapport avec Qt.
Cependant, une rapide recherche montre qu'il y a ce qu'il faut sur leur site :
https://doc.qt.io/qt-6/cmake-get-started.html
https://doc.qt.io/qt-6/cmake-manual.html
Salut,
J'ai une petite anecdote sympa.
Hier soir, j'ai visionné le 4e opus de la saison 3 de Foundation, une adaptation des romans d'Isaac Asimov.
Le Frère au Grand Jour (l'Empereur Cléon) s'adresse à Demerzel (androïde féminin) en ces termes (de mémoire):
Pour le contexte, Demerzel a effacé la mémoire de l'amoureuse de Cléon, puis l'a congédiée. Il est très en colère.
Citation:
Cléon: Sais-tu ce que c'est que d'avoir une connexion profonde avec l'être aimé ?
Citation:
Demerzel: Oui ! J'ai été conçue pour avoir des connexions avec mes semblables. On appelle ça l'entrelacement, au point de ne former qu'un.
:DCitation:
Cléon: Oh! Un peu comme un thermostat parle à une chaudière ? C'est vrai que c'est très intime. Au temps pour moi.
salut a vous , j'essais de comprendre
enum Mode {OFF, CHAUFFAGE, CLIM, AUTO, MAINTENANCE}; ca je comprends.
ce que je comprend pas :
et comment faire pour le get_mode ?? dois je creer un switch case ou autre en return le enum Mode ??Code:
1
2
3 std::string get_status() const { return froid.get_status()+ " | "+ chaud.get_status();} //void set_mode(Mode m) {mode= m;}
std::atomic<Mode> mode{OFF}; // => #include <atomic> ??
merci
Salut,
std::atomic, c'était dans l'éventualité d'avoir à protéger la variable d'accès concurrents, notamment avec les "threads".
Pour te donner une image, si tu vas dans un restaurant qui n'applique pas l'atomicité, en tant que client, tu risques de recevoir une assiette vide ou insuffisamment garnie (y compris dans les restaurants chiques où le garnissage est inversement proportionné à l'addition).
Dans le code, ça revient à écrire std::atomic<Mode> mode au lieu de Mode mode. Le compilateur s'occupe du reste. Bien sûr, il faut un #include <atomic> en amont.
Pour ce qui est du reste, sauf le set_mode(), ce n'était que des illustrations de mécanismes sous-jacents. Car dans les faits, rien n'oblige à avoir ce get_status() en particulier, mais juste quelque part, à rendre compte de l'état du système. Par exemple, en activant ou non un symbole sur un afficheur. De même pour get_mode(), si le système de chauffage est désactivé, les demandes de production de chaleur par le thermostat seront juste ignorées. En fait, les bouts de codes faisaient juste état de possibles orientations, sauf à être imposées par l'écosystème, bien entendu.
je vais donner un exemple simpliste et abordable (j'espère) et sans introduire de nouvelles notions qui risquent de causer des blocages :
Comme écrit en préambule, c'est loin d'être un code compact et sophistiqué (avec même une erreur (ou plutôt contrainte) de conception), mais plutôt verbeux et, ben j'ai finalement rebroussé chemin pour le rendre incomplet.. Du coup, pour qu'il fonctionne, il y a des modifications qui sont nécessaires. C'est laissé comme "exercice" compte tenu de la nature du projet, histoire de quand même faire un point.Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 class Froid { private: void disable() {enabled= false;} void display_status() { if (enabled) {TRACE("Froid: ENABLED\n");} else {TRACE("Froid: DISABLED\n");} } bool enabled{false}; }; enum Mode {OFF, CHAUFFAGE}; class PAC { // Pompe_A_Chaleur public: void set_mode(Mode m) { mode= m; switch (m) { case OFF: disable_all(); case CLIM: enable_froid(); break; } display_status(); } Mode get_mode() {return mode;} // en réponse à la question précédente, si besoin d'un get_mode() private: Chaud chaud{}; void enable_chaud() {froid.disable(); chaud.enable();} Mode mode{OFF}; }; int main() { PAC pax; TRACE("Setting CLIM mode...\n"); pac.select_mode(CLIM); TRACE("Setting chauffage mode...\n"); pac.select_mode(chauffage); }
bonjour , donc j'ai fais quelque chose comme ce qui suit
comment puis je incorporer le chrono pour remplacer la boucle while ,Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113 #include <chrono> #include "Trace.h" #include "ds18b20.h" #include "Thermostats.h" class Froid { public: void disable_froid() {enabledFroid = false;} void enable_froid() {enabledFroid = true;} void display_status_froid() { if (enabledFroid) {TRACE("Froid: ENABLED\n");} else {TRACE("Froid: DISABLED\n");} } private: bool enabledFroid {false}; }; class Chaud { public: void disable_chaud() {enabledChaud = false;} void enable_chaud() {enabledChaud = true;} void display_status_chaud() { if (enabledChaud) {TRACE("Chauffage: ENABLED\n");} else {TRACE("Chauffage: DISABLED\n");} } private: bool enabledChaud {false}; }; enum Mode {OFF, CHAUFFAGE, FROID, AUTO}; class PAC { // Pompe_A_Chaleur public: void set_mode(Mode m) { mode = m; switch (m) { case OFF: TRACE("OFF\n"); disable_all(); break; case FROID: TRACE("FROID\n"); froid.enable_froid(); froid.display_status_froid(); break; case CHAUFFAGE: TRACE("CHAUFFAGE\n"); chaud.display_status_chaud(); break; case AUTO: TRACE("AUTO\n"); if (read_sensor_outside() <= 13.5) {m = CHAUFFAGE;} else {m = FROID;} break; } } void display_temperature() {TRACE("sensor outside : %2.2f\n", read_sensor_outside());} double read_sensor_outside() {return sensorOutside.get_tempExt();} bool read_switch_room() {TRACE("thermostat is: %s", switchRoom.get_etatThermostat() ? "true\n" : "false\n"); return switchRoom.get_etatThermostat();} Mode get_mode() {return mode;} // en réponse à la question précédente, si besoin d'un get_mode() private: Chaud chaud{}; Froid froid{}; DS18B20 sensorOutside{}; Thermostat switchRoom{}; Mode mode{OFF}; void disable_all() {chaud.disable_chaud(); froid.disable_froid();} }; int main() { PAC pac; pac.display_temperature(); if (pac.read_switch_room()) { if (pac.read_sensor_outside() <= 13.5) {TRACE("Setting chauffage mode...\n"); pac.set_mode(CHAUFFAGE);} else {TRACE("Setting refroidissement mode...\n"); pac.set_mode(FROID);} } else {TRACE("Setting pac mode...\n"); pac.set_mode(OFF);} }
j'essais plein de chose avec les marqueur du temp mais je n'y arrive pas .
Salut,
C'est dommage, tu es parti trop loin et avec précipitation. J'aurais préféré une réponse plus tôt, où tu te serais contenté, comme demandé, de faire fonctionner le code précédent. C'est-à dire que dans PAC, il y a les fonctions enable_chaud() {froid.disable(); chaud.enable();}et enable_froid() {chaud.disable(); froid.enable();} permettant de garantir leur exclusion mutuelle (en plus, elles étaient écrites dans un code précédent). L'étape suivante était de restreindre les interfaces de chaud et froid pour éviter le genre de manipulation hasardeuse que tu as faites dans ton switch. Et maintenant il est question de chrono.
Le chrono, c'était pour les temporisations. Quelle est ta question exactement ?
je suis d'accord je me suis éparpillé ,
donc j'avait reussi a faire fonctionner le code du depart
et en sortie :Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91 #include <thread> #include "Trace.h" #include "ds18b20.h" class Froid { public: void disable() {enabled = false;} void enable() {enabled = true;} void display_status() { if (enabled) {TRACE("Froid: ENABLED\n");} else {TRACE("Froid: DISABLED\n");} } private: bool enabled {false}; }; class Chaud { public: void disable() {enabled = false;} void enable() {enabled = true;} private: void display_status() { if (enabled) {TRACE("Chauffage: ENABLED\n");} else {TRACE("Chauffage: DISABLED\n");} } bool enabled {false}; }; enum Mode {OFF, CHAUFFAGE, FROID, AUTO}; class PAC { // Pompe_A_Chaleur public: void set_mode(Mode m) { mode = m; switch (m) { case OFF: disable_all(); case FROID: enable_froid(); break; case CHAUFFAGE: enable_chaud(); break; } froid.display_status(); } Mode get_mode() {return mode;} // en réponse à la question précédente, si besoin d'un get_mode() void display_temperature() {TRACE("sensor outside : %2.2f\n", sensorOutside.get_tempExt());} private: Chaud chaud{}; Froid froid{}; DS18B20 sensorOutside{}; Mode mode{OFF}; void enable_chaud() {froid.disable(); chaud.enable();} void enable_froid() {chaud.disable(); froid.enable();} void disable_all() {froid.disable(); chaud.disable();} }; int main() { PAC pac; TRACE("Setting froid mode...\n"); pac.set_mode(FROID); TRACE("Setting chauffage mode...\n"); pac.set_mode(CHAUFFAGE); }
Setting froid mode...
Froid: ENABLED
Chauffage: DISABLED
Setting chauffage mode...
Froid: DISABLED
Chauffage: ENABLED
pour les tempos c'est bon j'ai compris comment il fonctionne
Code:
1
2
3
4
5 while(1) { std::this_thread::sleep_for(std::chrono::seconds{2}); pac.display_temperature(); // s'affiche toute les 2 secondes. }
Salut,
À dire vrai, ça avait déjà commencé il y a 15 jours avec CMake. Des jours définitivement perdus, puisque pour un temps, je ne serais probablement plus en mesure de participer à la discussion, donc une contribution en moins.
Pour ce qui est du reste, ta sortie ne correspond pas au code présenté, peut-être des artefacts de rééditions.
Aussi, dans la classe PAC, il manque des break dans le switch, certainement déjà signalés par compilateur. Si ce n'est pas le cas, il faut voir les options d'alertes -Wall -Wextra. Il manque aussi la fonction void display_statut(){froid.display_status(); chaud.display_status();}, qu'il faut appeler en fin du switch.
Le nom mode FROID, je ne sais pas ce qu'en pensent mes camarades, mais moi, ça m'évoque l'HIVER, le GRAND_FROID, c'est-à-dire la nécessité d'augmenter la puissance du chauffage.
Et si tu veux un mode AUTO, schématiquement, ça pourrait se traduire par un enable_auto(){disable_all();}, chaud ou froid sera activé à la demande du thermostat. Conf le message de Cléon, l'histoire du thermostat qui parle à la chaudière. Je n'avais pas cité cette conversation juste pour le fun, mais parce qu'il était possible d'y déceler un "patterrn", donc très à propos pour cette discussion.
c'est une erreur de ma part pour le break ;
apres les thermostats reglable oui parle a mon system (les thermostats reste que des entrées pour mon cas) NC ou NO (0 ou 5vdc) qu'il renvoi juste un bool,
le froid n'existe pas !!! c'est un manque de chaleur, clim c'est climatiseur ne fait pas forcement du chaud mais que du froid , pac c'est pompe a chaleur (convertible ou pas ) ne fait pas forcement du froid (pac dans un seche linge il sert qu'as faire du chaud). bref , mois c'est un groupe (pac aire/aire convertible qui fonctionne avec un vanne 4 voie (sur la partie frigorifique qui inverse le circuit pour que quand il fais froid dehors j'ai du chauffage a l'interieur et vis versa ), le tous est controler par des thermostat radio dans chaque piece pour ouvrir le volet de la piece qui demande du froid ou du chaud en fonction de la saison .
automatique est le fais que l'appareil n'as plus besoin de manipulation elle le gere toute seule (entre les saisons ete et hiver) a la demande de l'utilisateur .
le mode froid c'est que nous somme en été et le mode chaud est que nous somme en hiver.
tous les modes(auto, froid, chaud) sont gerer par les thermostats et le mode chaud ou froid est gerer par la temperature moyenne annuel de ma region (14°C)
l'automatique (entre les saisons hiver ou été) gere la temperature ambiante de la maison (23°C si en dessous de 21°C passe en mode chauffage ou 25°C passe en mode froid)
desole je me suis mal fais comprendre !
Cela fait partie des nombreuses raisons qui m’ont poussée à écrire que, même si le système sous-jacent était une bouillotte, que ça n'avait aucune importance.
Mais les actions demandées, là ça doit être clair. Quand on parle de chauffage/clim c'est clair pour tout le monde, été/hiver, c'est clair pour tout le monde, chauffage/froid, il n'y a plus personne. Des invités chez toi, s'ils savent qu'il peuvent avoir plus de fraicheur, ils te demanderont de mettre la clim s'il te plait. Même si tu n’as pas de climatiseur, la demande est claire. Bon, au pire, tu pourras leur donner un éventail. Et si je ne me trompe pas, @bacelar t'avait déjà rappelé l'importance des noms.
Pour le mode AUTO, même si ton thermostat ne sait faire que du on/off, ce n’est pas un problème non plus. Ta PAC activera ce qu'il convient au moment où son entrée sera signalée, et en fonction des conditions fixées.
merci , pour refroidissement je vais mettre cooling et heating pour chauffage , je pense que se serais plus clair comme cela.
pour ce bout de code si dessu,Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 void run_machine(const PAC& pac) { //may be (later) PAC member function: void PAC::run_machine() { // or void run_machine(const Model& model) { //Trace only when the state changes //something like: auto trace_condition{ __LINE__ }; // <= (reminiscence) TRACE_CONDITION_INIT(optional_condition_type(BASIC | TREE), opt_name, opt_condition); while (pac.get_mode() != SHUTDOWN) { //or (model.mode != SHUTDOWN) // or ( ! must_exit()) std::this_thread::sleep_for(std::chrono::seconds(1)|1s); //prevent high CPU load if (pac.termostat.wath_requested() == Request::heating) { if (pac.get_mode() == CHAUFFAGE) { //auto debug_mode_enabled= DEBUG_MODE_ENABLED & (__LINE__ != trace_condition); trace_condition= __LINE__; // <= TRACE_CONDITION_NOTRACE_ON_MATCH(..); _ON_MISMATCH(...); TRACE("Production et acheminement de la chaleur en cours...\n"); TRACE("Utilisation de l'algo %s...\n", (pac|termostat).get_sub_mode_chauffage_name()); } else { //TRACE_CONDITION_NOTRACE_ON_MATCH(..) TRACE("Production de chaleur requise par le thermostat, mais interdite par le PAC.\n"); } // .... } turn_off_hardward(); }
comment fonctionne dans cette fonction la class en reference ?
merci .
Attention, le jargon technique est toujours plus précis que les ambiguïtés du quidam.
Donc les noms sont importants mais quand ils sont précis.
L'interface utilisateur ne doit pas être jargonneux mais c'est pour ça qu'on a tendance à concevoir l'interface à part, plus tard, faisant le bon entre un outil utilisable par un "rookie" mais facilement maintenable par un professionnel du domaine.
Je ne suis pas sûr que le multithreading soit la manière de faire la plus simple pour un débutant.
Vous êtes sûr ?Citation:
Code:std::chrono::seconds(1)|1s
Je ne suis pas sûr que vous avez pris le temps de faire des POC intermédiaires.
Qu'entendez-vous par "class en reference" ?Citation:
cette fonction la class en reference ?
l'objet pas en paramètre de la fonction, qui est passé en référence constante ?
Salut ,
coucou toi,
Oui, il cite un pseudocode d'un de mes messages (#62). Il ne l'a pas balisé comme il se doit, et hors contexte, effectivement, ça prête à confusion. Dans cette expression, j'ai formalisé le "or", alors qu'un peu plus loin, il est en toutes lettres.
Ben, sans, ça reviendrait un peu à coder l'équivalent d'une boucle de jeu. Avec l'interface graphique, la gestion des timings, la nécessité d'un watchdog, c'est carrément hors de sa portée. Un projet comme ça devrait même être scindé en plusieurs processus, notamment pour des modifs de sécurité, mais avec les IPC, ce sera pareil. Il pourrait aussi se reposer sur les rappels et minuteries de l'OS, de Qt, mais je vois ça comme des entraves. Donc c'est un peu ce qui a motivé la proposition MVC+Threads détaillée dans le même précédent message (#62). Je te laisse voir...
IHM + multithread, c'est le début des emmerdes.
On peut très bien faire un calendrier des évènements "planifiés" et ne garder qu'une pompe à message.
Pour la sécurité, des watchdog dans des programmes indépendants est bien plus "safe".
salut a tous ,
donc j'ai fait ce bout de code , je pense qu'il ya beaucoup de chose a voir ,
j'ai supposé que tous ce qui est display est eventuellement pour l'interface graphique ?
je pense aussi qu'il faut que je recrée soit des nouvelle enum pour les differents etats de chaque objet (froid, chaud, auto et maintenance)
le plus difficile a mon avis c'est les temporisation de chaque etat de ma machine en fonction du mode que je suis . meme ci deja la c'est pas simple pour moi .
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147 #include <thread> #include <iostream> #include <string> #include "Trace.h" #include "ds18b20.h" #include "Thermostats.h" #include "Relay.h" class Cooling { public: void disable() {enabled = false;} void enable() {enabled = true;} void display_status() { if (enabled) {TRACE("Froid: ENABLED\n");} else {TRACE("Froid: DISABLED\n");} } private: bool enabled {false}; }; class Heating { public: void disable() {enabled = false;} void enable() {enabled = true;} void display_status() { if (enabled) {TRACE("Chauffage: ENABLED\n");} else {TRACE("Chauffage: DISABLED\n");} } private: bool enabled {false}; }; class Automatic { public: void disable() {enabled = false;} void enable() {enabled = true;} void display_status() { if (enabled) {TRACE("Automatique: ENABLED\n");} else {TRACE("Automatique: DISABLED\n");} } private: bool enabled {false}; }; enum Mode {OFF, HEATING, COOLING, AUTO, MAINTENANCE}; class PAC { // Pompe_A_Chaleur public: void run_pac() { while (1) { std::this_thread::sleep_for(std::chrono::seconds{2}); if (read_thermostat_room()) { if (read_sensorOutside() <= 13.5) { TRACE("Setting chauffage mode...\n"); set_mode(HEATING); } else { TRACE("Setting froid mode...\n"); set_mode(COOLING); } } else { TRACE("Setting off mode ...\n"); set_mode(OFF); } } } private: Heating chaud {}; Cooling froid {}; Automatic automatique {}; DS18B20 sensorOutside {}; Thermostat thermostatRoom {}; Relay orderRelay {}; Mode mode{OFF}; void set_mode(Mode m) { mode = m; switch (m) { case OFF: disable_all(); break; case COOLING: enable_froid(); break; case HEATING: enable_chaud(); break; case AUTO: enable_auto(); break; case MAINTENANCE: //enable_maintenance(); break; } display_status(); } Mode get_mode() {return mode;} // en réponse à la question précédente, si besoin d'un get_mode() double read_sensorOutside() {return sensorOutside.get_tempExt();} void display_outdoor_temperature() {TRACE("sensor outside : %2.2f\n", sensorOutside.get_tempExt());} bool read_thermostat_room() {TRACE("thermostat is: %s", thermostatRoom.get_etatThermostat() ? "true\n" : "false\n"); return thermostatRoom.get_etatThermostat();} void enable_chaud() {automatique.disable(); froid.disable(); chaud.enable(); orderRelay.highRelayEteHiver();} void enable_froid() {automatique.disable(); chaud.disable(); froid.enable(); orderRelay.lowRelayEteHiver();} void enable_auto() {froid.disable(); chaud.disable(); automatique.enable();} void disable_all() {froid.disable(); chaud.disable(); automatique.disable(); orderRelay.lowTousRelay();} void display_status() {display_outdoor_temperature(); froid.display_status(); chaud.display_status(); automatique.display_status();} }; int main() { PAC pac; pac.run_pac(); }
Ok, maintenant essayez de sortir la boucle de "run_pac" à l'extérieur.
(Ce qui est en rouge est fonction du framework/librairie graphique que vous souhaitez utiliser)Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 void run_pac() { if (read_thermostat_room()) { ... } ... } ... int main() { PAC pac; .... SetTimer(std::chrono::seconds{2}, pac::run_pac); .... do{ .... PompeAMessage(); .... }while(!Finir()); }
Ainsi, le code de la classe PAC n'est pas fonction du "framework/librairie graphique" et ne bloque pas toute la machinerie.
je suis desole je vois pas du tous comment faire? merci