diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index fbfcc72..5a21f97 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -12,17 +12,22 @@ RUN set -eux; \ apt-get update; \ apt-get install -y \ libncurses-dev \ - libmicrohttpd-dev;\ - apt-get clean + libmicrohttpd-dev \ + libcurl4-openssl-dev \ + zlib1g-dev \ + prometheus-cpp-dev RUN set -eux; \ - git clone https://github.com/jelmd/libprom.git; \ - cd libprom; \ - make build; \ - cd prom/build; \ - make install; \ - cd ../../promhttp/build; \ - make install; + apt-get update; \ + apt-get install -y \ + libpaho-mqtt-dev + + RUN set -eux; \ + apt-get update; \ + apt-get install -y \ + librabbitmq4 \ + librabbitmq-dev;\ + apt-get clean WORKDIR /root diff --git a/.gitignore b/.gitignore index 16be8f2..84c048a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -/output/ +/build/ diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..31a8b9e --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,26 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug geii_exporter", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build/geii_exporter", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Activer les pretty-printers pour gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + "preLaunchTask": "CMake: build" + } + ] +} + diff --git a/.vscode/tasks.json b/.vscode/tasks.json index a8ee3fe..ca1bc1f 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,33 +1,21 @@ { + "version": "2.0.0", "tasks": [ { - "type": "cppbuild", - "label": "C/C++: gcc build active file", - "command": "/usr/bin/gcc", - "args": [ - "-fdiagnostics-color=always", - "-g", - "${workspaceFolder}${pathSeparator}main.cpp", - "-lm", - "-lncursesw", - "-lprom", - "-lpromhttp", - "-lmicrohttpd", - "-o", - "${fileDirname}/${fileBasenameNoExtension}" - ], - "options": { - "cwd": "${fileDirname}" - }, - "problemMatcher": [ - "$gcc" - ], + "label": "CMake: build", + "type": "shell", + "command": "cmake --build build --config Debug", "group": { "kind": "build", "isDefault": true }, - "detail": "Task generated by Debugger." + "problemMatcher": ["$gcc"] + }, + { + "label": "CMake: configure", + "type": "shell", + "command": "cmake -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON", + "problemMatcher": ["$gcc"] } - ], - "version": "2.0.0" -} \ No newline at end of file + ] +} diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..1a2b47a --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,57 @@ +cmake_minimum_required(VERSION 3.15) +project(geii_exporter LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +# Activer warnings utiles +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic") + +# Executable principal +add_executable(geii_exporter + main.cpp +) + +# ------------------------------- +# Librairies systèmes +# ------------------------------- + +# CURL +find_package(CURL REQUIRED) + +# Microhttpd +find_library(MICROHTTPD_LIB microhttpd REQUIRED) + +# Threads et compression +find_package(Threads REQUIRED) +find_library(Z_LIB z REQUIRED) + +# ncursesw +find_library(NCURSESW_LIB ncursesw REQUIRED) + +# RabbitMQ C client +find_library(RABBITMQ_LIB rabbitmq REQUIRED) + +# Paho MQTT C client +find_library(PAHO_MQTT3C_LIB paho-mqtt3c REQUIRED) + +# ------------------------------- +# Prometheus C++ +# ------------------------------- +find_package(prometheus-cpp REQUIRED) + +# ------------------------------- +# Lien des bibliothèques +# ------------------------------- +target_link_libraries(geii_exporter + prometheus-cpp::core + prometheus-cpp::pull + ${CURL_LIBRARIES} + ${MICROHTTPD_LIB} + Threads::Threads + ${Z_LIB} + ${NCURSESW_LIB} + ${RABBITMQ_LIB} + ${PAHO_MQTT3C_LIB} +) diff --git a/main.cpp b/main.cpp index 79c175c..78c79fc 100644 --- a/main.cpp +++ b/main.cpp @@ -6,10 +6,10 @@ #include "main.h" #include "AutomForArduino.cpp" -extern "C" { - #include "libprom/prom.h" - #include "libprom/promhttp.h" -} +#include +#include +#include +#include // Constantes de fonctionnement #define LEVEL_MIN 2 @@ -34,14 +34,15 @@ TemporisationRetardMontee tempo4(2000); // Prometheus // ************************************************************ -struct MHD_Daemon *server; +using namespace prometheus; -prom_counter_t *pm_pompe; -prom_gauge_t *pm_debit; +std::shared_ptr registry; +Gauge* debit_entree = nullptr; +Gauge* debit_sortie = nullptr; // ************************************************************ int main(int argc, char *argv[]) -{ +{ /* Initialisation */ ConsoleInit(); AffichageWindow(); @@ -56,10 +57,10 @@ int main(int argc, char *argv[]) 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) { + if (ch == 27 || _digital[OUT_END].ivalue) { break; } - + // **** Beep if (_digital[OUT_BEEP].ivalue) { @@ -75,7 +76,7 @@ int main(int argc, char *argv[]) Actions(); ProcessPrometheus(); - + ProcessException(); usleep(100000); @@ -83,8 +84,7 @@ int main(int argc, char *argv[]) endwin(); // Termine ncurses et rétablit le terminal puts("Fin du programme"); - pcr_destroy(PROM_COLLECTOR_REGISTRY); - promhttp_stop_daemon(server); + return 0; } @@ -406,7 +406,7 @@ void ProcessInitValues() /** * Fonctionnement des moteurs */ -double ProcessMoteur(int i) +double ProcessMoteur(int i) { double vitesse = 1.0; double t = _digital[i].time / 5000.0; @@ -567,14 +567,14 @@ void Process() t_backup = t; } -double SimulConsoSinusoidale(long 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 +// dt : Intervalle de temps double SimulConsoBrown(double valeur_precedente) { float mu = 0.01 * -((((int)t_elapsed / 30) % 2) * 2 - 1); // Taux de croissance (1%) @@ -583,8 +583,8 @@ double SimulConsoBrown(double valeur_precedente) 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; - + 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; @@ -597,23 +597,23 @@ double SimulConsoBrown(double valeur_precedente) */ /** - * Initialisation, affichage des parties statiques + * 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); @@ -640,14 +640,14 @@ void AffichageWindow() 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); @@ -670,14 +670,14 @@ void AffichageWindow() 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"); + mvwprintw(window, 17, 2, "Mode"); mvwaddch(window, 16, 18, ACS_TTEE); mvwaddch(window, 18, 18, ACS_BTEE); @@ -750,50 +750,67 @@ void AffichageGraphe(int y, int x, double value) for (i = 0; i < entier; i++) { - mvwaddwstr(window, y, x + i, L"█"); // U+2588 + 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 + 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 + 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 + mvwaddwstr(window, y, x + i, L"▎"); //U+258E entier += 1; } for (int i = entier; i < 59; i++) { mvwprintw(window, y, x + i, " "); - } + } } /** - * Prometheus + * Prometheus */ -void InitPrometheus() +void InitPrometheus() { + static Exposer exposer{"0.0.0.0:8099"}; + + // Le registre central + registry = std::make_shared(); + + exposer.RegisterCollectable(registry); + + // Exemple : gauge (comme votre debit) + auto& gauge_family = BuildGauge() + .Name("geii_debit") + .Help("Débit en l/s") + .Register(*registry); + + debit_entree = &gauge_family.Add({{"numero", "entree"}}); + debit_sortie = &gauge_family.Add({{"numero", "sortie"}}); + + /* int result = pcr_init(0,"geii_"); std::array labels = { "numero" }; pm_pompe = prom_counter_new("pompe_on", "Mise en marche de la pompe" , labels.size(), labels.data()); pcr_register_metric(pm_pompe); - + pm_debit = prom_gauge_new("debit", "Débit en l/s" , labels.size(), labels.data()); pcr_register_metric(pm_debit); promhttp_set_active_collector_registry(NULL); - + // Serveur web server = promhttp_start_daemon(MHD_USE_SELECT_INTERNALLY , 8099, NULL, NULL); @@ -802,18 +819,18 @@ void InitPrometheus() printf("Impossible de démarrer le serveur HTTP\n"); exit(1); } + */ } void ProcessPrometheus() { // raising = 1 => front montant sur la sortie + /* if (_digital[OUT_PUMP_1].raising) { std::array labels1 = { "1" }; prom_counter_inc(pm_pompe, labels1.data()); } - - std::array labels1 = { "sortie" }; - std::array labels2 = { "entree" }; - prom_gauge_set(pm_debit, _digital[IN_FLOW_OUT].dvalue, labels1.data()); - prom_gauge_set(pm_debit, _digital[IN_FLOW_IN].dvalue, labels2.data()); + */ + debit_entree->Set(_digital[IN_FLOW_OUT].dvalue); + debit_sortie->Set(_digital[IN_FLOW_IN].dvalue); }