added snow, rain and blackIve prevision

This commit is contained in:
2025-10-17 19:22:05 +02:00
parent 28cf84c0c5
commit a8819971d7
4 changed files with 302 additions and 56 deletions

252
barometertrend.h Normal file
View File

@@ -0,0 +1,252 @@
#pragma once
#include <QObject>
#include <QVector>
#include <QDateTime>
#include <QtMath>
struct ForecastResult
{
QString message;
int urgency; // 0-5
QString colorCode; // "vert", "jaune", ...
bool snowRisk;
bool rainRisk;
bool stormRisk;
bool blackIce;
};
class BarometerTrend : public QObject
{
Q_OBJECT
public:
explicit BarometerTrend(QObject *parent = nullptr)
: QObject(parent)
{}
void addPressure(double pressure_hPa)
{
// 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();
}
}
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];
return sum / n;
}
// Variation de pression sur les dernières 3h
double deltaPressure3h() const
{
if (m_values.size() < 2)
{
return 0.0;
}
QDateTime now = QDateTime::currentDateTime();
QDateTime target = now.addSecs(-3 * 3600);
// Cherche la valeur la plus proche dil y a 3 heures
int idx = -1;
for (int i = 0; i < m_timestamps.size(); ++i)
{
if (m_timestamps[i] >= target)
{
idx = i;
break;
}
}
if (idx == -1)
{
idx = 0; // Pas assez vieux, on prend la plus ancienne
}
double p_now = smoothedPressure();
double p_past = m_values[idx];
return p_now - p_past;
}
ForecastResult forecast(double temperatureC, double humidityPercent) const
{
ForecastResult r;
double p = currentPressure();
double d = deltaPressure3h();
r.snowRisk = false;
r.rainRisk = false;
r.stormRisk = false;
r.blackIce = false;
// Logique combinée pression / tendance
if (p >= 1020 && d >= +3)
{
r.message = "Très beau temps durable";
r.urgency = 0;
r.colorCode = "sunny";
}else if (p >= 1020 && d >= +1)
{
r.message = "Beau temps durable";
r.urgency = 0;
r.colorCode = "sunny";
}else if (p >= 1020 && d < -3)
{
r.message = "Beau, mais rapide dégradation";
r.urgency = 4;
r.colorCode = "sun_behind_large_cloud";
}else if (p >= 1020 && d < -1)
{
r.message = "Beau, mais possible dégradation";
r.urgency = 1;
r.colorCode = "sun_behind_small_cloud";
}else if (p >= 1020 && d < 0.5)
{
r.message = "Beau temps stable";
r.urgency = 0;
r.colorCode = "sunny";
}else if (p >= 1010 && d >= +3)
{
r.message = "Rapide amélioration du temps";
r.urgency = 4;
r.colorCode = "sun_behind_small_cloud";
}else if (p >= 1010 && d >= +1)
{
r.message = "Amélioration du temps";
r.urgency = 0;
r.colorCode = "sun_behind_large_cloud";
}else if (p >= 1010 && d <= -3)
{
r.message = "Fort risque de pluie ou vent";
r.urgency = 4;
r.colorCode = "sun_behind_rain_cloud";
}else if (p >= 1010 && d <= -1)
{
r.message = "Risque de pluie ou vent";
r.urgency = 2;
r.colorCode = "sun_behind_rain_cloud";
}else if (p >= 1010 && d <= 0.5)
{
r.message = "Nuageux avec des éclaircies";
r.urgency = 2;
r.colorCode = "sun_behind_large_cloud";
}else if (p >= 1000 && d >= +3)
{
r.message = "Variable, amélioration rapide";
r.urgency = 4;
r.colorCode = "sun_behind_large_cloud";
}else if (p >= 1000 && d >= +1)
{
r.message = "Variable, tendance au beau";
r.urgency = 0;
r.colorCode = "sun_behind_large_cloud";
}else if (p >= 1000 && d <= -3)
{
r.message = "Pluie ou perturbation, dégradation rapide";
r.urgency = 4;
r.colorCode = "cloud_with_rain";
}else if (p >= 1000 && d <= -1)
{
r.message = "Pluie ou perturbation";
r.urgency = 2;
r.colorCode = "cloud_with_rain";
}else if (p < 990 && d <= -3)
{
r.message = "Tempête ou orage";
r.urgency = 5;
r.colorCode = "cloud_with_lightning";
}else if (p < 1000 && d >= +3)
{
r.message = "Accalmie temporaire, amélioration rapide";
r.urgency = 1;
r.colorCode = "sun_behind_rain_cloud";
}else if (p < 1000 && d >= +1)
{
r.message = "Accalmie temporaire";
r.urgency = 1;
r.colorCode = "sun_behind_rain_cloud";
}else if (p < 1000 && d <= -1)
{
r.message = "Mauvais temps durable";
r.urgency = 4;
r.colorCode = "cloud_with_rain";
}
if (qAbs(d) < 0.5)
{
r.message = "Stable, pas de changement significatif";
r.urgency = 0;
}
// Risque de neige
if (p < 1000 && d < -1 && temperatureC <= 1.0 && humidityPercent > 80.0)
{
r.snowRisk = true;
r.message += " — Risque de neige";
r.urgency = qMax(r.urgency, 3);
r.colorCode += "snowflake,";
}
// Risque de pluie
else if (p < 1010 && d < -1 && temperatureC > 1.0 && humidityPercent > 70.0)
{
r.rainRisk = true;
r.message += " — Risque de pluie";
r.urgency = qMax(r.urgency, 2);
r.colorCode += "cloud_with_rain,";
}
// Risque dorage
if (p < 995 && d < -3 && temperatureC > 20.0 && humidityPercent > 70.0)
{
r.stormRisk = true;
r.message += " ⚡ Risque dorage";
r.urgency = qMax(r.urgency, 4);
r.colorCode += "cloud_with_lightning,";
}
if (temperatureC <= 0.5 && humidityPercent >= 85.0) {
// conditions classiques de gel
if (d >= -1 && d <= +1)
{
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";
r.colorCode += "ice_cube,";
r.urgency = qMax(r.urgency, 4);
}
return r;
}
private:
QVector<double> m_values;
QVector<QDateTime> m_timestamps;
};

View File

@@ -25,6 +25,7 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
HEADERS += \
barometertrend.h \
httpserver.h \
mqtt.h \
pws2mqtt.h \

View File

@@ -1,6 +1,8 @@
#include "pws2mqtt.h"
#include "pws2mqtt.h"
#include "barometertrend.h"
#include "mqtt.h"
//#include "httpserver.h"
#include <cstring>
#include <unistd.h>
#include <QtGlobal>
#include <iostream>
@@ -21,6 +23,9 @@ extern MqttClient *mqttClient;
extern Pws2mqtt *pws2mqtt;
extern QHttpServer *httpServer;
UtciCalculator calc;
BarometerTrend baro;
using namespace std;
QStringList previsionList
{
@@ -153,6 +158,7 @@ void Pws2mqtt::parseData(QList<std::pair<QString, QString>> queryList)
QString notif = "";
QStringList priorityList {"", "min", "low", "default", "High", "urgent"};
QString attachment = "";
QString tag = "";
quint8 priority = 2;
double propertyValue = 0;
bool propertyFlag = false;
@@ -216,19 +222,6 @@ void Pws2mqtt::parseData(QList<std::pair<QString, QString>> queryList)
propertyList[name] = formatNotifString(propertyName[name].first, propertyName[name].second, QByteArray::number(propertyValue));
propertiesValue[name] = propertyValue;
}
/*}else if (name == "windchillf")
{
static QDateTime timeWindchill = QDateTime::currentDateTime().addSecs(-600);
propertyValue = round(fahrenheitToCelsius(value.toFloat()));
debug (DEBUGMACRO, name + " : " + QByteArray::number(propertyValue), DEBUG);
if (compare (propertiesValue[name], propertyValue, 1) and timeWindchill < QDateTime::currentDateTime())
{
//notif += formatNotifString (propertyName[name].first, propertyName[name].second , QByteArray::number(qPow(propertyValue, 1.0)));
//debug (DEBUGMACRO, "Notif = #" + notif + "#", DEBUG);
timeWindchill = timeWindchill.currentDateTime().addSecs(300);
propertyList[name] = formatNotifString(propertyName[name].first, propertyName[name].second, QByteArray::number(propertyValue));
propertiesValue[name] = propertyValue;
}*/
}else if (name == "winddir")
{
propertyValue = value.toFloat();
@@ -270,6 +263,7 @@ void Pws2mqtt::parseData(QList<std::pair<QString, QString>> queryList)
attachment = this->outputPath;
}
debug (DEBUGMACRO, "priority = " + QString::number(priority), DEBUG);
}else if (name == "rainin")
{
static double ecart;
@@ -291,6 +285,7 @@ void Pws2mqtt::parseData(QList<std::pair<QString, QString>> queryList)
propertyList[name] = formatNotifString(pluviosite + " : ", propertyName[name].second, QByteArray::number(propertyValue));
propertiesValue[name] = propertyValue;
}
debug (DEBUGMACRO, "priority = " + QString::number(priority), DEBUG);
}else if (name == "dailyrainin")
{
static double ecart;
@@ -310,38 +305,33 @@ void Pws2mqtt::parseData(QList<std::pair<QString, QString>> queryList)
propertyList[name] = formatNotifString(propertyName[name].first, propertyName[name].second, QByteArray::number(propertyValue));
propertiesValue[name] = propertyValue;
}
debug (DEBUGMACRO, "priority = " + QString::number(priority), DEBUG);
}else if (name == "baromin")
{
//static QDateTime timePrevision = QDateTime::currentDateTime().addSecs(-1000);
propertyValue = tohPa(pair.second.toFloat());
propertyValue = round(tohPa(pair.second.toFloat()) * 100) / 100;
debug (DEBUGMACRO, "Barometre en hPa : " + QByteArray::number(propertyValue), DEBUG);
if (compare (propertiesValue[name], propertyValue, 0.5))
{
//notif += formatNotifString (propertyName[name].first, propertyName[name].second , QByteArray::number(propertyValue));
//debug (DEBUGMACRO, "Notif = #" + notif + "#", DEBUG);
baro.addPressure(propertyValue);
propertyList[name] = formatNotifString(propertyName[name].first, "", QByteArray::number(propertyValue));
propertiesValue[name] = propertyValue;
}
static QString prevision;
quint8 prevPriority = 0;
QString ret = pressureVariation(propertyValue, prevPriority);
if (!ret.isEmpty())
{
debug (DEBUGMACRO, "baromin ret not empty : " + ret, DEBUG);
QString newPrevision = ret;
priority = setPriority(priority, prevPriority);
auto ret = baro.forecast(propertiesValue["tempf"], propertiesValue["humidity"]);
QString newPrevision = ret.message;
if (prevision != newPrevision)
{
prevision = newPrevision;
propertyList["prevision"] = "- " + prevision + " \n";
priority = setPriority(priority, ret.urgency);
tag += ret.colorCode;
}
}
debug (DEBUGMACRO, "priority = " + QString::number(priority), DEBUG);
}else if (name == "UV")
{
static QDateTime timeUV = QDateTime::currentDateTime().addSecs(-600);
propertyValue = pair.second.toFloat();
propertyValue = pair.second.toUInt();
debug (DEBUGMACRO, name + " : " + QByteArray::number(propertyValue), DEBUG);
if (compare (propertiesValue[name], propertyValue, 1) and timeUV < QDateTime::currentDateTime())
@@ -356,6 +346,8 @@ void Pws2mqtt::parseData(QList<std::pair<QString, QString>> queryList)
propertiesValue[name] = propertyValue;
debug (DEBUGMACRO, "Notif = #" + notif + "#", DEBUG);
}
debug (DEBUGMACRO, "priority = " + QString::number(priority), DEBUG);
}else if (name == "solarradiation")
{
propertiesValue[name] = round(pair.second.toFloat()*100/100);
@@ -364,8 +356,8 @@ void Pws2mqtt::parseData(QList<std::pair<QString, QString>> queryList)
}
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"]));
windChill(propertiesValue["tempf"], propertiesValue["vent"]);
calculerHumidex(propertiesValue["tempf"], propertiesValue["humidity"]);
//windChill(propertiesValue["tempf"], propertiesValue["vent"]);
//calculerHumidex(propertiesValue["tempf"], propertiesValue["humidity"]);
if (!jsonString.isEmpty())
{
@@ -406,7 +398,7 @@ void Pws2mqtt::parseData(QList<std::pair<QString, QString>> queryList)
debug(DEBUGMACRO, "calling notify with notif = #" + notif + "#", DEBUG);
if (changed)
{
notify (notif, priorityList[priority], attachment);
notify (notif, priorityList[priority], attachment, tag);
precPropertyList = propertyList;
}
}
@@ -434,7 +426,7 @@ double calculerUTCI(double temperature, double humiditeRelative, double vitesseV
return round(utci * 100) / 100;
}
double windChill(double airT, double vent)
/*double windChill(double airT, double vent)
{
double w = 0;
@@ -447,9 +439,9 @@ double windChill(double airT, double vent)
debug(DEBUGMACRO, "windChill = " + QString::number(w), DEBUG);
return w;
}
}
}*/
double calculerHumidex(double temperature, double humiditeRelative)
/*double calculerHumidex(double temperature, double humiditeRelative)
{
// Calcul de la température du point de rosée (T_rosée)
double T_rosee = (243.04 * (log(humiditeRelative / 100.0) + (17.625 * temperature) / (243.04 + temperature))) / (17.625 - (log(humiditeRelative / 100.0) + (17.625 * temperature) / (243.04 + temperature)));
@@ -459,7 +451,7 @@ double calculerHumidex(double temperature, double humiditeRelative)
debug(DEBUGMACRO, "humidex = " + QString::number(H), DEBUG);
return H;
}
}*/
QString getPluviosite(double value, quint8 &priority)
{
@@ -514,9 +506,9 @@ QString previsionMeteo(double currentPressure, double variation3h, quint8 &prior
} else if (currentPressure > 1010.0 && currentPressure <= 1020.0)
{
return "Éclaircies" + variation;
} else if (currentPressure > 1000.0 && currentPressure <= 1010.0)
} else if (currentPressure > 1000.0 && currentPressure < 1009.0)
{
priority = 4;
priority = 3;
return "Temps variable, risque de pluie légère" + variation;
} else if (currentPressure >=990 && currentPressure <= 1000.0)
{
@@ -530,7 +522,7 @@ QString previsionMeteo(double currentPressure, double variation3h, quint8 &prior
return variation;
}
QString pressureVariation(double currentPressure, quint8 &priority)
/*QString pressureVariation(double currentPressure, quint8 &priority)
{
const int NB_MESURES_3H = 360; // 3h × 120 mesures/heure (1 mesure toutes les 30s)
static QVector<double> historiquePressions;
@@ -570,7 +562,7 @@ QString pressureVariation(double currentPressure, quint8 &priority)
}
debug(DEBUGMACRO, "ending pressureVariation no result", DEBUG);
return "";
}
}*/
quint8 setPriority (quint8 currentPriority, quint8 newPriority)
{
@@ -631,7 +623,7 @@ static size_t ReadFile(void *ptr, size_t size, size_t nmemb, void *stream) {
return n;
}
void notify(QString notif, QString priority, QString inputPath)
void notify(QString notif, QString priority, QString inputPath, QString tag)
{
CURL *curl;
CURLcode res;
@@ -647,6 +639,7 @@ void notify(QString notif, QString priority, QString inputPath)
{
// Définis les en-têtes pour le titre et les priorités
struct curl_slist *headers = NULL;
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");

View File

@@ -56,7 +56,7 @@ double tohPa(double value);
bool compare (double value=0, double testValue=0, double ecart = 0.5);
QString formatNotifString (QString name, QString unit, QByteArray value="");
double mphTokmh (double value);
void notify (QString notif, QString priority = "low", QString inputPath = "");
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);