Endpoints capteurs : conversion d'unité, latitude/longitude, listes de valeurs/textes, obsolescence NMEA
This commit is contained in:
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
// Types de familles (cf TB_Familles.Type_source / TB_Events.Type_source) :
|
// Types de familles (cf TB_Familles.Type_source / TB_Events.Type_source) :
|
||||||
static const int TYPE_SOURCE_CIRCUIT = 1;
|
static const int TYPE_SOURCE_CIRCUIT = 1;
|
||||||
|
static const int TYPE_SOURCE_CAPTEUR = 2;
|
||||||
static const int TYPE_SOURCE_BATTERIE = 4;
|
static const int TYPE_SOURCE_BATTERIE = 4;
|
||||||
|
|
||||||
// États circuit (cf commentaire colonne TB_Circuits.Etat dans le schéma) :
|
// États circuit (cf commentaire colonne TB_Circuits.Etat dans le schéma) :
|
||||||
@@ -36,6 +37,80 @@ static const int ETAT_CIRCUIT_ABSENCE_TERRE = 8;
|
|||||||
static const int ETAT_CIRCUIT_ABSENCE_MASSE = 9;
|
static const int ETAT_CIRCUIT_ABSENCE_MASSE = 9;
|
||||||
static const int ETAT_COMMANDE_CARTE_OK = 0;
|
static const int ETAT_COMMANDE_CARTE_OK = 0;
|
||||||
|
|
||||||
|
// Types d'entrées capteur (cf commentaire colonne TB_Capteurs.Type_entrees) :
|
||||||
|
static const int TYPE_ENTREES_AUX = 1;
|
||||||
|
static const int TYPE_ENTREES_NMEA = 7;
|
||||||
|
static const int TYPE_ENTREES_CALCULEE_BOOLEEN = 20;
|
||||||
|
|
||||||
|
// Types de conversion d'unité (cf commentaire colonne TB_Variables.Conversion_unite,
|
||||||
|
// confirmé identique à shipheart_type_unite_* dans main.qml) :
|
||||||
|
static const int TYPE_UNITE_VOLUME = 1;
|
||||||
|
static const int TYPE_UNITE_TEMPERATURE = 2;
|
||||||
|
static const int TYPE_UNITE_LATITUDE = 3;
|
||||||
|
static const int TYPE_UNITE_LONGITUDE = 4;
|
||||||
|
|
||||||
|
// Unités cibles (cf main.qml, shipheart_unite_volume_*/shipheart_unite_temperature_*) :
|
||||||
|
static const int UNITE_VOLUME_LITRES = 0;
|
||||||
|
static const int UNITE_VOLUME_US_GALLONS = 1;
|
||||||
|
static const int UNITE_VOLUME_IMP_GALLONS = 2;
|
||||||
|
static const int UNITE_TEMPERATURE_CELSIUS = 0;
|
||||||
|
static const int UNITE_TEMPERATURE_FAHRENHEIT = 1;
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Conversions - traduction fidèle de fonctions.js (conversion_volume(),
|
||||||
|
// conversion_temperature(), chaine_latitude(), chaine_longitude()) et de
|
||||||
|
// fonctions_localisation.js (symbole_unite_volume(), symbole_unite_temperature()).
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
static double conversion_volume(double val, int unite)
|
||||||
|
{
|
||||||
|
switch (unite) {
|
||||||
|
case UNITE_VOLUME_US_GALLONS: return val / 3.785411784;
|
||||||
|
case UNITE_VOLUME_IMP_GALLONS: return val / 4.546090;
|
||||||
|
case UNITE_VOLUME_LITRES:
|
||||||
|
default: return val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static double conversion_temperature(double val, int unite)
|
||||||
|
{
|
||||||
|
switch (unite) {
|
||||||
|
case UNITE_TEMPERATURE_FAHRENHEIT: return (val * 1.8) + 32.0;
|
||||||
|
case UNITE_TEMPERATURE_CELSIUS:
|
||||||
|
default: return val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString symbole_unite_volume(int unite)
|
||||||
|
{
|
||||||
|
switch (unite) {
|
||||||
|
case UNITE_VOLUME_US_GALLONS: return QStringLiteral("US Ga");
|
||||||
|
case UNITE_VOLUME_IMP_GALLONS: return QStringLiteral("Imp. Ga");
|
||||||
|
case UNITE_VOLUME_LITRES:
|
||||||
|
default: return QStringLiteral("lit.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString symbole_unite_temperature(int unite)
|
||||||
|
{
|
||||||
|
return (unite == UNITE_TEMPERATURE_FAHRENHEIT) ? QStringLiteral("°F") : QStringLiteral("°C");
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString chaine_latitude(double lat)
|
||||||
|
{
|
||||||
|
const int deg = static_cast<int>(lat);
|
||||||
|
const double minutes = (lat - deg) * 60.0;
|
||||||
|
const QString suffixe = (lat >= 0) ? QStringLiteral("N") : QStringLiteral("S");
|
||||||
|
return QString("%1°%2' %3").arg(deg).arg(minutes, 0, 'f', 3).arg(suffixe);
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString chaine_longitude(double lon)
|
||||||
|
{
|
||||||
|
const int deg = static_cast<int>(lon);
|
||||||
|
const double minutes = (lon - deg) * 60.0;
|
||||||
|
const QString suffixe = (lon >= 0) ? QStringLiteral("E") : QStringLiteral("W");
|
||||||
|
return QString("%1°%2' %3").arg(deg).arg(minutes, 0, 'f', 3).arg(suffixe);
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Ajoute l'en-tête CORS à une réponse - indispensable puisque le client WASM
|
// Ajoute l'en-tête CORS à une réponse - indispensable puisque le client WASM
|
||||||
// (servi par nginx sur un port distinct) et cette API (port 8080) constituent
|
// (servi par nginx sur un port distinct) et cette API (port 8080) constituent
|
||||||
@@ -96,10 +171,11 @@ int main(int argc, char *argv[])
|
|||||||
int typeSource;
|
int typeSource;
|
||||||
if (type == "circuit") typeSource = TYPE_SOURCE_CIRCUIT;
|
if (type == "circuit") typeSource = TYPE_SOURCE_CIRCUIT;
|
||||||
else if (type == "batterie") typeSource = TYPE_SOURCE_BATTERIE;
|
else if (type == "batterie") typeSource = TYPE_SOURCE_BATTERIE;
|
||||||
|
else if (type == "capteur") typeSource = TYPE_SOURCE_CAPTEUR;
|
||||||
else {
|
else {
|
||||||
QJsonObject err;
|
QJsonObject err;
|
||||||
err["status"] = "erreur";
|
err["status"] = "erreur";
|
||||||
err["message"] = "type non supporté (circuit, batterie)";
|
err["message"] = "type non supporté (circuit, batterie, capteur)";
|
||||||
return withCors(QHttpServerResponse(QJsonDocument(err).toJson(), QHttpServerResponder::StatusCode::NotImplemented));
|
return withCors(QHttpServerResponse(QJsonDocument(err).toJson(), QHttpServerResponder::StatusCode::NotImplemented));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,6 +241,41 @@ int main(int argc, char *argv[])
|
|||||||
while (q3.next()) {
|
while (q3.next()) {
|
||||||
if (q3.value(0).toInt() != 0) etat = 2;
|
if (q3.value(0).toInt() != 0) etat = 2;
|
||||||
}
|
}
|
||||||
|
} else if (type == "capteur") {
|
||||||
|
// Période d'obsolescence NMEA (TB_Configuration) :
|
||||||
|
int periodeObsolescenceNmea = 0;
|
||||||
|
{
|
||||||
|
QSqlQuery qc("SELECT Valeur FROM TB_Configuration WHERE Nom='Periode_obsolescence_capteur_nmea'");
|
||||||
|
if (qc.next()) periodeObsolescenceNmea = qc.value(0).toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alarmes (Events) liées à cette famille :
|
||||||
|
QSqlQuery q2;
|
||||||
|
q2.prepare("SELECT COUNT(*) FROM TB_Events WHERE Type_source=:type AND Validite=1 AND Alarme_source>0 "
|
||||||
|
"AND Etat_test=1 AND ID_Source IN (SELECT Cle_primaire FROM TB_Capteurs WHERE ID_Famille=:famille)");
|
||||||
|
q2.bindValue(":type", typeSource);
|
||||||
|
q2.bindValue(":famille", idFamille);
|
||||||
|
q2.exec();
|
||||||
|
if (q2.next() && q2.value(0).toInt() > 0) etat = 1;
|
||||||
|
|
||||||
|
QSqlQuery q3;
|
||||||
|
q3.prepare(
|
||||||
|
"SELECT Etat, Etat_systeme, "
|
||||||
|
"IF(Type_entrees=:typeNmea, (SELECT (UNIX_TIMESTAMP() - UNIX_TIMESTAMP(Date_maj)) FROM TB_Nmea2000 "
|
||||||
|
"WHERE Pgn=SUBSTRING_INDEX(Entrees, ':', 1) AND Field=SUBSTRING_INDEX(Entrees, ':', -1)), 0) AS Age "
|
||||||
|
"FROM TB_Capteurs WHERE ID_Famille=:famille AND Priorite_affichage_accueil>0"
|
||||||
|
);
|
||||||
|
q3.bindValue(":typeNmea", TYPE_ENTREES_NMEA);
|
||||||
|
q3.bindValue(":famille", idFamille);
|
||||||
|
q3.exec();
|
||||||
|
while (q3.next()) {
|
||||||
|
const int etatCapteur = q3.value(0).toInt();
|
||||||
|
const int etatSysteme = q3.value(1).toInt();
|
||||||
|
const int age = q3.value(2).toInt();
|
||||||
|
|
||||||
|
if (age > periodeObsolescenceNmea && etat < 1) etat = 1;
|
||||||
|
if ((etatCapteur > 0 || etatSysteme != 0) && etat < 2) etat = 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject obj;
|
QJsonObject obj;
|
||||||
@@ -192,10 +303,10 @@ int main(int argc, char *argv[])
|
|||||||
const QString type = query.queryItemValue("type");
|
const QString type = query.queryItemValue("type");
|
||||||
const QString familleStr = query.queryItemValue("famille");
|
const QString familleStr = query.queryItemValue("famille");
|
||||||
|
|
||||||
if (type != "circuit" && type != "batterie") {
|
if (type != "circuit" && type != "batterie" && type != "capteur") {
|
||||||
QJsonObject err;
|
QJsonObject err;
|
||||||
err["status"] = "erreur";
|
err["status"] = "erreur";
|
||||||
err["message"] = "type non supporté (circuit, batterie)";
|
err["message"] = "type non supporté (circuit, batterie, capteur)";
|
||||||
return withCors(QHttpServerResponse(QJsonDocument(err).toJson(), QHttpServerResponder::StatusCode::NotImplemented));
|
return withCors(QHttpServerResponse(QJsonDocument(err).toJson(), QHttpServerResponder::StatusCode::NotImplemented));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,6 +388,116 @@ int main(int argc, char *argv[])
|
|||||||
obj["etat"] = q.value(7).toInt();
|
obj["etat"] = q.value(7).toInt();
|
||||||
elements.append(obj);
|
elements.append(obj);
|
||||||
}
|
}
|
||||||
|
} else if (type == "capteur") {
|
||||||
|
// Préférences d'unité du bateau (TB_Configuration) :
|
||||||
|
int uniteVolume = 0, uniteTemperature = 0, periodeObsolescenceNmea = 0;
|
||||||
|
{
|
||||||
|
QSqlQuery qc("SELECT Valeur FROM TB_Configuration WHERE Nom='Unite_volume'");
|
||||||
|
if (qc.next()) uniteVolume = qc.value(0).toInt();
|
||||||
|
}
|
||||||
|
{
|
||||||
|
QSqlQuery qc("SELECT Valeur FROM TB_Configuration WHERE Nom='Unite_temperature'");
|
||||||
|
if (qc.next()) uniteTemperature = qc.value(0).toInt();
|
||||||
|
}
|
||||||
|
{
|
||||||
|
QSqlQuery qc("SELECT Valeur FROM TB_Configuration WHERE Nom='Periode_obsolescence_capteur_nmea'");
|
||||||
|
if (qc.next()) periodeObsolescenceNmea = qc.value(0).toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
QSqlQuery q;
|
||||||
|
q.prepare(
|
||||||
|
"SELECT Cle_primaire, Etat_systeme, Nom, Type_entrees, Entrees, ID_Variable, Etat, "
|
||||||
|
"(SELECT COUNT(*) FROM TB_Events WHERE Validite=1 AND Type_source=:typeSource AND Alarme_source>0 AND Etat_test=1 "
|
||||||
|
"AND ID_Source=TB_Capteurs.Cle_primaire) AS Nb_alarmes, "
|
||||||
|
"Valeur, Precision_affichage_accueil, Liste_valeurs_textes, "
|
||||||
|
"IF(Type_entrees=:typeNmea, (SELECT (UNIX_TIMESTAMP() - UNIX_TIMESTAMP(Date_maj)) FROM TB_Nmea2000 "
|
||||||
|
"WHERE Pgn=SUBSTRING_INDEX(Entrees, ':', 1) AND Field=SUBSTRING_INDEX(Entrees, ':', -1)), 0) AS Age "
|
||||||
|
"FROM TB_Capteurs WHERE ID_Famille=:famille AND Priorite_affichage_accueil>0 "
|
||||||
|
"ORDER BY Priorite_affichage_accueil, Nom"
|
||||||
|
);
|
||||||
|
q.bindValue(":typeSource", TYPE_SOURCE_CAPTEUR);
|
||||||
|
q.bindValue(":typeNmea", TYPE_ENTREES_NMEA);
|
||||||
|
q.bindValue(":famille", idFamille);
|
||||||
|
q.exec();
|
||||||
|
|
||||||
|
while (q.next()) {
|
||||||
|
const int id = q.value(0).toInt();
|
||||||
|
const int etatSysteme = q.value(1).toInt();
|
||||||
|
const QString nom = q.value(2).toString();
|
||||||
|
const int typeEntrees = q.value(3).toInt();
|
||||||
|
const int idVariable = q.value(5).toInt();
|
||||||
|
const int etatCapteur = q.value(6).toInt();
|
||||||
|
const int nbAlarmes = q.value(7).toInt();
|
||||||
|
const double valeurBrute = q.value(8).toDouble();
|
||||||
|
const int precision = q.value(9).toInt();
|
||||||
|
const QString listeValeursTextes = q.value(10).toString();
|
||||||
|
const int age = q.value(11).toInt();
|
||||||
|
|
||||||
|
// Résolution de l'unité/conversion via TB_Variables :
|
||||||
|
QSqlQuery qv;
|
||||||
|
qv.prepare("SELECT Unite, Conversion_unite FROM TB_Variables WHERE Cle_primaire=:id");
|
||||||
|
qv.bindValue(":id", idVariable);
|
||||||
|
qv.exec();
|
||||||
|
QString uniteBrute;
|
||||||
|
int typeUnite = 0;
|
||||||
|
if (qv.next()) {
|
||||||
|
uniteBrute = qv.value(0).toString();
|
||||||
|
typeUnite = qv.value(1).toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject obj;
|
||||||
|
obj["id"] = id;
|
||||||
|
obj["etat_systeme"] = etatSysteme;
|
||||||
|
obj["nom"] = nom;
|
||||||
|
obj["etat"] = etatCapteur;
|
||||||
|
obj["etat_events"] = nbAlarmes;
|
||||||
|
|
||||||
|
if (typeUnite == TYPE_UNITE_LATITUDE) {
|
||||||
|
obj["valeur"] = chaine_latitude(valeurBrute);
|
||||||
|
obj["valeur_texte"] = true;
|
||||||
|
obj["unite"] = QString();
|
||||||
|
} else if (typeUnite == TYPE_UNITE_LONGITUDE) {
|
||||||
|
obj["valeur"] = chaine_longitude(valeurBrute);
|
||||||
|
obj["valeur_texte"] = true;
|
||||||
|
obj["unite"] = QString();
|
||||||
|
} else {
|
||||||
|
// Cas des listes de valeurs/textes (entrées AUX ou booléen calculé) :
|
||||||
|
QString texteListe;
|
||||||
|
if (typeEntrees == TYPE_ENTREES_AUX || typeEntrees == TYPE_ENTREES_CALCULEE_BOOLEEN) {
|
||||||
|
const auto paires = listeValeursTextes.split(';');
|
||||||
|
for (const auto &paire : paires) {
|
||||||
|
const auto champs = paire.split('/');
|
||||||
|
if (champs.size() == 2 && champs[0].toDouble() == valeurBrute) {
|
||||||
|
texteListe = champs[1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!texteListe.isEmpty()) {
|
||||||
|
obj["valeur"] = texteListe;
|
||||||
|
obj["valeur_texte"] = true;
|
||||||
|
obj["unite"] = QString();
|
||||||
|
} else {
|
||||||
|
double valeurConvertie = valeurBrute;
|
||||||
|
QString symboleUnite = uniteBrute;
|
||||||
|
if (typeUnite == TYPE_UNITE_VOLUME) {
|
||||||
|
valeurConvertie = conversion_volume(valeurBrute, uniteVolume);
|
||||||
|
symboleUnite = symbole_unite_volume(uniteVolume);
|
||||||
|
} else if (typeUnite == TYPE_UNITE_TEMPERATURE) {
|
||||||
|
valeurConvertie = conversion_temperature(valeurBrute, uniteTemperature);
|
||||||
|
symboleUnite = symbole_unite_temperature(uniteTemperature);
|
||||||
|
}
|
||||||
|
// Arrondi à la précision d'affichage configurée (équivalent toFixed()) :
|
||||||
|
obj["valeur"] = QString::number(valeurConvertie, 'f', precision).toDouble();
|
||||||
|
obj["valeur_texte"] = false;
|
||||||
|
obj["unite"] = symboleUnite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
obj["obsolete"] = (typeEntrees == TYPE_ENTREES_NMEA && age > periodeObsolescenceNmea);
|
||||||
|
elements.append(obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject reponse;
|
QJsonObject reponse;
|
||||||
|
|||||||
Reference in New Issue
Block a user