2026-01-09 07:46:52 +01:00
# include <stdio.h>
# include <time.h>
2026-01-09 11:24:51 +01:00
# include <unistd.h>
2026-01-09 07:46:52 +01:00
# undef timeout
# include "mqtt/async_client.h"
# include <nlohmann/json.hpp>
using json = nlohmann : : json ;
/* From Arduino.h */
# define HIGH 0x1
# define LOW 0x00
# define IO_INPUT 0x02
# define IO_OUTPUT 0x04
# define DIGITAL 0x08
# define ANALOG 0x10
# define PI 3.1415926535897932384626433832795
# define HALF_PI 1.5707963267948966192313216916398
# define true 1
# define false 0
// Temps
// Timestamp unix en millisecondes
// t_start : timestamp de départ
// t_backup : timestamp de la précédente itération
// t_elapsed : temps écoulé en secondes depuis le départ
// dt (delta t) : temps écoulé en secondes depuis la dernière itération
unsigned long t_start , t_backup ;
double t_elapsed , dt ;
unsigned long millis ( )
{
struct timespec now ;
clock_gettime ( CLOCK_REALTIME , & now ) ;
return ( ( unsigned long ) now . tv_sec ) * 1000 + ( ( unsigned long ) now . tv_nsec ) / 1000000 ;
}
# define OP_DIGITAL_READ 0
# define OP_DIGITAL_WRITE 1
# define OP_ANALOG_READ 2
# define OP_ANALOG_WRITE 3
# define OP_PIN_MODE 4
2026-01-09 11:24:51 +01:00
int marche = 0 ;
int arret = 1 ;
int b0 , b1 , b2 , b3 , b4 , b5 , b6 , b7 ;
int i0 , i1 , i2 , i3 , i4 , i5 , i6 , i7 ;
int s0 , s1 , s2 , s3 , s4 , s5 , s6 , s7 ;
2026-01-09 11:44:24 +01:00
int m0 , m1 , m2 , m3 ;
int v0 ;
2026-01-09 11:24:51 +01:00
/* ********************************************************
* MQTT *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2026-01-09 07:46:52 +01:00
2026-01-09 11:24:51 +01:00
/* Configuration MQTT */
const std : : string ADDRESS = " tcp://rabbitmq:1883 " ;
const std : : string CLIENTID = " CppClientTP " ;
const std : : string TOPIC = " geii/in/# " ;
const int QOS = 1 ;
const int CYCLE_MS = 100 ;
mqtt : : async_client client ( ADDRESS , CLIENTID ) ;
2026-01-09 07:46:52 +01:00
2026-01-09 11:24:51 +01:00
void mqtt_process ( mqtt : : async_client * client )
{
json obj = {
{ " s0 " , s0 } ,
{ " s1 " , s1 } ,
{ " s2 " , s2 } ,
{ " s3 " , s3 } ,
{ " s4 " , s4 } ,
{ " s5 " , s5 } ,
{ " s6 " , s6 } ,
{ " s7 " , s7 } ,
2026-01-09 11:44:24 +01:00
{ " m0 " , m0 } ,
{ " m1 " , m1 } ,
{ " m2 " , m2 } ,
{ " m3 " , m3 } ,
2026-01-09 11:24:51 +01:00
} ;
std : : string payload = obj . dump ( ) ;
auto msg = mqtt : : make_message ( " geii/out " , payload ) ;
msg - > set_qos ( 1 ) ;
client - > publish ( msg ) ;
usleep ( 100000 ) ;
2026-01-09 07:46:52 +01:00
}
2026-01-09 11:24:51 +01:00
2026-01-09 07:46:52 +01:00
// Réception des messages MQTT
// ************************************************************
2026-01-09 11:24:51 +01:00
class callback : public virtual mqtt : : callback {
2026-01-09 07:46:52 +01:00
public :
2026-01-09 11:24:51 +01:00
void message_arrived ( mqtt : : const_message_ptr msg ) override {
std : : string payload = msg - > to_string ( ) ;
try {
json j = json : : parse ( payload ) ;
marche = 0 ; arret = 1 ;
b0 = b1 = b2 = b3 = b4 = b5 = b6 = b7 = 0 ;
// Ne rien faire si l'objet JSON est vide
if ( j . empty ( ) ) return ;
if ( j . contains ( " marche " ) ) marche = j [ " marche " ] . get < int > ( ) ! = 0 ;
if ( j . contains ( " arret " ) ) arret = j [ " arret " ] . get < int > ( ) ! = 0 ;
if ( j . contains ( " b0 " ) ) b0 = j [ " b0 " ] . get < int > ( ) ! = 0 ;
if ( j . contains ( " b1 " ) ) b1 = j [ " b1 " ] . get < int > ( ) ! = 0 ;
if ( j . contains ( " b2 " ) ) b2 = j [ " b2 " ] . get < int > ( ) ! = 0 ;
if ( j . contains ( " b3 " ) ) b3 = j [ " b3 " ] . get < int > ( ) ! = 0 ;
if ( j . contains ( " b4 " ) ) b4 = j [ " b4 " ] . get < int > ( ) ! = 0 ;
if ( j . contains ( " b5 " ) ) b5 = j [ " b5 " ] . get < int > ( ) ! = 0 ;
if ( j . contains ( " b6 " ) ) b6 = j [ " b6 " ] . get < int > ( ) ! = 0 ;
if ( j . contains ( " b7 " ) ) b7 = j [ " b7 " ] . get < int > ( ) ! = 0 ;
if ( j . contains ( " i0 " ) ) i0 = j [ " i0 " ] . get < int > ( ) ! = 0 ;
if ( j . contains ( " i1 " ) ) i1 = j [ " i1 " ] . get < int > ( ) ! = 0 ;
if ( j . contains ( " i2 " ) ) i2 = j [ " i2 " ] . get < int > ( ) ! = 0 ;
if ( j . contains ( " i3 " ) ) i3 = j [ " i3 " ] . get < int > ( ) ! = 0 ;
if ( j . contains ( " i4 " ) ) i4 = j [ " i4 " ] . get < int > ( ) ! = 0 ;
if ( j . contains ( " i5 " ) ) i5 = j [ " i5 " ] . get < int > ( ) ! = 0 ;
if ( j . contains ( " i6 " ) ) i6 = j [ " i6 " ] . get < int > ( ) ! = 0 ;
if ( j . contains ( " i7 " ) ) i7 = j [ " i7 " ] . get < int > ( ) ! = 0 ;
2026-01-09 11:44:24 +01:00
if ( j . contains ( " v0 " ) & & j [ " v0 " ] . is_number ( ) ) v0 = j [ " v0 " ] . get < int > ( ) ;
std : : cout < < " Pompes : " < < marche < < " " < < arret < < " B " < < b0 < < " " < < b1 < < " " < < b2 < < " " < < b3 < < " " < < b4 < < " " < < b5 < < " " < < b6 < < " " < < b7 < < " I " < < i0 < < " " < < i1 < < " " < < i2 < < " " < < i3 < < " " < < i4 < < " " < < i5 < < " " < < i6 < < " " < < i7 < < " " < < v0 < < std : : endl ;
2026-01-09 11:24:51 +01:00
}
catch ( const json : : parse_error & e ) {
std : : cerr < < " Erreur JSON : " < < e . what ( ) < < " \n " ;
}
}
2026-01-09 07:46:52 +01:00
} ;
2026-01-09 11:24:51 +01:00
callback cb ;
void mqtt_open ( mqtt : : async_client * client ) {
client - > set_callback ( cb ) ;
mqtt : : connect_options connOpts ;
connOpts . set_clean_session ( true ) ;
connOpts . set_user_name ( " admin " ) ;
connOpts . set_password ( " geii2025 " ) ;
try {
client - > connect ( connOpts ) - > wait ( ) ;
client - > start_consuming ( ) ;
client - > subscribe ( TOPIC , QOS ) - > wait ( ) ;
} catch ( const mqtt : : exception & exc ) {
std : : cerr < < " Erreur MQTT: " < < exc . what ( ) < < " \n " ;
}
2026-01-09 07:46:52 +01:00
}
2026-01-09 11:24:51 +01:00
void mqtt_close ( ) {
try {
client . unsubscribe ( TOPIC ) - > wait ( ) ;
client . stop_consuming ( ) ;
client . disconnect ( ) - > wait ( ) ;
} catch ( const mqtt : : exception & exc ) {
std : : cerr < < " Erreur déconnexion MQTT: " < < exc . what ( ) < < std : : endl ;
}
2026-01-09 07:46:52 +01:00
}
2026-01-09 11:24:51 +01:00
// ************************************************************
2026-01-09 07:46:52 +01:00
/* ********************************************************
* TEMPORISATION RETARD A LA MONTEE *
* La sortie passe à 1 au bout de la tempo *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
class TemporisationRetardMontee
{
// methodes
public :
// Contructeur qui prend la duree souhaitee de la temporisation
TemporisationRetardMontee ( unsigned long duree )
{
this - > duree = duree ;
sortie = false ;
captureTemps = false ;
}
// Activation de la temporisation. Doit etre fait tout le temps de la duree de la tempo
void activation ( )
{
// Capture du temps de reference
if ( ! captureTemps )
{
debut = millis ( ) ;
captureTemps = true ;
}
// Calcul du temps ecoule depuis le temps de reference
tempsEcoule = millis ( ) - debut ;
// Mise a 1 de la fin de tempo
if ( tempsEcoule > = duree )
{
sortie = true ;
captureTemps = false ;
}
else
{
sortie = false ;
}
}
// Precharge de la temporisation
void setDuree ( unsigned long majduree )
{
duree = majduree ;
sortie = false ;
captureTemps = false ;
}
// Interrogation du bit de fin de tempo
bool getSortie ( )
{
return ( sortie ) ;
}
// Recuperation du temps ecoule depuis le debut si necessaire
unsigned long getTempsEcoule ( )
{
return ( tempsEcoule ) ;
}
// Attributs
private :
unsigned long duree ;
unsigned long debut ;
unsigned long tempsEcoule ;
bool captureTemps ;
bool sortie ;
} ;
/********************************************************
2026-01-09 11:24:51 +01:00
* TEMPORISATION RETARD A LA DESCENTE *
2026-01-09 07:46:52 +01:00
* La sortie passe à 0 au bout de la tempo *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
class TemporisationRetardDescente
{
public :
// Contructeur qui prend la duree souhaitee de la temporisation
TemporisationRetardDescente ( unsigned long duree )
{
this - > duree = duree ;
sortie = false ;
captureTemps = false ;
}
// Activation de la temporisation. Doit etre fait tout le temps de la duree de la tempo
void activation ( )
{
// Capture du temps de reference
if ( ! captureTemps )
{
debut = millis ( ) ;
captureTemps = true ;
sortie = true ;
}
// Calcul du temps ecoule depuis le temps de reference
tempsEcoule = millis ( ) - debut ;
// Mise a 0 de la fin de tempo
if ( tempsEcoule > = duree )
{
sortie = false ;
captureTemps = false ;
}
}
// Precharge de la temporisation
void setDuree ( unsigned long majduree )
{
duree = majduree ;
sortie = false ;
captureTemps = false ;
}
// Interrogration du bit de fin de tempo
bool getSortie ( )
{
return ( sortie ) ;
}
// Recuperation du temps ecoule depuis le debut si necessaire
unsigned long getTempsEcoule ( )
{
return ( tempsEcoule ) ;
}
private :
unsigned long duree ;
unsigned long debut ;
unsigned long tempsEcoule ;
bool captureTemps ;
bool sortie ;
} ;
/********************************************************
* * * * CLIGNOTEUR * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
class Clignoteur
{
// methodes
public :
// Construteur qui prend en parametre le temps haut ou bas souhaitee
Clignoteur ( int baseDeTemps )
{
this - > baseDeTemps = baseDeTemps ;
}
// Fonction qui renvoie true si le clignoteur est ├á l'├®tat haut et false s'il est ├á l'├®tat bas
bool statut ( )
{
return ( ( millis ( ) / baseDeTemps ) % 2 = = 1 ) ;
}
// Attributs
private :
int baseDeTemps ;
} ;
/********************************************************
* * * * COMPTEUR * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * ATTENTION : Il faut gerer le front montant dans le programme
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
class Compteur
{
// methodes
public :
// Constructeur qui prend en parametre la valeur de preselection
Compteur ( int valeurPreselection )
{
this - > valeurPreselection = valeurPreselection ;
valeur = 0 ;
}
// Incrementation du compteur
void incrementer ( )
{
valeur + + ;
}
// Decrementation du compteur
void decrementer ( )
{
valeur - - ;
}
// remise a zero du compteur
void remettreAZero ( )
{
valeur = 0 ;
}
// recuperation de la valeur courante
int getValeurCourante ( )
{
return ( valeur ) ;
}
// est-ce que la preselection est atteinte (sortie Q compteur Siemens ou Schnieder)
bool getSortie ( )
{
return ( valeur = = valeurPreselection ) ;
}
// Attributs
private :
int valeur ;
int valeurPreselection ;
} ;
/********************************************************
* * * * MISE A L ' ECHELLE DE VALEUR * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
class MiseAEchelle
{
public :
// Constructeur qui ne prend en parametre la plage d'entree et la plage de sortie
MiseAEchelle ( float minEntree , float maxEntree , float minSortie , float maxSortie )
{
this - > minEntree = minEntree ;
this - > maxEntree = maxEntree ;
this - > minSortie = minSortie ;
this - > maxSortie = maxSortie ;
}
// fonction de conversion qui prend la valeur a convertir et renvoie la valeur convertie
float convertir ( float valeurAConvertir )
{
if ( valeurAConvertir > = minEntree & & valeurAConvertir < = maxEntree )
{
float norm = ( 1 / ( maxEntree - minEntree ) ) * ( valeurAConvertir - minEntree ) ;
float scale = ( maxSortie - minSortie ) * norm + minSortie ;
return ( scale ) ;
}
return ( - 1000 ) ;
}
// Attributs
private :
float minEntree ;
float minSortie ;
float maxEntree ;
float maxSortie ;
} ;