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) :
|
||||
static const int TYPE_SOURCE_CIRCUIT = 1;
|
||||
static const int TYPE_SOURCE_CAPTEUR = 2;
|
||||
static const int TYPE_SOURCE_BATTERIE = 4;
|
||||
|
||||
// É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_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
|
||||
// (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;
|
||||
if (type == "circuit") typeSource = TYPE_SOURCE_CIRCUIT;
|
||||
else if (type == "batterie") typeSource = TYPE_SOURCE_BATTERIE;
|
||||
else if (type == "capteur") typeSource = TYPE_SOURCE_CAPTEUR;
|
||||
else {
|
||||
QJsonObject err;
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -165,6 +241,41 @@ int main(int argc, char *argv[])
|
||||
while (q3.next()) {
|
||||
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;
|
||||
@@ -192,10 +303,10 @@ int main(int argc, char *argv[])
|
||||
const QString type = query.queryItemValue("type");
|
||||
const QString familleStr = query.queryItemValue("famille");
|
||||
|
||||
if (type != "circuit" && type != "batterie") {
|
||||
if (type != "circuit" && type != "batterie" && type != "capteur") {
|
||||
QJsonObject err;
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -277,6 +388,116 @@ int main(int argc, char *argv[])
|
||||
obj["etat"] = q.value(7).toInt();
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user