Files
c_pompes/main.cpp
2025-12-07 16:04:44 +01:00

905 lines
22 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <unistd.h>
#include <ncurses.h>
#include <math.h>
#include <locale.h>
#include <array>
#include "main.hpp"
#include "AutomForArduino.cpp"
#include <prometheus/counter.h>
#include <prometheus/gauge.h>
#include <prometheus/histogram.h>
#include <prometheus/registry.h>
#include <prometheus/exposer.h>
#include <curl/curl.h>
#include <string>
#include <iostream>
#include <thread>
#include <atomic>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <csignal>
#include <chrono>
#include <cstring>
#undef timeout
#include "mqtt/async_client.h"
using namespace std::chrono_literals;
// Constantes de fonctionnement
#define LEVEL_MIN 2
#define FLOW_PER_PUMP 150
WINDOW *window;
int etape = 10; // Étape du grafcet : début Automatique
int bp_mode, bp_mode_fm;
unsigned short pompe1, pompe2, pompe3, pompe4; // bouton des pompes 0 (arrêt) / 1 (marche)
unsigned short pompe1_old, pompe2_old, pompe3_old, pompe4_old;
unsigned short sensor_max, sensor_high, sensor_low, sensor_min;
float TankInitalValue = 7;
TemporisationRetardMontee tempo1(1500);
TemporisationRetardMontee tempo2(3000);
TemporisationRetardMontee tempo3(4000);
TemporisationRetardMontee tempo4(6000);
// Prometheus
// ************************************************************
using namespace prometheus;
std::shared_ptr<Registry> registry;
Gauge *debit_entree = nullptr;
Gauge *debit_sortie = nullptr;
Gauge *debit_p1 = nullptr;
Gauge *debit_p2 = nullptr;
Gauge *debit_p3 = nullptr;
Gauge *debit_p4 = nullptr;
Gauge *tank_gauge = nullptr;
Counter *volume_p1 = nullptr;
Counter *volume_p2 = nullptr;
Counter *volume_p3 = nullptr;
Counter *volume_p4 = nullptr;
Histogram::BucketBoundaries buckets = {
2, 5, 6, 7, 8, 9, 9.5
};
Histogram *tank_histogram = nullptr;
// ************************************************************
int main()
{
/* Initialisation */
ConsoleInit();
AffichageWindow();
InitPrometheus();
ProcessInitKeyboard();
ProcessInitIO();
ProcessInitValues();
while (1)
{
int ch = getch(); // Lit l'entrée du clavier sans bloquer
// **** Break loop if escape key (27) is pressed
if (ch == 27 || _digital[OUT_END].ivalue) {
break;
}
// **** Beep
if (_digital[OUT_BEEP].ivalue)
{
beep();
_digital[OUT_BEEP].ivalue = false;
}
Process();
LireClavier(ch);
LireEntree();
EvolutionGrafcet();
Actions();
ProcessPrometheus();
ProcessMQTT(&client);
ProcessException();
usleep(100000);
}
endwin(); // Termine ncurses et rétablit le terminal
/* Arrêt */
try {
client.unsubscribe(TOPIC)->wait();
client.stop_consuming();
client.disconnect()->wait();
} catch(const mqtt::exception &exc){
std::cerr << "Erreur déconnexion MQTT: " << exc.what() << "\n";
}
//th_machine.join();
std::cout << "[MAIN] Terminé\n";
return 0;
}
/**
* Programme
*/
void LireEntree()
{
int input;
input = digitalRead(IN_KEYBOARD_A);
bp_mode_fm = (input > bp_mode);
bp_mode = input;
sensor_min = digitalRead(IN_SENSOR_MIN);
sensor_low = digitalRead(IN_SENSOR_LOW);
sensor_high = digitalRead(IN_SENSOR_HIGH);
sensor_max = digitalRead(IN_SENSOR_MAX);
}
void EvolutionGrafcet()
{
int etape_futur = etape;
if (etape < 10 && bp_mode_fm)
{
etape_futur = 10;
pompe1 = pompe2 = pompe3 = pompe4 = 0;
}
if (etape <= 2 && _digital[IN_KEYBOARD_1].raising)
{
pompe1 = !pompe1;
}
if (etape <= 2 && _digital[IN_KEYBOARD_2].raising)
{
pompe2 = !pompe2;
}
if (etape <= 2 && _digital[IN_KEYBOARD_3].raising)
{
pompe3 = !pompe3;
}
if (etape <= 2 && _digital[IN_KEYBOARD_4].raising)
{
pompe4 = !pompe4;
}
if (etape == 0 && !sensor_min)
{
etape_futur = 1;
}
if (etape == 1)
{
etape_futur = 2;
}
if (etape == 2 && sensor_min)
{
etape_futur = 0;
}
if (etape >= 10 && bp_mode_fm)
{
etape_futur = 0;
pompe1 = pompe2 = pompe3 = pompe4 = 0;
}
if (sensor_max)
{
pompe1 = pompe2 = pompe3 = pompe4 = 0;
}
/* Automatique */
if (etape == 10 && !sensor_low && !sensor_high)
{
etape_futur = 11;
}
if (etape == 11 && sensor_high)
{
etape_futur = 10;
}
if (etape == 11 && tempo1.getSortie())
{
etape_futur = 12;
}
if (etape == 12 && sensor_high)
{
etape_futur = 13;
}
if (etape == 12 && tempo2.getSortie())
{
etape_futur = 14; // Allumer le moteur 2
}
if (etape == 13 && tempo1.getSortie())
{
etape_futur = 10;
}
if (etape == 13 && !sensor_low && !sensor_high)
{
etape_futur = 12;
}
if (etape == 14 && sensor_high)
{
etape_futur = 15;
}
if (etape == 14 && tempo3.getSortie())
{
etape_futur = 16;
}
if (etape == 15 && tempo1.getSortie())
{
etape_futur = 13;
}
if (etape == 15 && !sensor_low && !sensor_high)
{
etape_futur = 14;
}
if (etape == 16 && sensor_high)
{
etape_futur = 17;
}
if (etape == 16 && tempo4.getSortie())
{
etape_futur = 18;
}
if (etape == 17 && tempo1.getSortie())
{
etape_futur = 15;
}
if (etape == 17 && !sensor_low && !sensor_high)
{
etape_futur = 16;
}
if (etape == 18 && sensor_high)
{
etape_futur = 19;
}
if (etape == 19 && tempo1.getSortie())
{
etape_futur = 17;
}
if (etape == 19 && !sensor_low && !sensor_high)
{
etape_futur = 18;
}
/* Fin de mode automatique */
if (etape != etape_futur)
{
etape = etape_futur;
}
}
void Actions()
{
digitalWrite(OUT_DISPLAY_GRAFCET, etape);
digitalWrite(OUT_DISPLAY_MODE, etape >= 10);
digitalWrite(OUT_PUMP_1, !sensor_max && (pompe1 == 1 || etape >= 12));
digitalWrite(OUT_PUMP_2, !sensor_max && (pompe2 == 1 || etape >= 14));
digitalWrite(OUT_PUMP_3, !sensor_max && (pompe3 == 1 || etape >= 16));
digitalWrite(OUT_PUMP_4, !sensor_max && (pompe4 == 1 || etape >= 18));
// digitalWrite(OUT_BEEP, etape == 1);
if (etape >= 11)
{
tempo1.activation();
tempo2.activation();
tempo3.activation();
tempo4.activation();
}
}
/**
* Process
*/
void ProcessInitKeyboard()
{
_keyboard[0].vKey = '1';
_keyboard[0].input = IN_KEYBOARD_1;
_keyboard[1].vKey = '2';
_keyboard[1].input = IN_KEYBOARD_2;
_keyboard[2].vKey = '3';
_keyboard[2].input = IN_KEYBOARD_3;
_keyboard[3].vKey = '4';
_keyboard[3].input = IN_KEYBOARD_4;
_keyboard[4].vKey = 'a';
_keyboard[4].input = IN_KEYBOARD_A;
_keyboard[5].vKey = 'x';
_keyboard[5].input = IN_KEYBOARD_X;
_keyboard[6].vKey = '6';
_keyboard[6].input = IN_KEYBOARD_7;
_keyboard[7].vKey = '7';
_keyboard[7].input = IN_KEYBOARD_8;
_keyboard[8].vKey = '8';
_keyboard[8].input = IN_KEYBOARD_9;
_keyboard[9].vKey = '9';
_keyboard[9].input = IN_KEYBOARD_0;
for (int i = 0; i < NB_KEYBOARD; i++)
{
_digital[_keyboard[i].input].mode = OP_DIGITAL_READ;
}
}
void ProcessInitIO()
{
pinMode(IN_KEYBOARD_1, IO_INPUT | DIGITAL);
pinMode(IN_KEYBOARD_2, IO_INPUT | DIGITAL);
pinMode(IN_KEYBOARD_3, IO_INPUT | DIGITAL);
pinMode(IN_KEYBOARD_4, IO_INPUT | DIGITAL);
pinMode(IN_KEYBOARD_A, IO_INPUT | DIGITAL);
pinMode(IN_KEYBOARD_7, IO_INPUT | DIGITAL);
pinMode(IN_KEYBOARD_8, IO_INPUT | DIGITAL);
pinMode(IN_KEYBOARD_9, IO_INPUT | DIGITAL);
pinMode(IN_KEYBOARD_0, IO_INPUT | DIGITAL);
pinMode(IN_KEYBOARD_X, IO_INPUT | DIGITAL);
pinMode(IN_SENSOR_MIN, IO_INPUT | DIGITAL);
pinMode(IN_SENSOR_LOW, IO_INPUT | DIGITAL);
pinMode(IN_SENSOR_HIGH, IO_INPUT | DIGITAL);
pinMode(IN_SENSOR_MAX, IO_INPUT | DIGITAL);
pinMode(IN_TANK_LEVEL, IO_INPUT | ANALOG);
pinMode(IN_FLOW_OUT, IO_INPUT | ANALOG);
pinMode(IN_FLOW_IN, IO_INPUT | ANALOG);
pinMode(IN_FLOW_DIF, IO_INPUT | ANALOG);
pinMode(IN_TANK_MIN, IO_INPUT | ANALOG);
pinMode(IN_TANK_MAX, IO_INPUT | ANALOG);
pinMode(IN_FLOW_CAP, IO_INPUT | ANALOG);
pinMode(IN_FLOW_1, IO_INPUT | ANALOG);
pinMode(IN_FLOW_2, IO_INPUT | ANALOG);
pinMode(IN_FLOW_3, IO_INPUT | ANALOG);
pinMode(IN_FLOW_4, IO_INPUT | ANALOG);
pinMode(OUT_PUMP_1, IO_OUTPUT | DIGITAL);
pinMode(OUT_PUMP_2, IO_OUTPUT | DIGITAL);
pinMode(OUT_PUMP_3, IO_OUTPUT | DIGITAL);
pinMode(OUT_PUMP_4, IO_OUTPUT | DIGITAL);
pinMode(OUT_DISPLAY_MODE, IO_OUTPUT | DIGITAL);
pinMode(OUT_DISPLAY_GRAFCET, IO_OUTPUT | DIGITAL);
pinMode(OUT_LEVEL_MIN, IO_OUTPUT | ANALOG);
pinMode(OUT_LEVEL_LOW, IO_OUTPUT | ANALOG);
pinMode(OUT_LEVEL_HIGH, IO_OUTPUT | ANALOG);
pinMode(OUT_LEVEL_MAX, IO_OUTPUT | ANALOG);
pinMode(OUT_FLOW_PER_PUMP, IO_OUTPUT | ANALOG);
pinMode(OUT_FLOW_OUT_AMPLITUDE, IO_OUTPUT | ANALOG);
pinMode(OUT_BEEP, IO_OUTPUT | DIGITAL);
_digital[OUT_PUMP_1].error = 30;
_digital[OUT_PUMP_1].efficacite = 1.0;
//_digital[OUT_PUMP_1].time = 4294967295; //UINT_MAX
_digital[OUT_PUMP_2].error = 30;
_digital[OUT_PUMP_2].efficacite = 0.72;
//_digital[OUT_PUMP_2].time = 4294967295;
_digital[OUT_PUMP_3].error = 10;
_digital[OUT_PUMP_3].efficacite = 1.0;
//_digital[OUT_PUMP_3].time = 4294967295;
_digital[OUT_PUMP_4].error = 30;
_digital[OUT_PUMP_4].efficacite = 1.0;
//_digital[OUT_PUMP_4].time = 4294967295;
}
void ProcessInitValues()
{
t_start = t_backup = millis();
srand(time(NULL));
_digital[IN_TANK_LEVEL].dvalue = _digital[IN_TANK_MAX].dvalue = _digital[IN_TANK_MIN].dvalue = TankInitalValue;
_digital[OUT_FLOW_PER_PUMP].dvalue = FLOW_PER_PUMP;
_digital[OUT_FLOW_OUT_AMPLITUDE].dvalue = 100.0;
_digital[OUT_LEVEL_MIN].dvalue = LEVEL_MIN;
_digital[OUT_LEVEL_LOW].dvalue = 6;
_digital[OUT_LEVEL_HIGH].dvalue = 7;
_digital[OUT_LEVEL_MAX].dvalue = 9.5;
_digital[IN_FLOW_OUT].dvalue = 100.0;
}
/**
* Fonctionnement des moteurs
*/
double ProcessMoteur(int i)
{
double vitesse = 1.0;
double t = _digital[i].time / 5000.0;
if (_digital[i].ivalue)
{
if (_digital[i].time < 2500)
{
vitesse = 4 * pow(t, 3.0);
}
else if (_digital[i].time < 5000)
{
vitesse = 1.0 - pow(2 - 2 * t, 3) / 2.0;
}
else
{
vitesse = 1.0 + 1.0 / (_digital[i].error * 2.0) - rand() / (double)RAND_MAX / _digital[i].error;
}
}
else
{
if (_digital[i].time < 2500)
{
vitesse = 1 - 4 * pow(t, 3.0);
}
else if (_digital[i].time < 5000)
{
vitesse = pow(2 - 2 * t, 3) / 2.0;
// vitesse = 1 - pow(t, 4.0);
}
else
{
vitesse = 0.0;
}
}
return _digital[OUT_FLOW_PER_PUMP].dvalue * _digital[i].efficacite * vitesse;
}
void ProcessException()
{
if (t_elapsed > 60) {
_digital[OUT_PUMP_1].mode = 0;
digitalWrite(OUT_PUMP_1, 0);
} else if (t_elapsed > 15) {
//_digital[IN_SENSOR_LOW].mode = 0;
}
}
void Process()
{
// *****
unsigned long t = millis();
t_elapsed = (t - t_start) / 1000.0;
dt = (t - t_backup) / 1000.0;
// ***** FLOW OUT
if (_digital[IN_TANK_LEVEL].dvalue > 1.0)
{
_digital[IN_FLOW_OUT].dvalue = SimulConsoSinusoidale(t);
//_digital[IN_FLOW_OUT].dvalue = SimulConsoBrown(_digital[IN_FLOW_OUT].dvalue);
}
else
{
if (_digital[IN_FLOW_CAP].dvalue == 0.0) {
_digital[IN_FLOW_CAP].dvalue = _digital[IN_FLOW_OUT].dvalue;
}
_digital[IN_FLOW_OUT].dvalue = _digital[IN_FLOW_CAP].dvalue * _digital[IN_TANK_LEVEL].dvalue;
}
// ***** FLOW IN
_digital[IN_FLOW_IN].dvalue = 0;
for (int i = OUT_PUMP_1; i <= OUT_PUMP_4; i++)
{
_digital[i - 4].dvalue = ProcessMoteur(i);
_digital[IN_FLOW_IN].dvalue += _digital[i - 4].dvalue;
}
_digital[IN_FLOW_DIF].dvalue = _digital[IN_FLOW_IN].dvalue - _digital[IN_FLOW_OUT].dvalue;
// ***** TANK LEVEL
_digital[IN_TANK_LEVEL].dvalue += (_digital[IN_FLOW_IN].dvalue - _digital[IN_FLOW_OUT].dvalue) / 1000.0 * dt;
if (_digital[IN_TANK_LEVEL].dvalue > 10.0) {
_digital[IN_TANK_LEVEL].dvalue = 10.0;
}
if (_digital[IN_TANK_LEVEL].dvalue > _digital[IN_TANK_MAX].dvalue) {
_digital[IN_TANK_MAX].dvalue = _digital[IN_TANK_LEVEL].dvalue;
}
if (_digital[IN_TANK_LEVEL].dvalue < _digital[IN_TANK_MIN].dvalue) {
_digital[IN_TANK_MIN].dvalue = _digital[IN_TANK_LEVEL].dvalue;
}
// **** KEYBOARD
if (_digital[IN_KEYBOARD_X].raising)
{
_digital[IN_SENSOR_LOW].mode = _digital[IN_SENSOR_LOW].mode ^ 0x01;
}
for (int i = IN_KEYBOARD_7; i <= IN_KEYBOARD_0; i++)
{
if (_digital[i].raising)
{
unsigned char p = i + (OUT_PUMP_1 - IN_KEYBOARD_7);
_digital[p].mode ^= 0x01;
if (!(_digital[p].mode & 0x01)) {
digitalWrite(p, 0);
}
}
}
// **** SENSOR
int test;
test = (_digital[IN_TANK_LEVEL].dvalue > _digital[OUT_LEVEL_MIN].dvalue);
if (_digital[IN_SENSOR_MIN].ivalue != test)
{
if (test == 0)
{
_digital[IN_SENSOR_MIN].nb += 1;
}
_digital[IN_SENSOR_MIN].ivalue = test;
}
test = _digital[IN_TANK_LEVEL].dvalue > _digital[OUT_LEVEL_LOW].dvalue && _digital[IN_SENSOR_LOW].mode & 0x01;
if (_digital[IN_SENSOR_LOW].ivalue != test)
{
if (test == 0)
{
_digital[IN_SENSOR_LOW].nb += 1;
}
_digital[IN_SENSOR_LOW].ivalue = test;
}
test = _digital[IN_TANK_LEVEL].dvalue > _digital[OUT_LEVEL_MAX].dvalue;
if (_digital[IN_SENSOR_MAX].ivalue != test)
{
if (test == 1)
{
_digital[IN_SENSOR_MAX].nb += 1;
}
_digital[IN_SENSOR_MAX].ivalue = test;
}
test = _digital[IN_TANK_LEVEL].dvalue > _digital[OUT_LEVEL_HIGH].dvalue;
if (_digital[IN_SENSOR_HIGH].ivalue != test)
{
if (test == 1)
{
_digital[IN_SENSOR_HIGH].nb += 1;
}
_digital[IN_SENSOR_HIGH].ivalue = test;
}
Affichage();
t_backup = t;
}
double SimulConsoSinusoidale(long t)
{
double alea = ((long)(t / 100.0) % 600) * 3 / 1800.0 * PI;
//mvprintw(18, 0, "%ld %f", (long)(t / 100.0), alea);
return 100 + cos(alea) * cos(alea) * _digital[OUT_FLOW_OUT_AMPLITUDE].dvalue;
}
// dt : Intervalle de temps
double SimulConsoBrown(double valeur_precedente)
{
float mu = 0.01 * -((((int)t_elapsed / 30) % 2) * 2 - 1); // Taux de croissance (1%)
float sigma = 0.05; // Volatilité (5%)
mvprintw(8, 40, "(µ %.1f %% ; σ %.1f %%) ", mu * 100, sigma * 100);
// Nombre aléatoire compris dans [-1 +1]
float rand_std_normal = ((double)rand() / RAND_MAX) * 2.0 - 1.0;
// Calcule la variation logarithmique pour cette étape
float drift = (mu - 0.5f * sigma * sigma) * dt;
float diffusion = sigma * sqrt(dt) * rand_std_normal;
return valeur_precedente * exp(drift + diffusion);
}
/**
* Affichage dans la console
*/
/**
* Initialisation, affichage des parties statiques
*/
void AffichageWindow()
{
window = subwin(stdscr, 19, 62, 0, 0);
box(window, 0, 0);
// Titre
mvwprintw(window, 1, 2, "Château d'eau (11/2024)");
// I/O
// Ligne du haut
mvwaddch(window, 2, 0, ACS_LTEE);
mvwhline(window, 2, 1, 0, 60);
mvwaddch(window, 2, 61, ACS_RTEE);
// Ligne du bas
mvwaddch(window, 7, 0, ACS_LTEE);
mvwhline(window, 7, 1, 0, 60);
mvwaddch(window, 7, 61, ACS_RTEE);
// Séparation verticale
mvwaddch(window, 2, 18, ACS_TTEE);
mvwvline(window, 3, 18, 0, 4);
mvwaddch(window, 7, 18, ACS_BTEE);
// Input : Boutons poussoirs
mvwprintw(window, 3, 2, "BP 1");
mvwprintw(window, 4, 2, "BP 2");
mvwprintw(window, 5, 2, "BP 3");
mvwprintw(window, 6, 2, "BP 4");
// Output : Moteurs pompes
mvwprintw(window, 3, 20, "Pompe 1");
mvwprintw(window, 4, 20, "Pompe 2");
mvwprintw(window, 5, 20, "Pompe 3");
mvwprintw(window, 6, 20, "Pompe 4");
// Mesures
mvwprintw(window, 8, 2, "Debit en sortie");
mvwprintw(window, 9, 2, "Debit en entrée");
mvwprintw(window, 10, 2, "Volume dans le réservoir");
// Graphe
// Ligne du haut
mvwaddch(window, 11, 0, ACS_LTEE);
mvwhline(window, 11, 1, 0, 60);
mvwaddch(window, 11, 61, ACS_RTEE);
// Ligne du bas
mvwaddch(window, 13, 0, ACS_LTEE);
mvwhline(window, 13, 1, 0, 60);
mvwaddch(window, 13, 61, ACS_RTEE);
// Graduations
for (int i = 1 ; i < 11; i++) {
mvwaddch(window, 11, 6 * i, ACS_TTEE);
mvwaddch(window, 13, 6 * i, ACS_BTEE);
}
mvwaddch(window, 13, 2 * 6, ACS_PLUS);
mvwaddch(window, 13, 6 * 6, ACS_PLUS);
mvwaddch(window, 13, 7 * 6, ACS_PLUS);
mvwaddch(window, 13, 57, ACS_TTEE); //9.5 x 6
mvwvline(window, 12, 6 * 10, 0, 1);
// Légende
mvwaddch(window, 16, 0, ACS_LTEE);
mvwhline(window, 16, 1, 0, 60);
mvwaddch(window, 16, 61, ACS_RTEE);
mvwprintw(window, 14, 2 * 6 - 1, "min");
mvwprintw(window, 14, 6 * 6 - 2, "low");
mvwprintw(window, 14, 7 * 6, "high");
mvwprintw(window, 14, 56, "max");
// Informations
mvwprintw(window, 17, 2, "Mode");
mvwaddch(window, 16, 18, ACS_TTEE);
mvwaddch(window, 18, 18, ACS_BTEE);
mvwvline(window, 17, 18, 0, 1);
mvwprintw(window, 17, 20, "Grafcet");
mvwaddch(window, 16, 31, ACS_TTEE);
mvwaddch(window, 18, 31, ACS_BTEE);
mvwvline(window, 17, 31, 0, 1);
mvwprintw(window, 17, 33, "min");
mvwprintw(window, 17, 46, "max");
wrefresh(window);
}
void Affichage()
{
mvwprintw(window, 1, 50, "%5.1f s", t_elapsed);
for (int i = OUT_PUMP_1; i <= OUT_PUMP_4; i++)
{
mvwprintw(window, (short)(i - OUT_PUMP_1 + 3), 30, " %c %5.1f s %dx", _digital[i].mode & 0x01 ? _digital[i].ivalue ? 'M' : '.' : 'X', _digital[i].duration, _digital[i].nb);
}
for (int i = IN_KEYBOARD_1; i <= IN_KEYBOARD_4; i++)
{
mvwprintw(window, (short)(i + 3), 10, _digital[_keyboard[i].input].ivalue ? "1" : "0");
}
mvwprintw(window, 8, 28, "%3d l/s", (int)_digital[IN_FLOW_OUT].dvalue);
mvwprintw(window, 9, 28, "%3d l/s", (int)_digital[IN_FLOW_IN].dvalue);
mvwprintw(window, 10, 29, "%5.2lf m3 (%+d l/s)", _digital[IN_TANK_LEVEL].dvalue, (int)_digital[IN_FLOW_DIF].dvalue);
AffichageGraphe(12, 1, _digital[IN_TANK_LEVEL].dvalue * 6);
/*
if (_digital[IN_SENSOR_LOW].mode & 0x01)
{
mvwprintw(window, 15, 1, " (%dx) (%dx) (%dx) (%dx)", _digital[IN_SENSOR_MIN].nb, _digital[IN_SENSOR_LOW].nb, _digital[IN_SENSOR_HIGH].nb, _digital[IN_SENSOR_MAX].nb);
}
else
{
mvwprintw(window, 15, 1, " (%dx) X (%dx) (%dx) (%dx)", _digital[IN_SENSOR_MIN].nb, _digital[IN_SENSOR_LOW].nb, _digital[IN_SENSOR_HIGH].nb, _digital[IN_SENSOR_MAX].nb);
}
*/
mvwprintw(window, 14, 15, "%d", _digital[IN_SENSOR_MIN].ivalue);
mvwprintw(window, 14, 38, "%d", _digital[IN_SENSOR_LOW].ivalue);
mvwprintw(window, 14, 47, "%d", _digital[IN_SENSOR_HIGH].ivalue);
mvwprintw(window, 14, 60, "%d", _digital[IN_SENSOR_MAX].ivalue);
mvwprintw(window, 15, 11, "(%dx) %s", _digital[IN_SENSOR_MIN].nb, _digital[IN_SENSOR_MIN].mode & 0x01 ? " " : "D");
mvwprintw(window, 15, 34, "(%dx) %s", _digital[IN_SENSOR_LOW].nb, _digital[IN_SENSOR_LOW].mode & 0x01 ? " " : "D");
mvwprintw(window, 15, 42, "(%dx) %s", _digital[IN_SENSOR_HIGH].nb, _digital[IN_SENSOR_HIGH].mode & 0x01 ? " " : "D");
mvwprintw(window, 15, 56, "(%dx)", _digital[IN_SENSOR_MAX].nb);
// Informations complémentaires
mvwprintw(window, 17, 2, _digital[OUT_DISPLAY_MODE].ivalue ? "Automatique" : "Manuel ");
mvwprintw(window, 17, 28, "%d", _digital[OUT_DISPLAY_GRAFCET].ivalue);
mvwprintw(window, 17, 38, "%4.2lf m3", _digital[IN_TANK_MIN].dvalue);
mvwprintw(window, 17, 51, "%4.2lf m3", _digital[IN_TANK_MAX].dvalue);
wrefresh(window);
}
void AffichageGraphe(int y, int x, double value)
{
int entier = (int)(value);
int i;
for (i = 0; i < entier; i++)
{
mvwaddwstr(window, y, x + i, L""); // U+2588
}
int frac = (int)((value - entier) * 4);
if (frac > 3) // 0.75 -> 0.99
{
mvwaddwstr(window, y, x + i, L""); // U+258A
entier += 1;
}
if (frac > 2) // 0.5 -> 0.99
{
mvwaddwstr(window, y, x + i, L""); // U+258C
entier += 1;
}
else if (frac > 1) // 0.25 -> 0.49
{
mvwaddwstr(window, y, x + i, L""); //U+258E
entier += 1;
}
for (int i = entier; i < 59; i++)
{
mvwprintw(window, y, x + i, " ");
}
}
/**
* Prometheus
*/
void InitPrometheus()
{
static Exposer exposer{"0.0.0.0:8099"};
// Le registre central
registry = std::make_shared<Registry>();
exposer.RegisterCollectable(registry);
auto& gauge_volume = BuildGauge()
.Name("geii_volume")
.Help("Volume en m3")
.Register(*registry);
tank_gauge = &gauge_volume.Add({});
auto& gauge_debit = BuildGauge()
.Name("geii_debit")
.Help("Débit en l/s")
.Register(*registry);
debit_entree = &gauge_debit.Add({{"numero", "entree"}});
debit_sortie = &gauge_debit.Add({{"numero", "sortie"}});
debit_p1 = &gauge_debit.Add({{"numero", "1"}});
debit_p2 = &gauge_debit.Add({{"numero", "2"}});
debit_p3 = &gauge_debit.Add({{"numero", "3"}});
debit_p4 = &gauge_debit.Add({{"numero", "4"}});
auto& counter_debit = BuildCounter()
.Name("geii_litre")
.Help("Volume en l")
.Register(*registry);
volume_p1 = &counter_debit.Add({{"numero", "1"}});
volume_p2 = &counter_debit.Add({{"numero", "2"}});
volume_p3 = &counter_debit.Add({{"numero", "3"}});
volume_p4 = &counter_debit.Add({{"numero", "4"}});
auto& hist_volume = BuildHistogram()
.Name("geii_tank")
.Help("volume du reservoir en m3")
.Register(*registry);
tank_histogram = &hist_volume.Add({}, buckets);
}
void ProcessMQTT(mqtt::async_client* client)
{
std::string payload = R"({
"order": "STATUS",
"speed": 120,
"temperature": 36.1
})";
auto msg = mqtt::make_message("geii/telemetry", payload);
msg->set_qos(1);
client->publish(msg);
}
void ProcessPrometheus()
{
tank_gauge->Set(_digital[IN_TANK_LEVEL].dvalue);
tank_histogram->Observe(_digital[IN_TANK_LEVEL].dvalue);
debit_entree->Set(_digital[IN_FLOW_IN].dvalue);
debit_sortie->Set(_digital[IN_FLOW_OUT].dvalue);
debit_p1->Set(_digital[IN_FLOW_1].dvalue);
debit_p2->Set(_digital[IN_FLOW_2].dvalue);
debit_p3->Set(_digital[IN_FLOW_3].dvalue);
debit_p4->Set(_digital[IN_FLOW_4].dvalue);
volume_p1->Increment(_digital[IN_FLOW_1].dvalue * dt);
volume_p2->Increment(_digital[IN_FLOW_2].dvalue * dt);
volume_p3->Increment(_digital[IN_FLOW_3].dvalue * dt);
volume_p4->Increment(_digital[IN_FLOW_4].dvalue * dt);
}