coorections après fusion

This commit is contained in:
2026-04-13 17:07:35 +02:00
7 changed files with 722 additions and 860 deletions
+10 -10
View File
@@ -14,10 +14,10 @@ CONFIG -= app_bundle
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
src/main.cpp \
src/mqtt.cpp \
src/pws2mqtt.cpp \
src/utcicalculator.cpp
src/main.cpp \
# src/mqtt.cpp \
src/pws2mqtt.cpp \
src/utcicalculator.cpp
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
@@ -25,10 +25,10 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
HEADERS += \
src/barometertrend.h \
src/httpserver.h \
src/mqtt.h \
src/pws2mqtt.h \
src/utcicalculator.h \
src/version.h
src/barometertrend.h \
#src/httpserver.h \
# src/mqtt.h \
src/pws2mqtt.h \
src/utcicalculator.h \
src/version.h
+406 -387
View File
@@ -8,426 +8,445 @@
struct ForecastResult
{
QString message;
int urgency = 0; // 0-5
QString icons = ""; // "vert", "jaune", ...
bool snowRisk = false;
bool rainRisk = false;
bool stormRisk = false;
bool blackIce = false;
QString prevision1h ="";
quint8 confiance = 50;
QString message;
int urgency = 0; // 0-5
QString icons = ""; // "vert", "jaune", ...
bool snowRisk = false;
bool rainRisk = false;
bool stormRisk = false;
bool blackIce = false;
QString prevision1h ="";
quint8 confiance = 50;
};
class BarometerTrend : public QObject
{
Q_OBJECT
Q_OBJECT
public:
explicit BarometerTrend(QObject *parent = nullptr)
: QObject(parent)
{
m_values.reserve(360 + 16); // évite reallocs fréquentes
m_timestamps.reserve(360 + 16);
restoreHistory();
// Sauvegarde automatique toutes les 10 minutes
m_saveTimer = new QTimer(this);
connect(m_saveTimer, &QTimer::timeout, this, &BarometerTrend::saveHistory);
m_saveTimer->start(10 * 60 * 1000);
if (!m_saveTimer->isActive())
{
debug(DEBUGMACRO, "Le timer n'est pas démarré", ERROR);
}
}
explicit BarometerTrend(QObject *parent = nullptr)
: QObject(parent)
{
m_values.reserve(360 + 16); // évite reallocs fréquentes
m_timestamps.reserve(360 + 16);
restoreHistory();
// Sauvegarde automatique toutes les 10 minutes
m_saveTimer = new QTimer(this);
connect(m_saveTimer, &QTimer::timeout, this, &BarometerTrend::saveHistory);
m_saveTimer->start(10 * 60 * 1000);
if (!m_saveTimer->isActive())
{
debug(DEBUGMACRO, "Le timer n'est pas démarré", ERROR);
}
}
~BarometerTrend()
{
saveHistory();
}
void addPressure(double pressure_hPa)
{
debug(DEBUGMACRO, "adding pressure " + QByteArray::number(pressure_hPa), DEBUG);
// Enregistrement de la nouvelle mesure
m_values.append(pressure_hPa);
m_timestamps.append(QDateTime::currentDateTime());
~BarometerTrend()
{
saveHistory();
}
void addPressure(double pressure_hPa)
{
debug(DEBUGMACRO, "adding pressure " + QByteArray::number(pressure_hPa), DEBUG);
// Enregistrement de la nouvelle mesure
m_values.append(pressure_hPa);
m_timestamps.append(QDateTime::currentDateTime());
// Limiter la taille de lhistorique à 3 heures (360 mesures à 30s dintervalle)
const int maxSamples = 360;
while (m_values.size() > maxSamples)
{
m_values.removeFirst();
m_timestamps.removeFirst();
}
}
// Limiter la taille de lhistorique à 3 heures (360 mesures à 30s dintervalle)
const int maxSamples = 360;
while (m_values.size() > maxSamples)
{
m_values.removeFirst();
m_timestamps.removeFirst();
}
}
double currentPressure() const
{
return m_values.isEmpty() ? 0.0 : m_values.last();
}
double currentPressure() const
{
return m_values.isEmpty() ? 0.0 : m_values.last();
}
// Moyenne glissante sur les dernières N mesures (par ex. 5 minutes)
double smoothedPressure(int samples = 10) const
{
if (m_values.isEmpty())
{
return 0.0;
}
int n = qMin(samples, m_values.size());
double sum = 0.0;
for (int i = m_values.size() - n; i < m_values.size(); ++i)
sum += m_values[i];
debug(DEBUGMACRO, "smoothed pressure : " + QByteArray::number(sum/n), DEBUG);
return sum / n;
// Moyenne glissante sur les dernières N mesures (par ex. 5 minutes)
double smoothedPressure(int samples = 10) const
{
if (m_values.isEmpty())
{
return 0.0;
}
int n = qMin(samples, m_values.size());
double sum = 0.0;
for (int i = m_values.size() - n; i < m_values.size(); ++i)
sum += m_values[i];
debug(DEBUGMACRO, "smoothed pressure : " + QByteArray::number(sum/n), DEBUG);
return sum / n;
}
}
// Retourne la pression moyenne autour d'un instant cible (fenêtre +/- windowSecs)
double pressureAround(const QDateTime &target, int windowSecs = 60) const
{
if (m_values.isEmpty()) return 0.0;
const QDateTime from = target.addSecs(-windowSecs);
const QDateTime to = target.addSecs(+windowSecs);
double sum = 0.0;
int count = 0;
for (int i = 0; i < m_timestamps.size(); ++i) {
if (m_timestamps[i] >= from && m_timestamps[i] <= to) {
sum += m_values[i];
++count;
}
}
if (count == 0) {
// pas d'échantillon proche -> fallback sur la valeur la plus proche dans le passé
for (int i = m_timestamps.size() - 1; i >= 0; --i) {
if (m_timestamps[i] <= target) {
return m_values[i];
}
}
return m_values.first();
}
return sum / count;
}
// Variation de pression sur N heures (ex: 1 ou 3)
double deltaPressureHours(double hours) const
{
if (m_values.size() < 2) return 0.0;
QDateTime now = QDateTime::currentDateTime();
QDateTime past = now.addSecs(-qRound(hours * 3600.0));
double p_now = smoothedPressure(); // moyenne récente (~5 min)
double p_past = pressureAround(past, 60); // moyenne autour de l'instant passé
double delta = p_now - p_past;
// debug(DEBUGMACRO, "delta " + QByteArray::number(hours) + "h : " + QByteArray::number(delta), DEBUG);
return delta;
}
// helpers spécifiques
double deltaPressure3h() const { return deltaPressureHours(3.0); }
double deltaPressure1h() const { return deltaPressureHours(1.0); }
ForecastResult forecast(double temperatureC, double humidityPercent) const
{
ForecastResult r;
r.confiance = 50;
double p = currentPressure();
double d = deltaPressure3h();
double d3 = deltaPressure3h();
double d1 = deltaPressure1h();
// Retourne la pression moyenne autour d'un instant cible (fenêtre +/- windowSecs)
double pressureAround(const QDateTime &target, int windowSecs = 60) const
{
if (m_values.isEmpty()) return 0.0;
const QDateTime from = target.addSecs(-windowSecs);
const QDateTime to = target.addSecs(+windowSecs);
double sum = 0.0;
int count = 0;
for (int i = 0; i < m_timestamps.size(); ++i) {
if (m_timestamps[i] >= from && m_timestamps[i] <= to) {
sum += m_values[i];
++count;
}
}
if (count == 0) {
// pas d'échantillon proche -> fallback sur la valeur la plus proche dans le passé
for (int i = m_timestamps.size() - 1; i >= 0; --i) {
if (m_timestamps[i] <= target) {
return m_values[i];
}
}
return m_values.first();
}
return sum / count;
}
debug(DEBUGMACRO, "current pressure : " + QByteArray::number(p) + " - delta pressure 3h" + QByteArray::number(d), DEBUG);
// Variation de pression sur N heures (ex: 1 ou 3)
double deltaPressureHours(double hours) const
{
if (m_values.size() < 2) return 0.0;
QDateTime now = QDateTime::currentDateTime();
QDateTime past = now.addSecs(-qRound(hours * 3600.0));
double p_now = smoothedPressure(); // moyenne récente (~5 min)
double p_past = pressureAround(past, 60); // moyenne autour de l'instant passé
double delta = p_now - p_past;
// debug(DEBUGMACRO, "delta " + QByteArray::number(hours) + "h : " + QByteArray::number(delta), DEBUG);
return delta;
}
// build icon list to produce colorCode
QStringList icons;
// helpers spécifiques
double deltaPressure3h() const { return deltaPressureHours(3.0); }
double deltaPressure1h() const { return deltaPressureHours(1.0); }
// Logique combinée pression / tendance
if (p < 990 && d3 <= -3.0)
{
r.message = "- Tempête ou orage";
r.urgency = 5;
icons << "cloud_with_lightning";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p >= 1020 && d3 >= +3.0)
{
r.message = "- Très beau temps durable";
r.urgency = 0;
icons << "sunny";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p >= 1020 && d3 >= +1.0)
{
r.message = "- Beau temps durable";
r.urgency = 0;
icons << "sunny";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p >= 1020 && d3 < -3.0)
{
r.message = "- Beau, mais rapide dégradation";
r.urgency = 4;
icons << "sun_behind_large_cloud";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p >= 1020 && d3 < -1.0)
{
r.message = "- Beau, mais possible dégradation";
r.urgency = 1;
icons << "sun_behind_small_cloud";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
/*}else if (p >= 1020 && d3 < 0.5.0)
{
r.message = "- Beau temps";
r.urgency = 0;
icons << "sunny";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);*/
}else if (p >= 1010 && d3 >= +3.0)
{
r.message = "- Nuageux, rapide amélioration";
r.urgency = 4;
icons << "sun_behind_small_cloud";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p >= 1010 && d3 >= +1.0)
{
r.message = "- Nuageux, en amélioration";
r.urgency = 0;
icons << "sun_behind_large_cloud";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p >= 1010 && d3 <= -3.0)
{
r.message = "- Nuageux, fort risque de pluie ou vent";
r.urgency = 4;
icons << "sun_behind_rain_cloud";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p >= 1010 && d3 <= -1.0)
{
r.message = "- nuageux, risque de pluie ou vent";
r.urgency = 2;
icons << "sun_behind_rain_cloud";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p >= 1010 && d3 <= 0.5)
{
r.message = "- Nuageux avec des éclaircies";
r.urgency = 2;
icons << "sun_behind_large_cloud";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p >= 1000 && d3 >= +3.0)
{
r.message = "- Variable, amélioration rapide";
r.urgency = 4;
icons << "sun_behind_large_cloud";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p >= 1000 && d3 >= +1.0)
{
r.message = "- Variable, tendance au beau";
r.urgency = 0;
icons << "sun_behind_large_cloud";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p >= 1000 && d3 <= -3.0)
{
r.message = "- Pluie ou perturbation, dégradation rapide";
r.urgency = 4;
icons << "cloud_with_rain";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p >= 1000 && d3 <= -1.0)
{
r.message = "- Pluie ou perturbation";
r.urgency = 2;
icons << "cloud_with_rain";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p < 1000 && d3 >= +3.0)
{
r.message = "- Pluie avec accalmie temporaire, amélioration rapide";
r.urgency = 1;
icons << "sun_behind_rain_cloud";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p < 1000 && d3 >= +1.0)
{
r.message = "- Pluie avec accalmie temporaire";
r.urgency = 1;
icons << "sun_behind_rain_cloud";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p < 1000 && d3 <= -1.0)
{
r.message = "- Mauvais temps durable";
r.urgency = 4;
icons << "cloud_with_rain";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}
if (qAbs(d3) < 1)
{
r.message += "- Stable, pas de changement significatif";
r.urgency = 0;
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}
ForecastResult forecast(double temperatureC, double humidityPercent) const
{
ForecastResult r;
// Risque de neige
if (p < 1000 && d3 < -1.0 && temperatureC <= 1.0 && humidityPercent > 80.0)
{
r.snowRisk = true;
r.message += "- Risque de neige";
r.urgency = qMax(r.urgency, 3);
icons << "snowflake";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}
r.confiance = 50;
double p = currentPressure();
double d = deltaPressure3h();
double d3 = deltaPressure3h();
double d1 = deltaPressure1h();
// Risque de pluie
else if (p < 1010 && d3 < -1.0 && temperatureC > 1.0 && humidityPercent > 70.0)
{
r.rainRisk = true;
r.message += "- Risque de pluie";
r.urgency = qMax(r.urgency, 2);
icons << "cloud_with_rain";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}
debug(DEBUGMACRO, "current pressure : " + QByteArray::number(p) + " - delta pressure 3h" + QByteArray::number(d), DEBUG);
// Risque dorage
if (p < 995 && d3 < -3.0 && temperatureC > 20.0 && humidityPercent > 70.0)
{
r.stormRisk = true;
r.message += "- Risque dorage";
r.urgency = qMax(r.urgency, 4);
icons << "cloud_with_lightning";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}
// build icon list to produce colorCode
QStringList icons;
if (temperatureC <= 0.5 && humidityPercent >= 85.0) {
// conditions classiques de gel
if (d3 >= -1.0 && d3 <= +1.0)
{
r.blackIce = true; // temps stable = ciel clair = refroidissement
}else if (d < -1 && p > 995)
{
r.blackIce = true; // arrivée d'air humide froid
}
}
// Logique combinée pression / tendance
if (p < 990 && d3 <= -3.0)
{
r.message = "- Tempête ou orage";
r.urgency = 5;
icons << "cloud_with_lightning";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p >= 1020 && d3 >= +3.0)
{
r.message = "- Très beau temps durable";
r.urgency = 0;
icons << "sunny";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p >= 1020 && d3 >= +1.0)
{
r.message = "- Beau temps durable";
r.urgency = 0;
icons << "sunny";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p >= 1020 && (d3 <= +1.0 && d3 >= -1.0))
{
r.message = "- Beau temps stable";
r.urgency = 0;
icons << "sunny";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p >= 1015 && d3 < -3.0)
{
r.message = "- Beau, mais rapide dégradation";
r.urgency = 4;
icons << "sun_behind_large_cloud";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p >= 1015 && d3 < -1.0)
{
r.message = "- Beau, mais possible dégradation";
r.urgency = 1;
icons << "sun_behind_small_cloud";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p >= 1015 && (d3 <= 1.0 && d3 >= -1.0))
{
r.message = "- Beau temps stable";
r.urgency = 0;
icons << "sunny";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p >= 1005 && d3 >= +3.0)
{
r.message = "- Nuageux, rapide amélioration";
r.urgency = 4;
icons << "sun_behind_small_cloud";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p >= 1005 && d3 >= +1.0)
{
r.message = "- Nuageux, en amélioration";
r.urgency = 0;
icons << "sun_behind_large_cloud";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p >= 1005 && d3 <= -3.0)
{
r.message = "- Nuageux, fort risque de pluie ou vent";
r.urgency = 4;
icons << "sun_behind_rain_cloud";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p >= 1005 && d3 <= -1.0)
{
r.message = "- nuageux, risque de pluie ou vent";
r.urgency = 2;
icons << "sun_behind_rain_cloud";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p >= 1005 && (d3 <= 1.0 && d3 >= 1.0))
{
r.message = "- Nuageux avec des éclaircies";
r.urgency = 2;
icons << "sun_behind_large_cloud";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p >= 1000 && d3 >= +3.0)
{
r.message = "- Variable, amélioration rapide";
r.urgency = 4;
icons << "sun_behind_large_cloud";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p >= 1000 && d3 >= +1.0)
{
r.message = "- Variable, tendance au beau";
r.urgency = 0;
icons << "sun_behind_large_cloud";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p >= 1000 && d3 <= -3.0)
{
r.message = "- Pluie ou perturbation, dégradation rapide";
r.urgency = 4;
icons << "cloud_with_rain";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p >= 1000 && d3 <= -1.0)
{
r.message = "- Pluie ou perturbation";
r.urgency = 2;
icons << "cloud_with_rain";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p >= 1000 && (d3 <= 1.0 && d3 >= -1.0))
{
r.message = "- Pluie ou perturbation stable";
r.urgency = 2;
icons << "cloud_with_rain";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p < 1000 && d3 >= +3.0)
{
r.message = "- Pluie avec accalmie temporaire, amélioration rapide";
r.urgency = 1;
icons << "sun_behind_rain_cloud";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p < 1000 && d3 >= +1.0)
{
r.message = "- Pluie avec accalmie temporaire";
r.urgency = 1;
icons << "sun_behind_rain_cloud";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p < 1000 && d3 <= -1.0)
{
r.message = "- Mauvais temps durable";
r.urgency = 4;
icons << "cloud_with_rain";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}else if (p < 1000 && (d3 <= 1.0 && d3 >= -1.0))
{
r.message = "- Mauvais temps stable";
r.urgency = 4;
icons << "cloud_with_rain";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}
if (r.blackIce)
{
r.message += "- Risque de verglas";
icons << "ice_cube";
r.urgency = qMax(r.urgency, 4);
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}
/*if (qAbs(d3) < 1)
{
r.message += "- Stable, pas de changement significatif";
r.urgency = 0;
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}*/
// --- Prévision à 1 heure ---
if (d <= -1.5 && p < 1010 && humidityPercent > 80.0)
{
r.prevision1h = "- Pluie probable dans l'heure";
r.urgency = qMax(r.urgency, 4);
r.confiance = 80;
}else if (d >= +1.5 && p > 1015)
{
r.prevision1h = "- mélioration probable dans l'heure";
r.confiance = 85;
}else if (qAbs(d1) < 0.3 && qAbs(temperatureC) < 0.5)
{
r.prevision1h = "- Conditions stables pour la prochaine heure";
r.confiance = 70;
}else if (temperatureC < 0 && humidityPercent > 85)
{
r.prevision1h = "- Possible formation de givre ou verglas dans l'heure";
r.urgency = qMax(r.urgency, 4);
r.confiance = 75;
}else
{
r.prevision1h = "- pas de changements dans l'heure";
r.urgency = qMax(r.urgency, 2);
r.confiance = 85;
}
// Risque de neige
if (p < 1000 && d3 < -1.0 && temperatureC <= 1.0 && humidityPercent > 80.0)
{
r.snowRisk = true;
r.message += "- Risque de neige";
r.urgency = qMax(r.urgency, 3);
icons << "snowflake";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}
// Risque de pluie
else if (p < 1010 && d3 < -1.0 && temperatureC > 1.0 && humidityPercent > 70.0)
{
r.rainRisk = true;
r.message += "- Risque de pluie";
r.urgency = qMax(r.urgency, 3);
icons << "cloud_with_rain";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}
// Risque dorage
if (p < 995 && d3 < -3.0 && temperatureC > 20.0 && humidityPercent > 70.0)
{
r.stormRisk = true;
r.message += "- Risque dorage";
r.urgency = qMax(r.urgency, 4);
icons << "cloud_with_lightning";
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}
if (temperatureC <= 0.5 && humidityPercent >= 85.0) {
// conditions classiques de gel
if (d3 >= -1.0 && d3 <= +1.0)
{
r.blackIce = true; // temps stable = ciel clair = refroidissement
}else if (d < -1 && p > 995)
{
r.blackIce = true; // arrivée d'air humide froid
}
}
if (r.blackIce)
{
r.message += "- Risque de verglas";
icons << "ice_cube";
r.urgency = qMax(r.urgency, 4);
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
}
// --- Prévision à 1 heure ---
if (d <= -1.5 && p < 1010 && humidityPercent > 80.0)
{
r.prevision1h = "- Pluie probable dans l'heure";
r.urgency = qMax(r.urgency, 3);
r.confiance = 80;
}else if (d >= +1.5 && p > 1015)
{
r.prevision1h = "- mélioration probable dans l'heure";
r.confiance = 85;
}else if (qAbs(d1) < 0.3 && qAbs(temperatureC) < 0.5)
{
r.prevision1h = "- Conditions stables pour la prochaine heure";
r.confiance = 70;
}else if (temperatureC < 0 && humidityPercent > 85)
{
r.prevision1h = "- Possible formation de givre ou verglas dans l'heure";
r.urgency = qMax(r.urgency, 4);
r.confiance = 75;
}else
{
r.prevision1h = "- pas de changements dans l'heure";
r.urgency = qMax(r.urgency, 2);
r.confiance = 85;
}
// --- Ajustement de confiance selon stabilité barométrique ---
if (qAbs(d) > 3.0)
{
r.confiance -= 15; // variations trop fortes → prévision moins fiable
}
if (p < 990 || p > 1030)
{
r.confiance -= 10; // situations extrêmes, moins prédictibles
}
if (r.blackIce)
{
r.confiance += 5; // phénomène local très probable
}
r.confiance = qBound((quint8)0, r.confiance, (quint8)100); // borne entre 0 et 100
// --- Ajustement de confiance selon stabilité barométrique ---
if (qAbs(d) > 3.0)
{
r.confiance -= 15; // variations trop fortes → prévision moins fiable
}
if (p < 990 || p > 1030)
{
r.confiance -= 10; // situations extrêmes, moins prédictibles
}
if (r.blackIce)
{
r.confiance += 5; // phénomène local très probable
}
r.confiance = qBound((quint8)0, r.confiance, (quint8)100); // borne entre 0 et 100
// --- Résultat complet ---
if (!r.prevision1h.isEmpty())
{
r.message += "\n**Prévision dans l'heure**";
r.message += "\n" + r.prevision1h;
r.message += "\n- Probabilité " + QByteArray::number(r.confiance) + "%";
}
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
// --- Résultat complet ---
if (!r.prevision1h.isEmpty())
{
r.message += "\n**Prévision dans l'heure**";
r.message += "\n" + r.prevision1h;
r.message += "\n- Probabilité " + QByteArray::number(r.confiance) + "%";
}
debug(DEBUGMACRO, "message : " + r.message, DEBUG);
if (!icons.isEmpty()) r.icons = icons.join(",");
if (!icons.isEmpty()) r.icons = icons.join(",");
return r;
}
return r;
}
private:
QVector<double> m_values;
QVector<QDateTime> m_timestamps;
QTimer *m_saveTimer;
QVector<double> m_values;
QVector<QDateTime> m_timestamps;
QTimer *m_saveTimer;
private slots:
void saveHistory()
{
QJsonArray array;
for (int i = 0; i < m_values.size(); ++i)
{
QJsonObject obj;
obj["timestamp"] = m_timestamps[i].toString(Qt::ISODate);
obj["pressure"] = m_values[i];
array.append(obj);
}
void saveHistory()
{
QJsonArray array;
for (int i = 0; i < m_values.size(); ++i)
{
QJsonObject obj;
obj["timestamp"] = m_timestamps[i].toString(Qt::ISODate);
obj["pressure"] = m_values[i];
array.append(obj);
}
QJsonDocument doc(array);
QFile file("/usr/local/share/pws2mqtt/barometer_history.json");
if (file.open(QIODevice::WriteOnly | QIODevice::Truncate))
{
file.write(doc.toJson());
file.close();
debug(DEBUGMACRO, "Barometer history saved (" + QByteArray::number(m_values.size()) + " samples)", DEBUG);
}else
{
debug(DEBUGMACRO, "File not open : " + file.errorString() , WARNING);
}
}
QJsonDocument doc(array);
QFile file("/usr/local/share/pws2mqtt/barometer_history.json");
if (file.open(QIODevice::WriteOnly | QIODevice::Truncate))
{
file.write(doc.toJson());
file.close();
debug(DEBUGMACRO, "Barometer history saved (" + QByteArray::number(m_values.size()) + " samples)", DEBUG);
}else
{
debug(DEBUGMACRO, "File not open : " + file.errorString() , WARNING);
}
}
void restoreHistory()
{
QFile file("/usr/local/share/pws2mqtt/barometer_history.json");
if (!file.exists())
{
debug(DEBUGMACRO, "File not open : " + file.errorString() , WARNING);
return;
}
if (file.open(QIODevice::ReadOnly))
{
QByteArray data = file.readAll();
file.close();
void restoreHistory()
{
QFile file("/usr/local/share/pws2mqtt/barometer_history.json");
if (!file.exists())
{
debug(DEBUGMACRO, "File not open : " + file.errorString() , WARNING);
return;
}
if (file.open(QIODevice::ReadOnly))
{
QByteArray data = file.readAll();
file.close();
QJsonDocument doc = QJsonDocument::fromJson(data);
if (!doc.isArray()) return;
QJsonDocument doc = QJsonDocument::fromJson(data);
if (!doc.isArray()) return;
QJsonArray array = doc.array();
for (const QJsonValue &val : array)
{
QJsonObject obj = val.toObject();
double pressure = obj["pressure"].toDouble();
QDateTime ts = QDateTime::fromString(obj["timestamp"].toString(), Qt::ISODate);
if (ts.isValid())
{
m_values.append(pressure);
m_timestamps.append(ts);
}
}
QJsonArray array = doc.array();
for (const QJsonValue &val : array)
{
QJsonObject obj = val.toObject();
double pressure = obj["pressure"].toDouble();
QDateTime ts = QDateTime::fromString(obj["timestamp"].toString(), Qt::ISODate);
if (ts.isValid())
{
m_values.append(pressure);
m_timestamps.append(ts);
}
}
// On ne garde que les 3 dernières heures
QDateTime limit = QDateTime::currentDateTime().addSecs(-3 * 3600);
while (!m_timestamps.isEmpty() && m_timestamps.first() < limit)
{
m_timestamps.removeFirst();
m_values.removeFirst();
}
// On ne garde que les 3 dernières heures
QDateTime limit = QDateTime::currentDateTime().addSecs(-3 * 3600);
while (!m_timestamps.isEmpty() && m_timestamps.first() < limit)
{
m_timestamps.removeFirst();
m_values.removeFirst();
}
debug(DEBUGMACRO, "Barometer history restored (" + QByteArray::number(m_values.size()) + " samples)", DEBUG);
}
}
debug(DEBUGMACRO, "Barometer history restored (" + QByteArray::number(m_values.size()) + " samples)", DEBUG);
}
}
};
+27 -46
View File
@@ -1,41 +1,39 @@
#include <QCoreApplication>
#include <QString>
//#include <QObject>
#include <unistd.h>
//#include <unistd.h>
#include <QtGlobal>
#include <iostream>
#include <QDebug>
#include <sys/socket.h>
#include <netinet/in.h>
#include <QtMqtt>
#include <QtMqtt/QMqttClient>
#include <QtMqtt/QMqttMessage>
#include <QtMqtt/QMqttSubscription>
//#include <iostream>
//#include <QDebug>
#include <qhttpserver.h>
#include <QHttpServerResponse>
#include "pws2mqtt.h"
#include "mqtt.h"
#ifdef WITH_MQTT
#include "mqtt.h"
#endif
#include "src/barometertrend.h"
#include "version.h"
#include <curl/curl.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>
//#include <sys/types.h>
//#include <sys/select.h>
#ifdef WITH_MQTT
#include <QtMqtt>
#include <QtMqtt/QMqttClient>
#include <QtMqtt/QMqttMessage>
#include <QtMqtt/QMqttSubscription>
#endif
#define CLIENT_ID "Client_ID"
#define BROKER_ADDRESS "localhost"
#define MQTT_PORT 1883;
uint debugLevel = DEBUG | INFO | NOTICE | INFO | WARNING | ERROR | ALERT;
uint debugLevel = INFO | ERROR | ALERT;
QByteArray toFollow;
//class MqttClient;
#ifdef WITH_MQTT
class MqttClient;
MqttClient *mqttClient;
#endif
using namespace std;
//Configuration config;
Pws2mqtt *pws2mqtt;
MqttClient *mqttClient;
QHttpServer *httpServer;
BarometerTrend *baro;
@@ -54,45 +52,28 @@ int main(int argc, char *argv[])
// Enable logging to journald
qputenv("QT_FORCE_STDERR_LOGGING", QByteArray("0"));
debug(DEBUGMACRO, "declaration of mqttClient", DEBUG);
#ifdef WITH_MQTT
debug(DEBUGMACRO, "declaration of mqttClient", INFO);
mqttClient = new MqttClient;
#endif
httpServer = new QHttpServer;
//declaration of debug level
pws2mqtt = new Pws2mqtt;
baro = new BarometerTrend;
baro = new BarometerTrend;
pws2mqtt->listeningHttp();
//notify (QString("Program started"), "default");
a.exec();
#ifdef WITH_MQTT
mqttClient->qmqttClient->unsubscribe(mqttClient->topic);
mqttClient->qmqttClient->disconnectFromHost();
debug(DEBUGMACRO, "exiting", DEBUG);
#endif
debug(DEBUGMACRO, "exiting", INFO);
notify ("Program exiting \n", "high");
//Closing http server
}
/*QString addValue(QByteArray value)
{
bool ok;
QString str;
value.toFloat(&ok);
if (ok)
{
str = (value);
}else
{
str = ("\"" + value + "\"" );
}
return str;
}*/
void debug(QString debugHeader, QString msg, uint8_t level, QByteArray property)
{
@@ -108,7 +89,7 @@ void debug(QString debugHeader, QString msg, uint8_t level, QByteArray property)
if ((debugLevel & level) == 4)
{
qInfo("%s%s WARNING: %s%s", debugHeader.toStdString().c_str(), ORANGE, msg.toStdString().c_str(), NORMAL);
notify (debugHeader + " - " + msg);
notify (debugHeader + " - " + msg);
}
if ((debugLevel & level) == 8)
{
-57
View File
@@ -11,63 +11,6 @@
#define MQTT_TOPIC "pws2mqtt"
/*{128, "Unspecified error: The Server does not wish to reveal the reason for the failure, or none of the other Reason Codes apply."},
{129, "Malformed Packet; Data within the CONNECT packet could not be correctly parsed."},
{130, "Protocol Error: Data in the CONNECT packet does not conform to this specification."},
{131, "Implementation specific error: The CONNECT is valid but is not accepted by this Server."},
{132, "Unsupported Protocol Version: The Server does not support the version of the MQTT protocol requested by the Client."},
{133, "Client Identifier not valid: The Client Identifier is a valid string but is not allowed by the Server."},
{134, "Bad User Name or Password: The Server does not accept the User Name or Password specified by the Client."},
{135, "Not authorized: The Client is not authorized to connect."},
{136, "Server unavailable: The MQTT Server is not available."},
{137, "Server busy: The Server is busy. Try again later."},
{138, "Banned: This Client has been banned by administrative action. Contact the server administrator."},
{140, "Bad authentication method: The authentication method is not supported or does not match the authentication method currently in use."},
{144, "Topic Name invalid: The Will Topic Name is not malformed, but is not accepted by this Server."},
{149, "Packet too large: The CONNECT packet exceeded the maximum permissible size."},
{151, "Quota exceeded: An implementation or administrative imposed limit has been exceeded."},
{153, "Payload format invalid: The Will Payload does not match the specified Payload Format Indicator."},
{154, "Retain not supported: The Server does not support retained messages, and Will Retain was set to 1."},
{155, "QoS not supported: The Server does not support the QoS set in Will QoS."},
{156, "Use another server: The Client should temporarily use another server."},
{157, "Server moved: The Client should permanently use another server."},
{159, "Connection rate exceeded: The connection rate limit has been exceeded."},
QHash <int, QString> mosq_error
{
{MOSQ_ERR_ERRNO, "System return error"},
{MOSQ_ERR_INVAL, "Input parameters were invalid."},
{MOSQ_ERR_NOMEM, "Out of memory condition occurred."},
{MOSQ_ERR_PAYLOAD_SIZE, "Payloadlen is too large."},
{MOSQ_ERR_MALFORMED_UTF8, "The topic is not valid UTF-8."},
{MOSQ_ERR_NOT_SUPPORTED, "Properties is not NULL and the client is not using MQTT v5"},
{MOSQ_ERR_NO_CONN, "if the client isnt connected to a broker."},
{MOSQ_ERR_DUPLICATE_PROPERTY, "A property is duplicated where it is forbidden."},
{MOSQ_ERR_PROTOCOL, "Any property is invalid for use with DISCONNECT."},
{MOSQ_ERR_QOS_NOT_SUPPORTED, "The QoS is greater than that supported by the broker."},
{MOSQ_ERR_OVERSIZE_PACKET, "The resulting packet would be larger than supported by the broker."},
{MOSQ_ERR_CONN_LOST, "The connection to the broker was lost."},
{MOSQ_ERR_PROTOCOL, "There is a protocol error communicating with the broker."},
};
*/
/*class MqttSub : public QMqttSubscription
{
Q_OBJECT;
public:
explicit MqttSub();
~MqttSub();
public slots:
void updateStatus({ , "SubscriptionState state);
};*/
class MqttClient : public QObject
{
Q_OBJECT
+175 -231
View File
@@ -1,25 +1,23 @@
#include "pws2mqtt.h"
#include "barometertrend.h"
#include "mqtt.h"
//#include "httpserver.h"
#include <cstring>
#include <unistd.h>
//#include <cstring>
#include <QtGlobal>
#include <QList>
#include <sys/socket.h>
#include <netinet/in.h>
#include <QtHttpServer/QHttpServer>
#include <QtHttpServer/QHttpServerRequest>
#include <QHttpServerResponse>
#include <curl/curl.h>
#include <QtMath>
#include <QImage>
#include <QTransform>
#include <stdio.h>
#include <sys/stat.h>
//#include <sys/stat.h>
#include "qstringview.h"
#include "utcicalculator.h"
#include <QNetworkAccessManager>
#include <QNetworkReply>
#ifdef WITH_MQTT
#include "mqtt.h"
/extern MqttClient *mqttClient;
#endif
extern MqttClient *mqttClient;
extern Pws2mqtt *pws2mqtt;
extern QHttpServer *httpServer;
extern BarometerTrend *baro;
@@ -46,7 +44,7 @@ QMap <QByteArray, QPair<QString, QByteArray>> propertyName
{
{"tempf", {"Température extérieure", "°C"}},
{"humidity", {"Humidité extérieure", "%"}},
{"dewptf", {"Point de rosée", "°C"}},
// {"dewptf", {"Point de rosée", "°C"}},
{"windchill", {"Température ressentie", "°C"}},
{"winddir", {"Direction du vent", "°"}},
{"windspeedmph", {"Vitesse du vent", " km/h"}},
@@ -55,12 +53,12 @@ QMap <QByteArray, QPair<QString, QByteArray>> propertyName
{"dailyrainin", {"Pluie de la journée", " mm"}},
// {"monthlyrainin", {"Pluie du mois", " mm"}},
// {"yearlyrainin", {"Pluie de l'année", " mm"}},
// {"solarradiation", {"Énergie solaire", " W/m²"}},
{"solarradiation", {"Énergie solaire", " W/m²"}},
// {"indoortempf", {"Température intérieure", "°C"}},
// {"indoorhumidity", {"Humidité intérieure", "%"}},
{"baromin", {"Pression atmosphérique", " hPa"}},
// {"lowbatt", {"Alerte batterie faible", ""}},
{"UV", {"Alerte UV", ""}}
{"UV", {"UV", ""}}
};
QList <QList <QVariant>> forceVent
@@ -91,13 +89,13 @@ Pws2mqtt::~Pws2mqtt()
void Pws2mqtt::init()
{
debug(DEBUGMACRO, "init http server", DEBUG);
httpServer->setMissingHandler(httpServer,[](const QHttpServerRequest &request, QHttpServerResponder &responder)
debug(DEBUGMACRO, "init http server", INFO);
/*httpServer->setMissingHandler([](const QHttpServerRequest &request, QHttpServerResponder &&responder)
{
debug(DEBUGMACRO, "body " + request.url().toString(), WARNING);
//responder.write(QHttpServerResponse(QString("404 - Page non trouvée. Route par défaut."), QHttpServerResponse::StatusCode::NotFound));
responder.write(QByteArray("404 - Page non trouvée. Route par défaut."), "text/plain", QHttpServerResponse::StatusCode::NotFound);
});
});*/
httpServer->route("/", [](const QHttpServerRequest &request)
{
@@ -108,7 +106,7 @@ void Pws2mqtt::init()
{
QByteArray data;
QList<std::pair<QString, QString>> queryList = request.query().queryItems();
debug(DEBUGMACRO, "Réception des données", INFO);
//QTextStream result(&data);
if (queryList.isEmpty())
@@ -116,21 +114,59 @@ void Pws2mqtt::init()
debug(DEBUGMACRO, "Request query is empty", WARNING);
}else
{
debug(DEBUGMACRO, "Request query :" + request.query().toString() , DEBUG);
this->parseData(queryList);
debug(DEBUGMACRO, "Request query :" + request.query().toString() , INFO
);
/* QMetaObject::invokeMethod(this, [this, query = request.query()]() {
this->parseData(query.queryItems());
}, Qt::QueuedConnection);*/
parseData(request.query().queryItems());
debug(DEBUGMACRO, "Returning 'success'", DEBUG);
}
//mqttClient.send_message(jsonString);
return QHttpServerResponse("text/plain", "Requête traitée en arrière-plan\n");
return QHttpServerResponse("text/plain", "Success\n");
//return QHttpServerResponse("text/plain", "Success\n");
});
for (auto [name, pair]: propertyName.asKeyValueRange())
{
propertyList[name].append(formatNotifString(pair.first, pair.second, "0"));
propertyList[name].append(formatNotifString(pair, "0"));
debug (DEBUGMACRO, "Init " + name + " => " + propertyList[name], DEBUG);
}
}
void notify(QString notif, QString priority, QString inputPath, QString tag)
{
(void) inputPath;
QNetworkAccessManager *manager = new QNetworkAccessManager();
QNetworkRequest request(QUrl("http://localhost:81/Meteo"));
request.setRawHeader("Content-Type", "charset=UTF-8; text/markdown");
if (!tag.isEmpty())
{
request.setRawHeader("Tags", tag.toUtf8());
}
request.setRawHeader("Title", "Météo");
request.setRawHeader("Priority", priority.toUtf8());
request.setRawHeader("Markdown", "yes");
request.setRawHeader("Config", "/etc/ntfy.client.yml");
request.setRawHeader("Firebase", "no");
QNetworkReply *reply = manager->post(request, notif.toUtf8());
QObject::connect(reply, &QNetworkReply::finished, [reply]()
{
if (reply->error() != QNetworkReply::NoError)
{
debug(DEBUGMACRO, "Erreur réseau : " + reply->errorString(), ERROR);
} else
{
debug(DEBUGMACRO, "Notification envoyée", DEBUG);
}
reply->deleteLater();
});
delete(manager);
}
void Pws2mqtt::listeningHttp()
{
//QByteArray data;
@@ -141,20 +177,23 @@ void Pws2mqtt::listeningHttp()
{
debug(DEBUGMACRO, "Http Server failed to listen on a port.", ERROR);
}
debug(DEBUGMACRO, "Listening on port " + QString::number(port));
debug(DEBUGMACRO, "Listening on port " + QString::number(port), INFO);
}
void Pws2mqtt::parseData(QList<std::pair<QString, QString>> queryList)
{
debug(DEBUGMACRO, "Parsing Datas", DEBUG);
#ifdef WITH_MQTT
QString jsonString = "{";
QString deviceString = "\"device\": {\"ieeeAddress\": \"" + mqttClient->macAddress + "\", \"type\": \"" + mqttClient->type + "\", \"powerSource\": \"Battery\"";
#endif
QString notif = "";
QStringList priorityList {"", "min", "low", "default", "High", "urgent"};
QString attachment = "";
QString tag = "";
quint8 priority = 2;
QHash <QByteArray, quint8> priority;
bool start = false;
double propertyValue = 0;
bool propertyFlag = false;
bool deviceFlag = false;
@@ -174,24 +213,29 @@ void Pws2mqtt::parseData(QList<std::pair<QString, QString>> queryList)
if(deviceFlag == false)
{
deviceFlag = true;
}else
}
#ifdef WITH_MQTT
else
{
deviceString.append(", ");
}
deviceString += "\"" + name + "\": ";
deviceString += pair.second;
#endif
}else
{
if(propertyFlag == false)
{
propertyFlag = true;
}else
}
#ifdef WITH_MQTT
else
{
jsonString.append(", ");
}
jsonString.append("\"" + name + "\": ");
jsonString.append(pair.second);
#endif
if (name == "tempf")
{
static QDateTime timeTemp = QDateTime::currentDateTime().addSecs(-600);
@@ -203,8 +247,15 @@ void Pws2mqtt::parseData(QList<std::pair<QString, QString>> queryList)
//notif += formatNotifString (propertyName[name].first, propertyName[name].second, QByteArray::number(qPow(propertyValue, 1.0)));
//debug (DEBUGMACRO, "", DEBUG);
timeTemp = timeTemp.currentDateTime().addSecs(300);
propertyList[name] = formatNotifString(propertyName[name].first, propertyName[name].second, QByteArray::number(propertyValue));
propertyList[name] = formatNotifString(propertyName[name], QByteArray::number(propertyValue));
propertiesValue[name] = propertyValue;
if (propertyValue > 35)
{
priority[name] = 4;
}else if (propertyValue > 27)
{
priority[name] = 3;
}
}
}else if (name == "humidity")
{
@@ -214,7 +265,7 @@ void Pws2mqtt::parseData(QList<std::pair<QString, QString>> queryList)
if (compare (propertiesValue[name], propertyValue, 3))
{
//notif += formatNotifString (propertyName[name].first, propertyName[name].second , value);
propertyList[name] = formatNotifString(propertyName[name].first, propertyName[name].second, QByteArray::number(propertyValue));
propertyList[name] = formatNotifString(propertyName[name], QByteArray::number(propertyValue));
propertiesValue[name] = propertyValue;
}
}else if (name == "winddir")
@@ -222,7 +273,8 @@ void Pws2mqtt::parseData(QList<std::pair<QString, QString>> queryList)
propertyValue = value.toFloat();
rotateAndSaveImage(this->inputPath, this->outputPath, (qreal)propertyValue);
debug (DEBUGMACRO, name + " : " + QByteArray::number(propertyValue), DEBUG);
propertyList[name] = formatNotifString(propertyName[name].first, propertyName[name].second, QByteArray::number(propertyValue));
propertyList[name] = formatNotifString(propertyName[name], QByteArray::number(propertyValue));
propertiesValue[name] = propertyValue;
}else if (name == "windspeedmph")
{
@@ -231,13 +283,13 @@ void Pws2mqtt::parseData(QList<std::pair<QString, QString>> queryList)
static QDateTime timeWind = QDateTime::currentDateTime().addSecs(-600);
quint8 windPriority = 1;
propertiesValue["vent"] = round(mphTokmh(value.toFloat()));
propertiesValue[name] = round(mphTokmh(value.toFloat()));
debug (DEBUGMACRO, name + " : " + QByteArray::number(propertiesValue["vent"]), DEBUG);
debug (DEBUGMACRO, name + " : " + QByteArray::number(propertiesValue[name]), DEBUG);
for (i=0; i<forceVent.size();i++)
{
if (propertiesValue["vent"] <= forceVent[i][0].toDouble())
if (propertiesValue[name] <= forceVent[i][0].toDouble())
{
msg = forceVent[i][1].toString();
windPriority = forceVent[i][2].toUInt();
@@ -245,7 +297,7 @@ void Pws2mqtt::parseData(QList<std::pair<QString, QString>> queryList)
}
}
propertyList[name] = formatNotifString ("Vent - " + msg, propertyName[name].second , QByteArray::number(propertiesValue["vent"]));
propertyList[name] = "- Vent - " + msg + " : " + QByteArray::number(propertiesValue[name]) + "Km/h" + "\n";
propertiesValue["forcevent"] = i;
if (i >= 5)
{
@@ -254,9 +306,9 @@ void Pws2mqtt::parseData(QList<std::pair<QString, QString>> queryList)
if (propertiesValue["forcevent"] != i)
{
priority = qMax(priority, windPriority);
priority[name] = qMax(priority[name], windPriority);
}
debug (DEBUGMACRO, "priority = " + QString::number(priority), DEBUG);
debug (DEBUGMACRO, "priority = " + QString::number(priority[name]), DEBUG);
}else if (name == "windgustmph")
{
QString msg = "";
@@ -264,15 +316,15 @@ void Pws2mqtt::parseData(QList<std::pair<QString, QString>> queryList)
propertiesValue[name] = round(mphTokmh(value.toFloat()));
debug (DEBUGMACRO, name + " : " + QByteArray::number(propertiesValue["rafale"]), DEBUG);
debug (DEBUGMACRO, name + " : " + QByteArray::number(propertiesValue[name]), DEBUG);
propertyList[name] = formatNotifString (propertyName[name].first, propertyName[name].second , QByteArray::number(propertiesValue[name]));
propertyList[name] = formatNotifString (propertyName[name], QByteArray::number(propertiesValue[name]));
if (propertiesValue["rafales"] > 50)
if (propertiesValue[name] > 50)
{
priority = qMax(priority, (quint8)4);
priority[name] = qMax(priority[name], (quint8)4);
}
debug (DEBUGMACRO, "priority = " + QString::number(priority), DEBUG);
debug (DEBUGMACRO, "priority = " + QString::number(priority[name]), DEBUG);
}else if (name == "rainin")
{
static double ecart;
@@ -289,12 +341,12 @@ void Pws2mqtt::parseData(QList<std::pair<QString, QString>> queryList)
if (compare (propertiesValue[name], propertyValue, ecart))
{
QString pluviosite = getPluviosite(propertyValue, raininPriority);
priority = setPriority (priority, raininPriority);
priority[name] = setPriority (priority[name], raininPriority);
//debug (DEBUGMACRO, "Notif = #" + notif + "#", DEBUG);
propertyList[name] = formatNotifString(pluviosite, propertyName[name].second, QByteArray::number(propertyValue));
propertyList[name] = formatNotifString(propertyName[name], QByteArray::number(propertyValue));
propertiesValue[name] = propertyValue;
}
debug (DEBUGMACRO, "priority = " + QString::number(priority), DEBUG);
debug (DEBUGMACRO, "priority = " + QString::number(priority[name]), DEBUG);
}else if (name == "dailyrainin")
{
static double ecart;
@@ -309,20 +361,19 @@ void Pws2mqtt::parseData(QList<std::pair<QString, QString>> queryList)
debug (DEBUGMACRO, name + " : " + QByteArray::number(propertyValue), DEBUG);
if (compare (propertiesValue[name], propertyValue, ecart))
{
//priority = setPriority (priority, 3);
//priority[name] = setPriority (priority[name], 3);
//debug (DEBUGMACRO, "Notif = #" + notif + "#", DEBUG);
propertyList[name] = formatNotifString(propertyName[name].first, propertyName[name].second, QByteArray::number(propertyValue));
propertyList[name] = formatNotifString(propertyName[name], QByteArray::number(propertyValue));
propertiesValue[name] = propertyValue;
}
debug (DEBUGMACRO, "priority = " + QString::number(priority), DEBUG);
debug (DEBUGMACRO, "priority = " + QString::number(priority[name]), DEBUG);
}else if (name == "baromin")
{
//static QDateTime timePrevision = QDateTime::currentDateTime().addSecs(-1000);
propertyValue = round(tohPa(pair.second.toFloat()) * 100) / 100;
debug (DEBUGMACRO, "Barometre en hPa : " + QByteArray::number(propertyValue), DEBUG);
baro->addPressure(propertyValue);
propertyList[name] = formatNotifString(propertyName[name].first, "", QByteArray::number(propertyValue));
propertyList[name] = formatNotifString(propertyName[name], QByteArray::number(propertyValue));
propertiesValue[name] = propertyValue;
static QString prevision;
@@ -331,13 +382,14 @@ void Pws2mqtt::parseData(QList<std::pair<QString, QString>> queryList)
prevision = ret.message;
//if (prevision != newPrevision)
//{
priority = setPriority(priority, ret.urgency);
priority[name] = setPriority(priority[name], ret.urgency);
tag += ret.icons;
propertyList["prevision"] = prevision;
debug (DEBUGMACRO, "priority = " + QString::number(priority), DEBUG);
debug (DEBUGMACRO, "priority = " + QString::number(priority[name]), DEBUG);
}else if (name == "UV")
{
QString msg;
static QDateTime timeUV = QDateTime::currentDateTime().addSecs(-600);
propertyValue = pair.second.toUInt();
@@ -346,27 +398,30 @@ void Pws2mqtt::parseData(QList<std::pair<QString, QString>> queryList)
{
//notif += formatNotifString (propertyName[name].first, propertyName[name].second , value);
if (propertyValue == 5 )
priority = setPriority (priority, 4);
priority[name] = setPriority (priority[name], 4);
if (propertyValue >= 6 )
priority = setPriority (priority, 5);
priority[name] = setPriority (priority[name], 5);
timeUV = timeUV.currentDateTime().addSecs(300);
propertiesValue[name] = propertyValue;
debug (DEBUGMACRO, "Notif = #" + notif + "#", DEBUG);
propertyList[name] = formatNotifString(propertyName[name].first, "", QByteArray::number(propertyValue));
propertyList[name] = "- UV - " + QByteArray::number(propertyValue) + "\n";
}
debug (DEBUGMACRO, "priority = " + QString::number(priority), DEBUG);
debug (DEBUGMACRO, "priority = " + QString::number(priority[name]), DEBUG);
}else if (name == "solarradiation")
{
propertyValue = pair.second.toFloat()*100/100;
propertyList[name] = formatNotifString(propertyName[name], QByteArray::number(propertyValue));
propertiesValue[name] = round(pair.second.toFloat()*100/100);
debug (DEBUGMACRO, "SolarRadiations = " + QByteArray::number(propertyValue), DEBUG);
}
}
}
propertiesValue["windchill"] = calc.computeUTCI(propertiesValue["tempf"], propertiesValue["vent"], propertiesValue["solarradiation"], propertiesValue["humidity"]);
propertyList["windchill"] = formatNotifString(propertyName["windchill"].first, propertyName["windchill"].second, QByteArray::number(propertiesValue["windchill"]));
propertyList["windchill"] = formatNotifString(propertyName["windchill"], QByteArray::number(propertiesValue["windchill"]));
//windChill(propertiesValue["tempf"], propertiesValue["vent"]);
//calculerHumidex(propertiesValue["tempf"], propertiesValue["humidity"]);
#ifdef WITH_MQTT
if (!jsonString.isEmpty())
{
debug(DEBUGMACRO, "json string : " + jsonString, DEBUG);
@@ -376,50 +431,76 @@ void Pws2mqtt::parseData(QList<std::pair<QString, QString>> queryList)
{
debug(DEBUGMACRO, "No values to send", DEBUG);
}
#endif
debug(DEBUGMACRO, "current datetime : " + QDateTime::currentDateTime().toString() + ", timer = " + timer.toString(), DEBUG);
if (priority > 3 or QDateTime::currentDateTime() > timer.addSecs(1800))
//bool changed = false;
quint8 aPriority= 0;
debug(DEBUGMACRO, "looping to fill notif", DEBUG);
QTime currentTime = QTime::currentTime();
if (currentTime.minute() == 0 or start == false)
{
bool changed = false;
timer = QDateTime::currentDateTime();
debug(DEBUGMACRO, "looping to fill notif, priority = " + QString::number(priority), DEBUG);
if (precPropertyList.size() == 0)
{
changed = true;
}
for (auto [name, value]: propertyList.asKeyValueRange())
{
if (precPropertyList.contains(name))
{
if (precPropertyList[name] != propertyList[name])
{
debug(DEBUGMACRO, "changed = true", DEBUG);
changed = true;
}
}
debug(DEBUGMACRO, "Name = " + name + ", value = " + value, DEBUG);
if (! (name == "prevision"))
{
notif += propertyList[name];
}
}
if (changed)
{
notify (notif, priorityList[priority], attachment, tag);
precPropertyList = propertyList;
}
start = true;
notif = listProperties2notify (propertyList, priority, 0);
notify (notif, priorityList[aPriority], attachment, tag);
precPropertyList = propertyList;
debug(DEBUGMACRO, "calling notify with notif = #" + notif + "#", INFO);
notif = "**Prévisions à 12/24h**\n" + propertyList["prevision"];
notify (notif, priorityList[priority], attachment, tag);
debug(DEBUGMACRO, "calling notify with notif = #" + notif + "#", DEBUG);
notify (notif, priorityList[aPriority], "", tag);
debug(DEBUGMACRO, "calling notify with notif = #" + notif + "#", INFO);
}
if (aPriority >= 3)
{
notif = "**ALERTES**\n" + listProperties2notify (propertyList,priority, 3);
precPropertyList = propertyList;
notify (notif, priorityList[aPriority], attachment, tag);
}
debug(DEBUGMACRO, "parseData: Returning", DEBUG);
}
QString listProperties2notify (QMap <QByteArray, QString> propertyList, QHash <QByteArray, quint8> priority, quint8 minAlert)
{
static QHash <QByteArray, quint8> announced = {};
QString notif = "";
for (auto [name, value]: propertyList.asKeyValueRange())
{
if (name != "prevision")
{
//if (precPropertyList.contains(name))
//{
//if (precPropertyList[name] != propertyList[name])
//{
if (minAlert == 0)
{
notif += propertyList[name];
}else if (priority[name] >= minAlert)
{
if (announced.contains(name) and priority.contains(name))
{
if (announced[name] != priority[name])
{
notif += propertyList[name];
announced[name] = priority[name];
}else
{
debug (DEBUGMACRO, name + " : déjà annoncé = " + announced[name] + " nouvelle valeur = " + priority[name], INFO);
}
}
}
//}
//}
debug(DEBUGMACRO, "Name = " + name + ", value = " + value, DEBUG);
}
}
return notif;
}
double calculerUTCI(double temperature, double humiditeRelative, double vitesseVent, double rayonnement)
{
double e = (humiditeRelative / 100.0) * 6.105 * exp((17.27 * temperature) / (237.7 + temperature));
@@ -506,154 +587,17 @@ bool compare (double value, double currentValue, double ecart)
}
}
QString formatNotifString (QString name, QString unit ,QByteArray value)
QString formatNotifString (QPair<QString, QByteArray> property ,QByteArray value)
{
QString text = "- " + name + " : " + value;
if (!unit.isEmpty())
QString text = "- " + property.first + " : " + value;
if (!property.second.isEmpty())
{
text += unit;
text += property.second;
//"- " + propertyName[name].first + " : " + value + " " + propertyName[name].second + " ";
}
return text += "\n";
}
static size_t ReadFile(void *ptr, size_t size, size_t nmemb, void *stream) {
FILE *f = (FILE *)stream;
size_t n = fread(ptr, size, nmemb, f);
return n;
}
// Callback for curl library
static size_t WriteCallback(void *contents, size_t size, size_t nmemb, std::string *output)
{
size_t total_size = size * nmemb;
output->append((char*)contents, total_size);
return total_size;
}
void notify(QString notif, QString priority, QString inputPath, QString tag)
{
CURL *curl;
CURLcode res;
std::string readBuffer;
priority = "Priority: " + priority;
debug (DEBUGMACRO, "notifying at priority " + priority + "with tag : " + tag + " - message : " + notif, DEBUG);
// Initialise libcurl
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if (curl)
{
// Définis les en-têtes pour le titre et les priorités
struct curl_slist *headers = NULL;
notif.replace("\\", "\\\\\\'"); // Échappe les apostrophes
if (!tag.isEmpty())
{
headers = curl_slist_append(headers, ("Tags: " + tag).toStdString().c_str());
}
headers = curl_slist_append(headers, "Title: Météo");
headers = curl_slist_append(headers, priority.toStdString().c_str());
headers = curl_slist_append(headers, "Markdown: yes");
// headers = curl_slist_append(headers, "Config: /etc/ntfy.client.yml");
headers = curl_slist_append(headers, "Firebase: no");
// headers = curl_slist_append(headers, "Content-Type: charset=UTF-8; text/markdown"); // Ajout de l'encodage
struct curl_slist *h = headers;
while (h) {
debug(DEBUGMACRO, "Header: " + QString(h->data), DEBUG);
h = h->next;
}
debug(DEBUGMACRO, "Notif: " + notif, DEBUG);
// Configure la requête POST
curl_easy_setopt(curl, CURLOPT_URL, "http://localhost:81/Meteo");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, notif.toUtf8().constData());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
// Exécute la requête
res = curl_easy_perform(curl);
// Vérifie les erreurs
if (res != CURLE_OK)
{
debug(DEBUGMACRO, "Erreur libcurl :" + QString(curl_easy_strerror(res)), DEBUG);
} else
{
debug(DEBUGMACRO, "Réponse du serveur: " + QString::fromStdString(readBuffer), DEBUG);
}
// Nettoie les ressources
//curl_mime_free(mime);
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
}
// Nettoie libcurl
curl_global_cleanup();
if (!inputPath.isEmpty())
{
FILE *fd = fopen(inputPath.toStdString().c_str(), "rb");
if (!fd) {
perror("Erreur lors de l'ouverture du fichier");
return;
}
// Initialise libcurl
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if (curl)
{
// Définis les en-têtes pour le titre et les priorités
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Title: Météo");
headers = curl_slist_append(headers, priority.toStdString().c_str());
// headers = curl_slist_append(headers, "Config: /etc/ntfy.client.yml");
headers = curl_slist_append(headers, "Firebase: no");
headers = curl_slist_append(headers, "Content-Type: image/png");
headers = curl_slist_append(headers, "X-Original-Size: true");
headers = curl_slist_append(headers, "X-Filename: fleche.png");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); // Configurer l'URL
curl_easy_setopt(curl, CURLOPT_URL, "localhost:81/Meteo");
// Utiliser la méthode PUT (comme `curl -T`)
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
// Lire le fichier et l'envoyer en tant que body
curl_easy_setopt(curl, CURLOPT_READFUNCTION, ReadFile);
curl_easy_setopt(curl, CURLOPT_READDATA, fd);
// Définir la taille du fichier (optionnel mais recommandé)
struct stat file_info;
fstat(fileno(fd), &file_info);
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_info.st_size);
// Exécuter la requête
res = curl_easy_perform(curl);
// Vérifie les erreurs
if (res != CURLE_OK)
{
debug(DEBUGMACRO, "Erreur libcurl :" + QString(curl_easy_strerror(res)), DEBUG);
} else
{
debug(DEBUGMACRO, "Notification envoyée avec succès", DEBUG);
}
// Nettoyer
fclose(fd);
curl_easy_cleanup(curl);
}
// Nettoie libcurl
curl_global_cleanup();
}
}
void rotateAndSaveImage(const QString &inputPath, const QString &outputPath, qreal angle)
{
QImage image(inputPath);
+4 -2
View File
@@ -5,6 +5,7 @@
#include <QObject>
#include <QtMqtt>
#include <QtMqtt/QMqttClient>
//#include <cstdint>
#define RED "\e[31m"
#define GREEN "\e[32m"
@@ -53,9 +54,8 @@ class Pws2mqtt : public QObject
double fahrenheitToCelsius(double fahrenheit);
double tohPa(double value);
bool compare (double value=0, double testValue=0, double ecart = 0.5);
QString formatNotifString (QString name, QString unit, QByteArray value="");
QString formatNotifString (QPair<QString, QByteArray> property ,QByteArray value);
double mphTokmh (double value);
void notify (QString notif, QString priority = "low", QString inputPath = "", QString tag = "");
quint8 setPriority (quint8 currentPriority, quint8 newPriority);
QString previsionMeteo(double currentPressure, double variation3h, quint8 &priority);
QString pressureVariation(double currentPressure, quint8 &priority);
@@ -63,4 +63,6 @@ QString getPluviosite(double value, quint8 &priority);
void rotateAndSaveImage(const QString &inputPath, const QString &outputPath, qreal angle=0);
double windChill(double airT, double vent);
double calculerHumidex(double temperature, double humiditeRelative);
void notify (QString notif, QString priority = "low", QString inputPath = "", QString tag = "");
QString listProperties2notify (QMap <QByteArray, QString> propertyList, QHash <QByteArray, quint8> priority, quint8 minAlert = 0);
+100 -127
View File
@@ -5,174 +5,147 @@
#include <QRegularExpression>
UtciCalculator::UtciCalculator(QObject *parent)
: QObject(parent)
: QObject(parent)
{
}
/*// Loads coefficients from a simple text file containing one coefficient per line or tab-separated.
// The expected file is the ESM_3 coefficients table exported to a plain text file where the coefficients
// appear in the same order as in the official table (210 coefficients).
bool UtciCalculator::loadCoefficientsFromFile(const QString &path)
{
QFile f(path);
if (!f.open(QIODevice::ReadOnly | QIODevice::Text))
return false;
QTextStream in(&f);
QVector<double> coeffs;
coeffs.reserve(300);
while (!in.atEnd()) {
QString line = in.readLine().trimmed();
if (line.isEmpty()) continue;
// Allow lines with comments or 'term coefficient' headings:
// We try to extract numbers from the line.
QStringList parts = line.split(QRegularExpression("[\\s,\\t]+"), Qt::SkipEmptyParts);
for (const QString &p : parts) {
bool ok = false;
double val = p.toDouble(&ok);
if (ok) coeffs.append(val);
}
}
if (coeffs.isEmpty()) return false;
m_coeffs = coeffs;
return true;
}
*/
// Magnus formula to estimate saturation vapour pressure (hPa) then return pa in kPa
double UtciCalculator::vapourPressureFromRH(double Ta, double rh)
{
// Magnus-Tetens approximation for saturation vapour pressure (hPa)
// valid roughly for -45C..+60C
// constants for water over liquid
double a = 17.27;
double b = 237.7; // °C
double es = 6.112 * qExp((a * Ta) / (Ta + b));
double ea = es * (rh / 100.0);
return ea / 10.0; // hPa -> kPa
// Magnus-Tetens approximation for saturation vapour pressure (hPa)
// valid roughly for -45C..+60C
// constants for water over liquid
double a = 17.27;
double b = 237.7; // °C
double es = 6.112 * qExp((a * Ta) / (Ta + b));
double ea = es * (rh / 100.0);
return ea / 10.0; // hPa -> kPa
}
double UtciCalculator::computeUTCI(double Ta, double va, double Tr, double rh) const
{
double pa = vapourPressureFromRH(Ta, rh);
double tm = Tr - Ta;
double offset = evalOffset(Ta, va, tm, pa);
return Ta + offset;
double pa = vapourPressureFromRH(Ta, rh);
double tm = Tr - Ta;
double offset = evalOffset(Ta, va, tm, pa);
return Ta + offset;
}
double UtciCalculator::evalOffset(double Ta, double va, double tm, double pa) const
{
if (m_coeffs.size() < 210)
return 0.0;
if (m_coeffs.size() < 210)
return 0.0;
// Pré-calcul des puissances
double Ta2 = Ta*Ta, Ta3 = Ta2*Ta, Ta4 = Ta3*Ta, Ta5 = Ta4*Ta, Ta6 = Ta5*Ta;
double va2 = va*va, va3 = va2*va, va4 = va3*va, va5 = va4*va, va6 = va5*va;
double tm2 = tm*tm, tm3 = tm2*tm, tm4 = tm3*tm, tm5 = tm4*tm, tm6 = tm5*tm;
double pa2 = pa*pa, pa3 = pa2*pa, pa4 = pa3*pa, pa5 = pa4*pa, pa6 = pa5*pa;
// Pré-calcul des puissances
double Ta2 = Ta*Ta, Ta3 = Ta2*Ta, Ta4 = Ta3*Ta, Ta5 = Ta4*Ta, Ta6 = Ta5*Ta;
double va2 = va*va, va3 = va2*va, va4 = va3*va, va5 = va4*va, va6 = va5*va;
double tm2 = tm*tm, tm3 = tm2*tm, tm4 = tm3*tm, tm5 = tm4*tm, tm6 = tm5*tm;
double pa2 = pa*pa, pa3 = pa2*pa, pa4 = pa3*pa, pa5 = pa4*pa, pa6 = pa5*pa;
QVector<double> terms(210, 0.0);
QVector<double> terms(210, 0.0);
// Construire les termes dans le même ordre que les coefficients ESM_3
terms[0] = 1.0; // constante
terms[1] = Ta;
terms[2] = Ta2;
terms[3] = Ta3;
terms[4] = Ta4;
terms[5] = Ta5;
terms[6] = Ta6;
// Construire les termes dans le même ordre que les coefficients ESM_3
terms[0] = 1.0; // constante
terms[1] = Ta;
terms[2] = Ta2;
terms[3] = Ta3;
terms[4] = Ta4;
terms[5] = Ta5;
terms[6] = Ta6;
terms[7] = va;
terms[8] = Ta*va;
terms[9] = Ta2*va;
terms[10] = Ta3*va;
terms[11] = Ta4*va;
terms[12] = Ta5*va;
terms[7] = va;
terms[8] = Ta*va;
terms[9] = Ta2*va;
terms[10] = Ta3*va;
terms[11] = Ta4*va;
terms[12] = Ta5*va;
terms[13] = va2;
terms[14] = Ta*va2;
terms[15] = Ta2*va2;
terms[16] = Ta3*va2;
terms[17] = Ta4*va2;
terms[13] = va2;
terms[14] = Ta*va2;
terms[15] = Ta2*va2;
terms[16] = Ta3*va2;
terms[17] = Ta4*va2;
terms[18] = va3;
terms[19] = Ta*va3;
terms[20] = Ta2*va3;
terms[21] = Ta3*va3;
terms[18] = va3;
terms[19] = Ta*va3;
terms[20] = Ta2*va3;
terms[21] = Ta3*va3;
terms[22] = va4;
terms[23] = Ta*va4;
terms[24] = Ta2*va4;
terms[22] = va4;
terms[23] = Ta*va4;
terms[24] = Ta2*va4;
terms[25] = va5;
terms[26] = Ta*va5;
terms[25] = va5;
terms[26] = Ta*va5;
terms[27] = va6;
terms[27] = va6;
terms[28] = tm;
terms[29] = Ta*tm;
terms[30] = Ta2*tm;
terms[31] = Ta3*tm;
terms[32] = Ta4*tm;
terms[33] = Ta5*tm;
terms[34] = Ta6*tm;
terms[28] = tm;
terms[29] = Ta*tm;
terms[30] = Ta2*tm;
terms[31] = Ta3*tm;
terms[32] = Ta4*tm;
terms[33] = Ta5*tm;
terms[34] = Ta6*tm;
terms[35] = va*tm;
terms[36] = Ta*va*tm;
terms[37] = Ta2*va*tm;
terms[38] = Ta3*va*tm;
terms[39] = Ta4*va*tm;
terms[35] = va*tm;
terms[36] = Ta*va*tm;
terms[37] = Ta2*va*tm;
terms[38] = Ta3*va*tm;
terms[39] = Ta4*va*tm;
terms[40] = va2*tm;
terms[41] = Ta*va2*tm;
terms[42] = Ta2*va2*tm;
terms[43] = Ta3*va2*tm;
terms[40] = va2*tm;
terms[41] = Ta*va2*tm;
terms[42] = Ta2*va2*tm;
terms[43] = Ta3*va2*tm;
terms[44] = va3*tm;
terms[45] = Ta*va3*tm;
terms[46] = Ta2*va3*tm;
terms[44] = va3*tm;
terms[45] = Ta*va3*tm;
terms[46] = Ta2*va3*tm;
terms[47] = va4*tm;
terms[48] = Ta*va4*tm;
terms[47] = va4*tm;
terms[48] = Ta*va4*tm;
terms[49] = va5*tm;
terms[49] = va5*tm;
// tm^2 à tm^6
terms[50] = tm2; terms[51] = Ta*tm2; terms[52] = Ta2*tm2; terms[53] = Ta3*tm2; terms[54] = Ta4*tm2;
terms[55] = va*tm2; terms[56] = Ta*va*tm2; terms[57] = Ta2*va*tm2; terms[58] = Ta3*va*tm2;
terms[59] = va2*tm2; terms[60] = Ta*va2*tm2; terms[61] = Ta2*va2*tm2;
terms[62] = va3*tm2;
terms[63] = tm3; terms[64] = Ta*tm3; terms[65] = Ta2*tm3;
terms[66] = va*tm3; terms[67] = Ta*va*tm3; terms[68] = va2*tm3;
terms[69] = tm4; terms[70] = Ta*tm4; terms[71] = va*tm4;
terms[72] = tm5;
terms[73] = tm6;
// tm^2 à tm^6
terms[50] = tm2; terms[51] = Ta*tm2; terms[52] = Ta2*tm2; terms[53] = Ta3*tm2; terms[54] = Ta4*tm2;
terms[55] = va*tm2; terms[56] = Ta*va*tm2; terms[57] = Ta2*va*tm2; terms[58] = Ta3*va*tm2;
terms[59] = va2*tm2; terms[60] = Ta*va2*tm2; terms[61] = Ta2*va2*tm2;
terms[62] = va3*tm2;
terms[63] = tm3; terms[64] = Ta*tm3; terms[65] = Ta2*tm3;
terms[66] = va*tm3; terms[67] = Ta*va*tm3; terms[68] = va2*tm3;
terms[69] = tm4; terms[70] = Ta*tm4; terms[71] = va*tm4;
terms[72] = tm5;
terms[73] = tm6;
// pa et combinaisons
terms[74] = pa; terms[75] = Ta*pa; terms[76] = Ta2*pa; terms[77] = Ta3*pa; terms[78] = Ta4*pa; terms[79] = Ta5*pa;
terms[80] = va*pa; terms[81] = Ta*va*pa; terms[82] = Ta2*va*pa; terms[83] = Ta3*va*pa;
terms[84] = va2*pa; terms[85] = Ta*va2*pa; terms[86] = Ta2*va2*pa;
terms[87] = va3*pa; terms[88] = Ta*va3*pa;
terms[89] = va4*pa;
// pa et combinaisons
terms[74] = pa; terms[75] = Ta*pa; terms[76] = Ta2*pa; terms[77] = Ta3*pa; terms[78] = Ta4*pa; terms[79] = Ta5*pa;
terms[80] = va*pa; terms[81] = Ta*va*pa; terms[82] = Ta2*va*pa; terms[83] = Ta3*va*pa;
terms[84] = va2*pa; terms[85] = Ta*va2*pa; terms[86] = Ta2*va2*pa;
terms[87] = va3*pa; terms[88] = Ta*va3*pa;
terms[89] = va4*pa;
terms[90] = pa2; terms[91] = Ta*pa2; terms[92] = Ta2*pa2;
terms[90] = pa2; terms[91] = Ta*pa2; terms[92] = Ta2*pa2;
// Remplir le reste avec 0.0 pour simplifier (les 210 coefficients réels peuvent être affectés directement)
for (int i = 93; i < 210; ++i) terms[i] = 0.0;
// Remplir le reste avec 0.0 pour simplifier (les 210 coefficients réels peuvent être affectés directement)
for (int i = 93; i < 210; ++i) terms[i] = 0.0;
// Calcul de l'offset
double offset = 0.0;
for (int i = 0; i < 210; ++i)
offset += m_coeffs[i] * terms[i];
// Calcul de l'offset
double offset = 0.0;
for (int i = 0; i < 210; ++i)
offset += m_coeffs[i] * terms[i];
return offset;
return offset;
}
void UtciCalculator::initCoefficients()
{
// Coefficients ESM_3 (exemple simplifié, à remplacer par la liste complète 210 valeurs)
m_coeffs = {
6.07562052E-01, -2.27712343E-02, 8.06470249E-04, -1.54271372E-04, -3.24651735E-06, 7.32602852E-08, 1.35959073E-09, -2.25836520E+00, 8.80326035E-02, 2.16844454E-03, -1.53347087E-05, -5.72983704E-07, -2.55090145E-09, -7.51269505E-01, -4.08350271E-03, -5.21670675E-05, 1.94544667E-06, 1.14099531E-08, 1.58137256E-01, -6.57263143E-05, 2.22697524E-07, -4.16117031E-08, -1.27762753E-02, 9.66891875E-06, 2.52785852E-09, 4.56306672E-04, -1.74202546E-07, -5.91491269E-06, 3.98374029E-01, 1.83945314E-04, -1.73754510E-04, -7.60781159E-07, 3.77830287E-08, 5.43079673E-10, -2.00518269E-02, 8.92859837E-04, 3.45433048E-06, -3.77925774E-07, -1.69699377E-09, 1.69992415E-04, -4.99204314E-05, 2.47417178E-07, 1.07596466E-08, 8.49242932E-05, 1.35191328E-06, -6.21531254E-09, -4.99410301E-06, -1.89489258E-08, 8.15300114E-08, 7.55043090E-04, -3.69476348E-02, 1.62325322E-03, -3.14279680E-05, 2.59835559E-06, -4.77136523E-08, 8.64203390E-03, -6.87405181E-04, -9.13863872E-06, 5.15916806E-07, -3.59217476E-05, 3.28696511E-05, -7.10542454E-07, -1.24382300E-05, -7.38584400E-09, 2.20609296E-07, -7.32469180E-04, -1.87381964E-05, 4.80925239E-06, -8.75492040E-08, 2.77862930E-05, -5.06004592E-06, 1.14325367E-07, 2.53016723E-06, -1.72857035E-08, -3.95079398E-08, -3.59413173E-07, 7.04388046E-07, -1.89309167E-08, -4.79768731E-07, 7.96079978E-09, 1.62897058E-09, 3.94367674E-08, -1.18566247E-09, 3.34678041E-10, -1.15606447E-10, -2.80626406E+00, 5.48712484E-01, -3.99428410E-03, -9.54009191E-04, 1.93090978E-05, -3.08806365E-01, 1.16952364E-02, 4.95271903E-04, -1.90710882E-05, 2.10787756E-03, -6.98445738E-04, 2.30109073E-05, 4.17856590E-04, -1.27043871E-05, -3.04620472E-06, -5.65095215E-05, -4.52166564E-07, 2.46688878E-08, 2.42674348E-10, 1.54547250E-04, 5.24110970E-06, -8.75874982E-08, -1.50743064E-09, -1.56236307E-05, -1.33895614E-07, 2.49709824E-09, 6.51711721E-07, 1.94960053E-09, -1.00361113E-08, -1.21206673E-05, -2.18203660E-07, 7.51269482E-09, 9.79063848E-11, 1.25006734E-06, -1.81584736E-09, -3.52197671E-10, -3.36514630E-08, 1.35908359E-10, 4.17032620E-10, -1.30369025E-09, 4.13908461E-10, 9.22652254E-12, -5.08220384E-09, -2.24730961E-11, 1.17139133E-10, 6.62154879E-10, 4.03863260E-13, 1.95087203E-12, -4.73602469E-12, 5.12733497E+00, -3.12788561E-01, -1.96701861E-02, 9.99690870E-04, 9.51738512E-06, -4.66426341E-07, 5.48050612E-01, -3.30552823E-03, -1.64119440E-03, -5.16670694E-06, 9.52692432E-07, -4.29223622E-02, 5.00845667E-03, 1.00601257E-06, -1.81748644E-06, -1.25813502E-03, -1.79330391E-04, 2.34994441E-06, 1.29735808E-04, 1.29064870E-06, -2.28558686E-06, 5.14507424E-02, -4.32510997E-03, 8.99281156E-05, -7.14663943E-07, -2.66016305E-04, 2.63789586E-04, -7.01199003E-06, -1.06823306E-04, 3.61341136E-06, 2.29748967E-07, 3.04788893E-04, -6.42070836E-05, 1.16257971E-06, 7.68023384E-06, -5.47446896E-07, -3.59937910E-08, -4.36497725E-06, 1.68737969E-07, 2.67489271E-08, 3.23926897E-09, -3.53874123E-02, -2.21201190E-01, 1.55126038E-02, -2.63917279E-04, 4.53433455E-02, -4.32943862E-03, 1.45389826E-04, 2.17508610E-04, -6.66724702E-05, 3.33217140E-05, -2.26921615E-03, 3.80261982E-04, -5.45314314E-09, -7.96355448E-04, 2.53458034E-05, -6.31223658E-06, 3.02122035E-04, -4.77403547E-06, 1.73825715E-06, -4.09087898E-07, 6.14155345E-01, -6.16755931E-02, 1.33374846E-03, 3.55375387E-03, -5.13027851E-04, 1.02449757E-04, -1.48526421E-03, -4.11469183E-05, -6.80434415E-06, -9.77675906E-06, 8.82773108E-02, -3.01859306E-03, 1.04452989E-03, 2.47090539E-04, 1.48348065E-03
};
// Coefficients ESM_3 (exemple simplifié, à remplacer par la liste complète 210 valeurs)
m_coeffs = {
6.07562052E-01, -2.27712343E-02, 8.06470249E-04, -1.54271372E-04, -3.24651735E-06, 7.32602852E-08, 1.35959073E-09, -2.25836520E+00, 8.80326035E-02, 2.16844454E-03, -1.53347087E-05, -5.72983704E-07, -2.55090145E-09, -7.51269505E-01, -4.08350271E-03, -5.21670675E-05, 1.94544667E-06, 1.14099531E-08, 1.58137256E-01, -6.57263143E-05, 2.22697524E-07, -4.16117031E-08, -1.27762753E-02, 9.66891875E-06, 2.52785852E-09, 4.56306672E-04, -1.74202546E-07, -5.91491269E-06, 3.98374029E-01, 1.83945314E-04, -1.73754510E-04, -7.60781159E-07, 3.77830287E-08, 5.43079673E-10, -2.00518269E-02, 8.92859837E-04, 3.45433048E-06, -3.77925774E-07, -1.69699377E-09, 1.69992415E-04, -4.99204314E-05, 2.47417178E-07, 1.07596466E-08, 8.49242932E-05, 1.35191328E-06, -6.21531254E-09, -4.99410301E-06, -1.89489258E-08, 8.15300114E-08, 7.55043090E-04, -3.69476348E-02, 1.62325322E-03, -3.14279680E-05, 2.59835559E-06, -4.77136523E-08, 8.64203390E-03, -6.87405181E-04, -9.13863872E-06, 5.15916806E-07, -3.59217476E-05, 3.28696511E-05, -7.10542454E-07, -1.24382300E-05, -7.38584400E-09, 2.20609296E-07, -7.32469180E-04, -1.87381964E-05, 4.80925239E-06, -8.75492040E-08, 2.77862930E-05, -5.06004592E-06, 1.14325367E-07, 2.53016723E-06, -1.72857035E-08, -3.95079398E-08, -3.59413173E-07, 7.04388046E-07, -1.89309167E-08, -4.79768731E-07, 7.96079978E-09, 1.62897058E-09, 3.94367674E-08, -1.18566247E-09, 3.34678041E-10, -1.15606447E-10, -2.80626406E+00, 5.48712484E-01, -3.99428410E-03, -9.54009191E-04, 1.93090978E-05, -3.08806365E-01, 1.16952364E-02, 4.95271903E-04, -1.90710882E-05, 2.10787756E-03, -6.98445738E-04, 2.30109073E-05, 4.17856590E-04, -1.27043871E-05, -3.04620472E-06, -5.65095215E-05, -4.52166564E-07, 2.46688878E-08, 2.42674348E-10, 1.54547250E-04, 5.24110970E-06, -8.75874982E-08, -1.50743064E-09, -1.56236307E-05, -1.33895614E-07, 2.49709824E-09, 6.51711721E-07, 1.94960053E-09, -1.00361113E-08, -1.21206673E-05, -2.18203660E-07, 7.51269482E-09, 9.79063848E-11, 1.25006734E-06, -1.81584736E-09, -3.52197671E-10, -3.36514630E-08, 1.35908359E-10, 4.17032620E-10, -1.30369025E-09, 4.13908461E-10, 9.22652254E-12, -5.08220384E-09, -2.24730961E-11, 1.17139133E-10, 6.62154879E-10, 4.03863260E-13, 1.95087203E-12, -4.73602469E-12, 5.12733497E+00, -3.12788561E-01, -1.96701861E-02, 9.99690870E-04, 9.51738512E-06, -4.66426341E-07, 5.48050612E-01, -3.30552823E-03, -1.64119440E-03, -5.16670694E-06, 9.52692432E-07, -4.29223622E-02, 5.00845667E-03, 1.00601257E-06, -1.81748644E-06, -1.25813502E-03, -1.79330391E-04, 2.34994441E-06, 1.29735808E-04, 1.29064870E-06, -2.28558686E-06, 5.14507424E-02, -4.32510997E-03, 8.99281156E-05, -7.14663943E-07, -2.66016305E-04, 2.63789586E-04, -7.01199003E-06, -1.06823306E-04, 3.61341136E-06, 2.29748967E-07, 3.04788893E-04, -6.42070836E-05, 1.16257971E-06, 7.68023384E-06, -5.47446896E-07, -3.59937910E-08, -4.36497725E-06, 1.68737969E-07, 2.67489271E-08, 3.23926897E-09, -3.53874123E-02, -2.21201190E-01, 1.55126038E-02, -2.63917279E-04, 4.53433455E-02, -4.32943862E-03, 1.45389826E-04, 2.17508610E-04, -6.66724702E-05, 3.33217140E-05, -2.26921615E-03, 3.80261982E-04, -5.45314314E-09, -7.96355448E-04, 2.53458034E-05, -6.31223658E-06, 3.02122035E-04, -4.77403547E-06, 1.73825715E-06, -4.09087898E-07, 6.14155345E-01, -6.16755931E-02, 1.33374846E-03, 3.55375387E-03, -5.13027851E-04, 1.02449757E-04, -1.48526421E-03, -4.11469183E-05, -6.80434415E-06, -9.77675906E-06, 8.82773108E-02, -3.01859306E-03, 1.04452989E-03, 2.47090539E-04, 1.48348065E-03
};
}