added snow, rain and blackIve prevision
This commit is contained in:
252
barometertrend.h
Normal file
252
barometertrend.h
Normal 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 l’historique à 3 heures (360 mesures à 30s d’intervalle)
|
||||
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 d’il 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 d’orage
|
||||
if (p < 995 && d < -3 && temperatureC > 20.0 && humidityPercent > 70.0)
|
||||
{
|
||||
r.stormRisk = true;
|
||||
r.message += " ⚡ Risque d’orage";
|
||||
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;
|
||||
};
|
||||
@@ -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 \
|
||||
|
||||
103
src/pws2mqtt.cpp
103
src/pws2mqtt.cpp
@@ -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,7 +263,8 @@ void Pws2mqtt::parseData(QList<std::pair<QString, QString>> queryList)
|
||||
|
||||
attachment = this->outputPath;
|
||||
}
|
||||
}else if (name == "rainin")
|
||||
debug (DEBUGMACRO, "priority = " + QString::number(priority), DEBUG);
|
||||
}else if (name == "rainin")
|
||||
{
|
||||
static double ecart;
|
||||
quint8 raininPriority = 1;
|
||||
@@ -291,7 +285,8 @@ void Pws2mqtt::parseData(QList<std::pair<QString, QString>> queryList)
|
||||
propertyList[name] = formatNotifString(pluviosite + " : ", propertyName[name].second, QByteArray::number(propertyValue));
|
||||
propertiesValue[name] = propertyValue;
|
||||
}
|
||||
}else if (name == "dailyrainin")
|
||||
debug (DEBUGMACRO, "priority = " + QString::number(priority), DEBUG);
|
||||
}else if (name == "dailyrainin")
|
||||
{
|
||||
static double ecart;
|
||||
propertyValue = round(pair.second.toFloat()*100)/100;
|
||||
@@ -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;
|
||||
}
|
||||
}else if (name == "baromin")
|
||||
debug (DEBUGMACRO, "priority = " + QString::number(priority), DEBUG);
|
||||
}else if (name == "baromin")
|
||||
{
|
||||
//static QDateTime timePrevision = QDateTime::currentDateTime().addSecs(-1000);
|
||||
|
||||
propertyValue = tohPa(pair.second.toFloat());
|
||||
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);
|
||||
propertyList[name] = formatNotifString(propertyName[name].first, "", QByteArray::number(propertyValue));
|
||||
propertiesValue[name] = propertyValue;
|
||||
}
|
||||
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));
|
||||
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);
|
||||
if (prevision != newPrevision)
|
||||
{
|
||||
prevision = newPrevision;
|
||||
propertyList["prevision"] = "- " + prevision + " \n";
|
||||
}
|
||||
}
|
||||
}else if (name == "UV")
|
||||
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;
|
||||
@@ -643,11 +635,12 @@ void notify(QString notif, QString priority, QString inputPath)
|
||||
// Initialise libcurl
|
||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
curl = curl_easy_init();
|
||||
if (curl)
|
||||
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, ("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");
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user