- correction of bugs\n- added notifications with ntfy
This commit is contained in:
8
main.cpp
8
main.cpp
@@ -16,7 +16,7 @@
|
||||
#include "pws2mqtt.h"
|
||||
#include "mqtt.h"
|
||||
//#include "version.h"
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
@@ -25,7 +25,7 @@
|
||||
#define BROKER_ADDRESS "localhost"
|
||||
#define MQTT_PORT 1883;
|
||||
|
||||
uint debugLevel = ALL;
|
||||
uint debugLevel = INFO | NOTICE | INFO | WARNING | ERROR | ALERT;
|
||||
QByteArray toFollow;
|
||||
|
||||
//class MqttClient;
|
||||
@@ -43,6 +43,7 @@ int main(int argc, char *argv[])
|
||||
debug(DEBUGMACRO, "QcoreApplication", DEBUG);
|
||||
QCoreApplication a(argc, argv);
|
||||
|
||||
notify ("Météo" "Program starting");
|
||||
// Enable logging to journald
|
||||
qputenv("QT_FORCE_STDERR_LOGGING", QByteArray("0"));
|
||||
|
||||
@@ -61,6 +62,7 @@ int main(int argc, char *argv[])
|
||||
mqttClient->qmqttClient->unsubscribe(mqttClient->topic);
|
||||
mqttClient->qmqttClient->disconnectFromHost();
|
||||
debug(DEBUGMACRO, "exiting", DEBUG);
|
||||
notify ("Météo" "Program exiting");
|
||||
//Closing http server
|
||||
}
|
||||
|
||||
@@ -96,10 +98,12 @@ 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);
|
||||
}
|
||||
if ((debugLevel & level) == 8)
|
||||
{
|
||||
qInfo("%s%s ERROR: %s%s", debugHeader.toStdString().c_str(), RED, msg.toStdString().c_str(), NORMAL);
|
||||
notify ("Proram exiting " + debugHeader + " - " + msg );
|
||||
exit(1);
|
||||
}
|
||||
if ((debugLevel & level) == 16)
|
||||
|
||||
10
mqtt.cpp
10
mqtt.cpp
@@ -82,7 +82,7 @@ void MqttClient::on_messageSentStatusChanged(qint32 id, QMqtt::MessageStatus s,
|
||||
|
||||
if ( id == 0)
|
||||
{
|
||||
debug(DEBUGMACRO, "message id = " + QString::number(id) + this->messageStatus[static_cast<int>(s)], DEBUG);
|
||||
debug(DEBUGMACRO, "message id = " + QString::number(id) + this->messageStatus[static_cast<int>(s)], WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,10 +116,10 @@ void MqttClient::updateStatus(QMqttSubscription::SubscriptionState state)
|
||||
switch (state)
|
||||
{
|
||||
case QMqttSubscription::Unsubscribed:
|
||||
debug(DEBUGMACRO, "Unsubscribed", INFO);
|
||||
debug(DEBUGMACRO, "Unsubscribed", WARNING);
|
||||
break;
|
||||
case QMqttSubscription::SubscriptionPending:
|
||||
debug(DEBUGMACRO, "Pending subscription", DEBUG);
|
||||
debug(DEBUGMACRO, "Pending subscription", WARNING);
|
||||
break;
|
||||
case QMqttSubscription::Subscribed:
|
||||
debug(DEBUGMACRO, "Subscribed", INFO);
|
||||
@@ -128,7 +128,7 @@ void MqttClient::updateStatus(QMqttSubscription::SubscriptionState state)
|
||||
debug(DEBUGMACRO, "Subscription error" + this->subscription->reason(), WARNING);
|
||||
break;
|
||||
case QMqttSubscription::UnsubscriptionPending:
|
||||
debug(DEBUGMACRO, "Pending Unsubscription", DEBUG);
|
||||
debug(DEBUGMACRO, "Pending Unsubscription", WARNING);
|
||||
break;
|
||||
default:
|
||||
debug(DEBUGMACRO, "--Unknown--", DEBUG);
|
||||
@@ -138,5 +138,5 @@ void MqttClient::updateStatus(QMqttSubscription::SubscriptionState state)
|
||||
|
||||
void MqttClient::on_stateChanged(QMqttClient::ClientState state)
|
||||
{
|
||||
debug(DEBUGMACRO, QLatin1String("State Change : ") + this->clientStateString[state], DEBUG );
|
||||
debug(DEBUGMACRO, QLatin1String("State Change : ") + this->clientStateString[state], WARNING );
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ QT += core
|
||||
QT += mqtt
|
||||
QT += httpserver
|
||||
|
||||
LIBS += -lcurl
|
||||
|
||||
CONFIG += c++17 console
|
||||
CONFIG -= app_bundle
|
||||
|
||||
@@ -24,6 +26,6 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin
|
||||
HEADERS += \
|
||||
httpserver.h \
|
||||
mqtt.h \
|
||||
pws2mqtt.h \
|
||||
pws2mqtt.h \
|
||||
version.h
|
||||
|
||||
|
||||
294
pws2mqtt.cpp
294
pws2mqtt.cpp
@@ -9,19 +9,36 @@
|
||||
#include <netinet/in.h>
|
||||
#include <QtHttpServer/QHttpServer>
|
||||
#include <QtHttpServer/QHttpServerRequest>
|
||||
#include <curl/curl.h>
|
||||
#include <QtMath>
|
||||
|
||||
extern MqttClient *mqttClient;
|
||||
extern Pws2mqtt *pws2mqtt;
|
||||
extern QHttpServer *httpServer;
|
||||
QStringList previsionList {"Temps variable (incertain).", \
|
||||
"Beau temps stable (anticyclone).", \
|
||||
"Amélioration progressive (éclaircies).", \
|
||||
"Risque de pluie légère ou nuages.", \
|
||||
"Dégradation marquée (pluie/vent/orage).", \
|
||||
"Tempête ou dépression forte (vigilance)." \
|
||||
};
|
||||
|
||||
QMap <QByteArray, QByteArray> propertyList;
|
||||
// Callback for curl library
|
||||
static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
|
||||
{
|
||||
(void)contents; // Évite les warnings de compilation
|
||||
(void)userp;
|
||||
return size * nmemb; // On ne traite pas les données reçues
|
||||
}
|
||||
|
||||
QMap <QByteArray, qfloat16> propertyList;
|
||||
QMap <QByteArray, QPair<QString, QByteArray>> propertyName
|
||||
{
|
||||
{"tempf", {"Température extérieure", "°C"}},
|
||||
{"humidity", {"Humidité extérieure", "%"}},
|
||||
{"dewptf", {"Point de rosée", "°C"}},
|
||||
{"windchillf", {"Température ressentie", "°C"}},
|
||||
{"windir", {"Direction du vent", "°"}},
|
||||
{"winddir", {"Direction du vent", "°"}},
|
||||
{"windspeedmph", {"vitesse du vent", "km/h"}},
|
||||
{"windgustmph", {"Rafales", "km/h"}},
|
||||
{"rainin", {"Pluie", "mm/h"}},
|
||||
@@ -32,7 +49,7 @@ QMap <QByteArray, QPair<QString, QByteArray>> propertyName
|
||||
{"indoortempf", {"Température intérieure", "°C"}},
|
||||
{"indoorhumidity", {"Humidité intérieure", "%"}},
|
||||
{"baromin", {"pression atmosphérique", "hPa"}},
|
||||
{"lowbatt", {"Batterie faible", ""}},
|
||||
{"lowbatt", {"Alerte batterie faible", ""}},
|
||||
{"UV", {"UV", ""}}
|
||||
};
|
||||
|
||||
@@ -105,9 +122,13 @@ void Pws2mqtt::parseData(QList<std::pair<QString, QString>> queryList)
|
||||
QString jsonString = "{";
|
||||
bool propertyFlag = false;
|
||||
bool deviceFlag = false;
|
||||
QString topic;
|
||||
QString spaceFlag = "";
|
||||
// QString topic;
|
||||
QString deviceString = "\"device\": {\"ieeeAddress\": \"" + mqttClient->macAddress + "\", \"type\": \"" + mqttClient->type + "\", \"powerSource\": \"Battery\"";
|
||||
QString notif;
|
||||
QString notif = "";
|
||||
double propertyValue;
|
||||
QStringList priorityList {"", "min", "low", "default", "High", "urgent"};
|
||||
quint8 priority = 2;
|
||||
|
||||
debug(DEBUGMACRO, "looping list of query", DEBUG);
|
||||
|
||||
@@ -140,56 +161,289 @@ void Pws2mqtt::parseData(QList<std::pair<QString, QString>> queryList)
|
||||
//mqttClient->end_message(topic, jsonString);
|
||||
if (pair.first == "tempf")
|
||||
{
|
||||
QByteArray tmp = pair.second.toLatin1();
|
||||
if (compare (propertyList[pair.first.toLatin1()], tmp, 0.2))
|
||||
propertyValue = fahrenheitToCelsius(pair.second.toFloat());
|
||||
if (compare (propertyList[pair.first.toLatin1()], propertyValue, 0.5))
|
||||
{
|
||||
notif += formatNotifString (pair, QByteArray::number(fahrenheitToCelsius(pair.second.toFloat())));
|
||||
notif += spaceFlag + formatNotifString (pair, QByteArray::number(qPow(propertyValue, 1.0)));
|
||||
debug (DEBUGMACRO, "Notif = #" + notif + "#", DEBUG);
|
||||
propertyList[pair.first.toLatin1()] = propertyValue;
|
||||
}
|
||||
}else if (pair.first == "humidity")
|
||||
//TODO
|
||||
propertyList[pair.first.toLatin1()] = pair.second.toLatin1();
|
||||
{
|
||||
propertyValue = pair.second.toFloat();
|
||||
if (compare (propertyList[pair.first.toLatin1()], propertyValue, 3))
|
||||
{
|
||||
notif += spaceFlag + formatNotifString (pair, pair.second.toLatin1());
|
||||
debug (DEBUGMACRO, "Notif = #" + notif + "#", DEBUG);
|
||||
}
|
||||
}else if (pair.first == "windchillf")
|
||||
{
|
||||
propertyValue = fahrenheitToCelsius(pair.second.toFloat());
|
||||
if (compare (propertyList[pair.first.toLatin1()], propertyValue, 0.2))
|
||||
{
|
||||
notif += spaceFlag + formatNotifString (pair, QByteArray::number(qPow(propertyValue, 1.0)));
|
||||
debug (DEBUGMACRO, "Notif = #" + notif + "#", DEBUG);
|
||||
}
|
||||
}else if (pair.first == "winddir")
|
||||
{
|
||||
propertyValue = pair.second.toFloat();
|
||||
if (compare (propertyList[pair.first.toLatin1()], propertyValue, 90))
|
||||
{
|
||||
notif += spaceFlag + formatNotifString (pair, pair.second.toLatin1());
|
||||
debug (DEBUGMACRO, "Notif = #" + notif + "#", DEBUG);
|
||||
}
|
||||
}else if (pair.first == "windspeedmph")
|
||||
{
|
||||
propertyValue = mphTokmh(pair.second.toFloat());
|
||||
if (compare (propertyList[pair.first.toLatin1()], propertyValue, 10))
|
||||
{
|
||||
notif += spaceFlag + formatNotifString (pair, QByteArray::number(round(propertyValue)));
|
||||
if (propertyValue > 30)
|
||||
priority = setPriority (priority, 4);
|
||||
if (propertyValue > 50)
|
||||
priority = setPriority (priority, 5);
|
||||
debug (DEBUGMACRO, "Notif = #" + notif + "#", DEBUG);
|
||||
}
|
||||
}else if (pair.first == "windgustmph")
|
||||
{
|
||||
propertyValue = mphTokmh(pair.second.toFloat());
|
||||
if (compare (propertyList[pair.first.toLatin1()], propertyValue, 5) and propertyValue > 20)
|
||||
{
|
||||
notif += spaceFlag + formatNotifString (pair, QByteArray::number(round(propertyValue)));
|
||||
if (propertyValue > 40)
|
||||
priority = setPriority (priority, 4);
|
||||
if (propertyValue > 60)
|
||||
priority = setPriority (priority, 5);
|
||||
debug (DEBUGMACRO, "Notif = #" + notif + "#", DEBUG);
|
||||
}
|
||||
}else if (pair.first == "rainin")
|
||||
{
|
||||
propertyValue = pair.second.toFloat();
|
||||
if (compare (propertyList[pair.first.toLatin1()], propertyValue, 0.01))
|
||||
{
|
||||
notif += spaceFlag + formatNotifString (pair, pair.second.toLatin1());
|
||||
priority = setPriority (priority, 4);
|
||||
debug (DEBUGMACRO, "Notif = #" + notif + "#", DEBUG);
|
||||
}
|
||||
}else if (pair.first == "baromin")
|
||||
{
|
||||
propertyValue = tohPa(pair.second.toFloat());
|
||||
pressureVariation(propertyValue);
|
||||
if (compare (propertyList[pair.first.toLatin1()], propertyValue, 100))
|
||||
{
|
||||
notif += spaceFlag + formatNotifString (pair, QByteArray::number(propertyValue));
|
||||
debug (DEBUGMACRO, "Notif = #" + notif + "#", DEBUG);
|
||||
}
|
||||
}else if (pair.first == "UV")
|
||||
{
|
||||
propertyValue = pair.second.toFloat();
|
||||
if (compare (propertyList[pair.first.toLatin1()], propertyValue, 1))
|
||||
{
|
||||
notif += spaceFlag + formatNotifString (pair, pair.second.toLatin1());
|
||||
if (propertyValue > 3)
|
||||
priority = setPriority (priority, 5);
|
||||
debug (DEBUGMACRO, "Notif = #" + notif + "#", DEBUG);
|
||||
}
|
||||
}else if (pair.first == "lowbat")
|
||||
{
|
||||
static QTime time;
|
||||
if (pair.second.toInt() == 1 and time > QTime::currentTime().addSecs(3600))
|
||||
{
|
||||
notif += spaceFlag + formatNotifString (pair, "");
|
||||
debug (DEBUGMACRO, "Notif = #" + notif + "#", DEBUG);
|
||||
priority = setPriority (priority, 4);
|
||||
time = time.currentTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
propertyList[pair.first.toLatin1()] = propertyValue;
|
||||
if (!notif.isEmpty())
|
||||
{
|
||||
spaceFlag = " ";
|
||||
}
|
||||
}
|
||||
if (!jsonString.isEmpty())
|
||||
{
|
||||
jsonString = jsonString +", " + deviceString + "}}";
|
||||
mqttClient->send_message(jsonString);
|
||||
debug(DEBUGMACRO, "sent => " + jsonString, DEBUG);
|
||||
//debug(DEBUGMACRO, "sent => " + jsonString, DEBUG);
|
||||
}else
|
||||
{
|
||||
debug(DEBUGMACRO, "No values to send", DEBUG);
|
||||
}
|
||||
|
||||
if (!notif.isEmpty())
|
||||
{
|
||||
debug(DEBUGMACRO, "calling notify with notif = #" + notif + "#", DEBUG);
|
||||
notify (notif, priorityList[priority]);
|
||||
}
|
||||
debug(DEBUGMACRO, "parseData: Returning", DEBUG);
|
||||
//return jsonString;
|
||||
}
|
||||
|
||||
double fahrenheitToCelsius(double fahrenheit)
|
||||
quint8 previsionMeteo(double currentPressure, double variation3h)
|
||||
{
|
||||
if (currentPressure > 1020.0 && variation3h >= 0.0)
|
||||
{
|
||||
return 0;
|
||||
} else if (currentPressure > 1010.0 && currentPressure <= 1020.0 && variation3h > 0.0)
|
||||
{
|
||||
return 1;
|
||||
} else if (currentPressure > 1000.0 && currentPressure <= 1010.0 && variation3h < 0.0)
|
||||
{
|
||||
return 2;
|
||||
} else if (currentPressure <= 1000.0 && variation3h < -2.0)
|
||||
{
|
||||
return 3;
|
||||
} else if (currentPressure < 990.0)
|
||||
{
|
||||
return 4;
|
||||
} else
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
|
||||
void pressureVariation(qfloat16 currentPressure)
|
||||
{
|
||||
const int NB_MESURES_3H = 360; // 3h × 120 mesures/heure (1 mesure toutes les 30s)
|
||||
QVector<double> historiquePressions;
|
||||
|
||||
debug(DEBUGMACRO, "PressureVariation", DEBUG);
|
||||
|
||||
historiquePressions.reserve(NB_MESURES_3H);
|
||||
|
||||
// Ajout de la mesure à l'historique
|
||||
historiquePressions.push_back(currentPressure);
|
||||
|
||||
// Si on a assez de mesures pour couvrir 3h
|
||||
if (historiquePressions.size() > NB_MESURES_3H)
|
||||
{
|
||||
historiquePressions.erase(historiquePressions.begin());
|
||||
}
|
||||
|
||||
// Calcul de la variation sur 3h si on a assez de mesures
|
||||
if (historiquePressions.size() == NB_MESURES_3H)
|
||||
{
|
||||
double pressionInitiale = historiquePressions.front();
|
||||
double pressionFinale = historiquePressions.back();
|
||||
double variation = pressionFinale - pressionInitiale;
|
||||
|
||||
debug(DEBUGMACRO, "Pression actuelle : " + QString::number(pressionFinale) + " hPa", DEBUG);
|
||||
debug(DEBUGMACRO, "Variation sur 3h : " + QString::number(variation) + " hPa", DEBUG);
|
||||
|
||||
// Prévision météo
|
||||
quint8 prevision = previsionMeteo(pressionFinale, variation);
|
||||
debug(DEBUGMACRO, "Prévision : " + previsionList[prevision], DEBUG);
|
||||
|
||||
// Exemple : Envoi d'une alerte si nécessaire
|
||||
if (prevision == 4)
|
||||
{
|
||||
notify ("ALERTE : " + previsionList[prevision], "high");
|
||||
}else if (prevision == 5)
|
||||
{
|
||||
notify ("ALERTE : " + previsionList[prevision], "urgent");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
quint8 setPriority (quint8 currentPriority, quint8 newPriority)
|
||||
{
|
||||
if (newPriority > currentPriority)
|
||||
{
|
||||
return newPriority;
|
||||
}else
|
||||
{
|
||||
return currentPriority;
|
||||
}
|
||||
}
|
||||
|
||||
double fahrenheitToCelsius (double fahrenheit)
|
||||
{
|
||||
return (fahrenheit - 32.0) * 5.0 / 9.0;
|
||||
}
|
||||
|
||||
qfloat16 tohPa(qfloat16 value)
|
||||
qfloat16 tohPa (qfloat16 value)
|
||||
{
|
||||
return value * 33.8639;
|
||||
}
|
||||
|
||||
bool compare (QByteArray valueBA, QByteArray testValueBA, qfloat16 ecart)
|
||||
qfloat16 mphTokmh (qfloat16 value)
|
||||
{
|
||||
qfloat16 value = valueBA.toFloat();
|
||||
qfloat16 testValue = testValueBA.toFloat();
|
||||
return value * 1.60934;
|
||||
}
|
||||
|
||||
if (value <= (testValue - ecart) or value >= (testValue + ecart))
|
||||
bool compare (qfloat16 value, qfloat16 currentValue, qfloat16 ecart)
|
||||
{
|
||||
|
||||
debug(DEBUGMACRO, "value: " + QByteArray::number(value) + "testValue: " + QByteArray::number(currentValue), DEBUG);
|
||||
|
||||
if (currentValue <= (value - ecart) or currentValue >= (value + ecart))
|
||||
{
|
||||
debug(DEBUGMACRO, "compare return true", DEBUG);
|
||||
return true;
|
||||
}else
|
||||
{
|
||||
debug(DEBUGMACRO, "compare return false", DEBUG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
QString formatNotifString (QPair <QString, QString> pair, QByteArray value)
|
||||
{
|
||||
return propertyName[pair.first.toLatin1()].first + " : " + value + propertyName[pair.first.toLatin1()].second;
|
||||
|
||||
return "- " + propertyName[pair.first.toLatin1()].first + " : " + value + propertyName[pair.first.toLatin1()].second;
|
||||
}
|
||||
|
||||
void notify(QString notif, QString priority)
|
||||
{
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
|
||||
priority = "Priority: " + priority;
|
||||
|
||||
// Initialise libcurl
|
||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
curl = curl_easy_init();
|
||||
|
||||
if (curl)
|
||||
{
|
||||
// URL de ton serveur ntfy
|
||||
QString url = "http://localhost:81/Meteo"; // Remplace par ton URL et topic
|
||||
|
||||
// Message à envoyer
|
||||
QString message = notif;
|
||||
|
||||
// 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, "Markdown: yes");
|
||||
headers = curl_slist_append(headers, "Config: /etc/ntfy.client.yml");
|
||||
headers = curl_slist_append(headers, "Firebase: no");
|
||||
|
||||
// Configure la requête POST
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.toUtf8().constData());
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, message.toUtf8().constData());
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||
|
||||
// Exécute la requête
|
||||
res = curl_easy_perform(curl);
|
||||
|
||||
// Vérifie les erreurs
|
||||
if (res != CURLE_OK)
|
||||
{
|
||||
qCritical() << "Erreur libcurl :" << curl_easy_strerror(res);
|
||||
} else
|
||||
{
|
||||
qDebug() << "Notification envoyée avec succès !";
|
||||
}
|
||||
|
||||
// Nettoie les ressources
|
||||
curl_slist_free_all(headers);
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
|
||||
// Nettoie libcurl
|
||||
curl_global_cleanup();
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,12 @@ class Pws2mqtt : public QObject
|
||||
};
|
||||
double fahrenheitToCelsius(double fahrenheit);
|
||||
qfloat16 tohPa(qfloat16 value);
|
||||
bool compare (QByteArray value, QByteArray testValue, qfloat16 ecart = 0.5);
|
||||
bool compare (qfloat16 value, qfloat16 testValue, qfloat16 ecart = 0.5);
|
||||
QString formatNotifString (QPair<QString, QString> pair, QByteArray value);
|
||||
qfloat16 mphTokmh (qfloat16 value);
|
||||
void notify (QString notif, QString priority = "low");
|
||||
quint8 setPriority (quint8 currentPriority, quint8 newPriority);
|
||||
quint8 previsionMeteo(double currentPressure, double variation3h);
|
||||
void pressureVariation(qfloat16 currentPressure);
|
||||
|
||||
#endif // PWS2MQTT_H
|
||||
|
||||
Reference in New Issue
Block a user