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;
|
2026-01-12 18:43:34 +01:00
|
|
|
int light = 0;
|
2026-01-09 11:24:51 +01:00
|
|
|
int b0, b1, b2, b3, b4, b5, b6, b7;
|
|
|
|
|
int i0, i1, i2, i3, i4, i5, i6, i7;
|
2026-01-12 23:32:48 +01:00
|
|
|
int s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11;
|
2026-01-09 11:44:24 +01:00
|
|
|
int m0, m1, m2, m3;
|
|
|
|
|
int v0;
|
2026-01-09 11:24:51 +01:00
|
|
|
|
2026-01-10 07:29:55 +01:00
|
|
|
int a0, a1, a2, a3, a4, a5, a6, a7;
|
|
|
|
|
int c0, c1, c2, c3, c4, c5, c6, c7;
|
|
|
|
|
|
2026-01-09 19:45:24 +01:00
|
|
|
void process();
|
|
|
|
|
|
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 19:45:24 +01:00
|
|
|
void mqtt_send(mqtt::async_client *client);
|
2026-01-09 11:24:51 +01:00
|
|
|
|
2026-01-09 07:46:52 +01:00
|
|
|
// Réception des messages MQTT
|
|
|
|
|
// ************************************************************
|
2026-01-09 19:45:24 +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;
|
|
|
|
|
|
2026-01-09 19:45:24 +01:00
|
|
|
if (j.contains("b0") && j["b0"].is_number())
|
|
|
|
|
b0 = j["b0"].get<int>();
|
|
|
|
|
if (j.contains("b1") && j["b1"].is_number())
|
|
|
|
|
b1 = j["b1"].get<int>();
|
|
|
|
|
if (j.contains("b2") && j["b2"].is_number())
|
|
|
|
|
b2 = j["b2"].get<int>();
|
|
|
|
|
if (j.contains("b3") && j["b3"].is_number())
|
|
|
|
|
b3 = j["b3"].get<int>();
|
|
|
|
|
if (j.contains("b4") && j["b4"].is_number())
|
|
|
|
|
b4 = j["b4"].get<int>();
|
|
|
|
|
if (j.contains("b5") && j["b5"].is_number())
|
|
|
|
|
b5 = j["b5"].get<int>();
|
|
|
|
|
if (j.contains("b6") && j["b6"].is_number())
|
|
|
|
|
b6 = j["b6"].get<int>();
|
|
|
|
|
if (j.contains("b7") && j["b7"].is_number())
|
|
|
|
|
b7 = j["b7"].get<int>();
|
|
|
|
|
|
|
|
|
|
if (j.contains("i0")) i0 = j["i0"].get<int>();
|
|
|
|
|
if (j.contains("i1")) i1 = j["i1"].get<int>();
|
|
|
|
|
if (j.contains("i2")) i2 = j["i2"].get<int>();
|
|
|
|
|
if (j.contains("i3")) i3 = j["i3"].get<int>();
|
|
|
|
|
if (j.contains("i4")) i4 = j["i4"].get<int>();
|
|
|
|
|
if (j.contains("i5")) i5 = j["i5"].get<int>();
|
|
|
|
|
if (j.contains("i6")) i6 = j["i6"].get<int>();
|
|
|
|
|
if (j.contains("i7")) i7 = j["i7"].get<int>();
|
2026-01-09 11:24:51 +01:00
|
|
|
|
2026-01-12 18:43:34 +01:00
|
|
|
if (j.contains("c0") && j["c0"].is_number())
|
2026-01-10 07:29:55 +01:00
|
|
|
c0 = j["c0"].get<int>();
|
2026-01-12 18:43:34 +01:00
|
|
|
if (j.contains("c1") && j["c1"].is_number())
|
2026-01-10 07:29:55 +01:00
|
|
|
c1 = j["c1"].get<int>();
|
2026-01-12 18:43:34 +01:00
|
|
|
if (j.contains("c2") && j["c2"].is_number())
|
2026-01-10 07:29:55 +01:00
|
|
|
c2 = j["c2"].get<int>();
|
2026-01-12 18:43:34 +01:00
|
|
|
if (j.contains("c3") && j["c3"].is_number())
|
2026-01-10 07:29:55 +01:00
|
|
|
c3 = j["c3"].get<int>();
|
2026-01-12 18:43:34 +01:00
|
|
|
if (j.contains("c4") && j["c4"].is_number())
|
2026-01-10 07:29:55 +01:00
|
|
|
c4 = j["c4"].get<int>();
|
2026-01-12 18:43:34 +01:00
|
|
|
if (j.contains("c5") && j["c5"].is_number())
|
2026-01-10 07:29:55 +01:00
|
|
|
c5 = j["c5"].get<int>();
|
2026-01-12 18:43:34 +01:00
|
|
|
if (j.contains("c6") && j["c6"].is_number())
|
2026-01-10 07:29:55 +01:00
|
|
|
c6 = j["c6"].get<int>();
|
2026-01-12 18:43:34 +01:00
|
|
|
if (j.contains("c7") && j["c7"].is_number())
|
2026-01-10 07:29:55 +01:00
|
|
|
c7 = j["c7"].get<int>();
|
|
|
|
|
|
2026-01-14 07:37:16 +01:00
|
|
|
if (j.contains("v0") && j["v0"].is_number())
|
|
|
|
|
v0 = j["v0"].get<int>();
|
|
|
|
|
|
|
|
|
|
if (j.contains("p0") && j["p0"].is_number())
|
|
|
|
|
v0 = j["p0"].get<int>();
|
2026-01-09 11:44:24 +01:00
|
|
|
|
2026-01-09 19:45:24 +01:00
|
|
|
process();
|
|
|
|
|
mqtt_send(&client);
|
|
|
|
|
}
|
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 19:45:24 +01:00
|
|
|
void mqtt_send(mqtt::async_client *client)
|
|
|
|
|
{
|
|
|
|
|
json obj = {
|
|
|
|
|
{"s0", s0},
|
|
|
|
|
{"s1", s1},
|
|
|
|
|
{"s2", s2},
|
|
|
|
|
{"s3", s3},
|
|
|
|
|
{"s4", s4},
|
|
|
|
|
{"s5", s5},
|
|
|
|
|
{"s6", s6},
|
|
|
|
|
{"s7", s7},
|
|
|
|
|
{"m0", m0},
|
|
|
|
|
{"m1", m1},
|
|
|
|
|
{"m2", m2},
|
|
|
|
|
{"m3", m3},
|
2026-01-10 07:29:55 +01:00
|
|
|
{"a0", a0},
|
|
|
|
|
{"a1", a1},
|
|
|
|
|
{"a2", a2},
|
|
|
|
|
{"a3", a3},
|
|
|
|
|
{"a4", a4},
|
|
|
|
|
{"a5", a5},
|
|
|
|
|
{"a6", a6},
|
|
|
|
|
{"a7", a7},
|
2026-01-12 23:32:48 +01:00
|
|
|
{"s8", s8},
|
|
|
|
|
{"s9", s9},
|
|
|
|
|
{"s10", s10},
|
|
|
|
|
{"s11", s11},
|
2026-01-09 19:45:24 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
std::string payload = obj.dump();
|
|
|
|
|
auto msg = mqtt::make_message("geii/out", payload);
|
|
|
|
|
msg->set_qos(1);
|
|
|
|
|
client->publish(msg);
|
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
};
|