#include #include #include #include #include #include "main.hpp" #include "AutomForArduino.cpp" #include #include #include #include #include // 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; 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(); ProcessException(); usleep(100000); } endwin(); // Termine ncurses et rétablit le terminal puts("Fin du programme"); 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(); 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 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); }