diff --git a/MqttClient.h b/MqttClient.h index bda20d267505408ba552d336acdde811436a8ad8..070831623919fb59dcafdbc2eca93b701a62346e 100644 --- a/MqttClient.h +++ b/MqttClient.h @@ -73,7 +73,10 @@ public: // * qos (0,1,2) // * retain (boolean) - indicates if message is retained on broker or not // Should return MOSQ_ERR_SUCCESS - int ret = publish(NULL, topic, sizeof(message), message, db->getSettings().mqtt_qos, true); + int ret = publish(NULL, topic, strlen(message), message, db->getSettings().mqtt_qos, true); + if (DEBUG) std::cout << "Published: " << std::endl; + if (DEBUG) std::cout << "Topic: " << topic << std::endl; + if (DEBUG) std::cout << "Message: " << message << std::endl; return (ret == MOSQ_ERR_SUCCESS); } @@ -94,14 +97,14 @@ public: std::string str(buf); - if (str.find("Request_") != std::string::npos) { + /*if (str.find("Request_") != std::string::npos) { std::cout << "MqttClient::on_message() - Request found" << std::endl; std::string client = str.substr(str.find("_") + 1); std::cout << "Client " + client + " requested update" << std::endl; std::string result = db->getFrontendData().c_str(); snprintf(buf, payload_size, result.c_str()); publish(NULL, db->getSettings().mqtt_topic_frontend.c_str(), strlen(result.c_str()), result.c_str()); - } + }*/ } } }; \ No newline at end of file diff --git a/backend.cpp b/backend.cpp index 8963d22d4baff419c1c245c6a70569949042531e..b1f07eeec7c83cdf5c79a6f87c840ef82853dcc6 100644 --- a/backend.cpp +++ b/backend.cpp @@ -1,8 +1,9 @@ #include <iostream> #include <thread> -#include <vector> #include <chrono> #include <ctime> +#include <vector> +#include <string> #include "openweathermap.h" #include "MqttClient.h" #include "dbSqlite.h" @@ -10,6 +11,11 @@ #define DEBUG true +using std::string; +using std::cout; +using std::endl; +using std::thread; + // Database object dbSqlite* db; openweathermap* owmw; @@ -17,45 +23,70 @@ MqttClient* mqttClient; // Thread for openweathermap:getWeather void schedulerWeather(int time) { - if (DEBUG) std::cout << "Wetterstation::schedulerWeather()" << std::endl; + if (DEBUG) cout << "Wetterstation::schedulerWeather()" << endl; + string topic; + string weather; + std::vector<Region> region; + std::vector<Frontend> frontend; + while (1) { - owmw->getWeather(db->getSettings().owm_plz, db->getSettings().owm_lngCode); + region = db->queryRegions(); + frontend = db->queryFrontends(); + for (int i = 0; i < region.size(); i++) { + if (DEBUG) cout << "Wetterstation::schedulerWeather(" + region[i].plz + ")" << endl; + owmw->getWeather(region[i].plz, region[i].lngCode); + weather = db->getFrontendDataWeather().c_str(); + for (int fr = 0; fr < frontend.size(); fr++) { + if (frontend[fr].plz == region[i].plz) { + topic = db->getSettings().mqtt_topic_frontend + frontend[fr].frontendId + "/weather"; + mqttClient->send_message(weather.c_str(), topic.c_str()); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + } + } + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } std::this_thread::sleep_for(std::chrono::milliseconds(time)); } } // Thread for openweathermap:getForecast void schedulerForecast(int time) { - if (DEBUG) std::cout << "Wetterstation::schedulerForecast()" << std::endl; + if (DEBUG) cout << "Wetterstation::schedulerForecast()" << endl; + string topic; + string forecast; + std::vector<Region> region; + std::vector<Frontend> frontend; + while (1) { - owmw->getForecast(db->getSettings().owm_plz, db->getSettings().owm_lngCode); + region = db->queryRegions(); + frontend = db->queryFrontends(); + for (int i = 0; i < region.size(); i++) { + if (DEBUG) cout << "Wetterstation::schedulerForecast(" + region[i].plz + ")" << endl; + owmw->getForecast(region[i].plz, region[i].lngCode); + forecast = db->getFrontendDataForecast().c_str(); + for (int fr = 0; fr < frontend.size(); fr++) { + if (frontend[fr].plz == region[i].plz) { + topic = db->getSettings().mqtt_topic_frontend + frontend[i].frontendId + "/forecast"; + mqttClient->send_message(forecast.c_str(), topic.c_str()); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + } + } + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } std::this_thread::sleep_for(std::chrono::milliseconds(time)); } } -// Thread for MQTT:sendWeather -//void schedulerMqttSendWeather(int time) { -// if (DEBUG) std::cout << "Wetterstation::schedulerMqttSendWeather()" << std::endl; -// while (1) { -// //mqttClient->publish(); -// std::this_thread::sleep_for(std::chrono::milliseconds(time)); -// } -//} - void mqttStart() { - if (DEBUG) std::cout << "Wetterstation::mqttStart()" << std::endl; - + if (DEBUG) cout << "Wetterstation::mqttStart()" << endl; mosqpp::lib_init(); - mqttClient = new MqttClient("Wetterstation", db); - //std::thread thrMqttSendWeather{ schedulerMqttSendWeather, 10000 }; - mosqpp::lib_cleanup(); } // Main method int main() { - if (DEBUG) std::cout << "Wetterstation::main()" << std::endl; + if (DEBUG) cout << "Wetterstation::main()" << endl; // Sockets aktivieren WSADATA wsaData; @@ -70,19 +101,17 @@ int main() { owmw = new openweathermap(db); + // MQTT starten + mqttStart(); + // Thread für getWeather starten - std::thread thrWeather{ schedulerWeather, 60000 }; + thread thrWeather{ schedulerWeather, 60000 }; std::this_thread::sleep_for(std::chrono::milliseconds(50)); // Thread für getForecast starten - std::thread thrForecast{ schedulerForecast, 90000 }; + thread thrForecast{ schedulerForecast, 90000 }; std::this_thread::sleep_for(std::chrono::milliseconds(50)); - // MQTT starten - mqttStart(); - - std::vector<WeatherConditions> cond = db->getConditions(); - while (1) { Sleep(1000); } diff --git a/dbSqlite.h b/dbSqlite.h index 6bb76673c95963648f83302626318358567fa128..ff71ca56ebcca05d3116cbf419c98551ee9877cf 100644 --- a/dbSqlite.h +++ b/dbSqlite.h @@ -2,10 +2,10 @@ #include <iostream> #include <string> #include <vector> -#include "influxdb.h" #include "Poco/Data/Session.h" #include "Poco/Data/SQLite/Connector.h" #include "nlohmann/json.hpp" +#include "influxdb.h" #include "structs.h" using namespace Poco::Data::Keywords; @@ -13,122 +13,142 @@ using Poco::Data::Session; using Poco::Data::Statement; using std::string; using std::cout; +using std::endl; -#define DEBUG false +#define DEBUG true class dbSqlite { private: - std::vector<WeatherConditions> weatherConditions; Settings settings; - std::vector<weatherData> vecForecast; - weatherData sWeather; + std::vector<WeatherData> vecForecast; + WeatherData sWeather; public: string dbFile; dbSqlite() { - if (DEBUG) std::cout << "sbSqlite()" << std::endl; + if (DEBUG) cout << "sbSqlite()" << endl; Poco::Data::SQLite::Connector::registerConnector(); this->dbFile = "weatherstation.db"; - this->weatherConditions = this->queryConditions(); this->querySettings(); }; Settings getSettings() { - if (DEBUG) std::cout << "dbSqlite::getSettings()" << std::endl; + if (DEBUG) cout << "dbSqlite::getSettings()" << endl; return this->settings; } - std::vector<WeatherConditions> getConditions() { - return this->weatherConditions; + WeatherData getSWeather() { + return this->sWeather; } - weatherData getSWeather() { - return this->sWeather; + string getFrontendDataWeather() { + if (DEBUG) cout << "dbSqlite::getFrontendDataWeather()" << endl; + nlohmann::json jObj; + + jObj["plz"] = sWeather.plz; + jObj["lngCode"] = sWeather.lngCode; + jObj["sunrise"] = sWeather.sunrise; + jObj["sunset"] = sWeather.sunset; + jObj["visibility"] = sWeather.visibility; + jObj["temp"] = sWeather.temp; + jObj["tempFeelsLike"] = sWeather.tempFeelsLike; + jObj["tempMin"] = sWeather.tempMin; + jObj["tempMax"] = sWeather.tempMax; + jObj["humidity"] = sWeather.humidity; + jObj["pressure"] = sWeather.pressure; + jObj["windSpeed"] = sWeather.windSpeed; + jObj["windDeg"] = sWeather.windDeg; + jObj["clouds"] = sWeather.clouds; + jObj["rain1h"] = sWeather.rain1h; + jObj["rain3h"] = sWeather.rain3h; + jObj["snow1h"] = sWeather.snow1h; + jObj["snow3h"] = sWeather.snow3h; + jObj["icon1Id"] = sWeather.icon1Id; + jObj["icon1"] = sWeather.icon1; + jObj["icon2Id"] = sWeather.icon2Id; + jObj["icon2"] = sWeather.icon2; + + return jObj.dump(); } - std::string getFrontendData() { + string getFrontendDataForecast() { + if (DEBUG) cout << "dbSqlite::getFrontendDataForecast()" << endl; nlohmann::json jObj; + int index = 0; + + for (int i = 0; i < vecForecast.size(); i++) { + if (vecForecast[i].from.find("12:00:00") != string::npos) { + jObj[index]["plz"] = vecForecast[i].plz; + jObj[index]["lngCode"] = vecForecast[i].lngCode; + jObj[index]["sunrise"] = vecForecast[i].sunrise; + jObj[index]["sunset"] = vecForecast[i].sunset; + jObj[index]["visibility"] = vecForecast[i].visibility; + jObj[index]["temp"] = vecForecast[i].temp; + jObj[index]["tempFeelsLike"] = vecForecast[i].tempFeelsLike; + jObj[index]["tempMin"] = vecForecast[i].tempMin; + jObj[index]["tempMax"] = vecForecast[i].tempMax; + jObj[index]["humidity"] = vecForecast[i].humidity; + jObj[index]["pressure"] = vecForecast[i].pressure; + jObj[index]["windSpeed"] = vecForecast[i].windSpeed; + jObj[index]["windDeg"] = vecForecast[i].windDeg; + jObj[index]["clouds"] = vecForecast[i].clouds; + jObj[index]["rain1h"] = vecForecast[i].rain1h; + jObj[index]["rain3h"] = vecForecast[i].rain3h; + jObj[index]["snow1h"] = vecForecast[i].snow1h; + jObj[index]["snow3h"] = vecForecast[i].snow3h; + jObj[index]["icon1Id"] = vecForecast[i].icon1Id; + jObj[index]["icon1"] = vecForecast[i].icon1; + jObj[index]["icon2Id"] = vecForecast[i].icon2Id; + jObj[index]["icon2"] = vecForecast[i].icon2; + jObj[index]["from"] = vecForecast[i].from; + index++; + } + } + + return jObj.dump(); + } - std::string queryResult; + string getFrontendDataSensors() { + if (DEBUG) cout << "dbSqlite::getFrontendDataSensors()" << endl; + nlohmann::json jObj; + int i = 0; + int j = 0; + + string queryResult; influxdb_cpp::server_info si(this->getSettings().influx_host, this->getSettings().influx_port, this->getSettings().influx_db, this->getSettings().influx_user, this->getSettings().influx_pass); influxdb_cpp::query(queryResult, "SELECT * FROM Sensors WHERE client = 'DVES_06236C' AND time > now() - 5m;", si); auto response = nlohmann::json::parse(queryResult); nlohmann::json columns = response["results"][0]["series"][0]["columns"]; - - int i = 0; - int j = 0; for (nlohmann::json line : response["results"][0]["series"][0]["values"]) { j = 0; nlohmann::json temp; for (nlohmann::json column : columns) { - temp[column.get<std::string>()] = line[j]; + temp[column.get<string>()] = line[j]; j++; } - jObj["sensors"][i++] = temp; + jObj[i++] = temp; } - for (int i = 0; i < vecForecast.size(); i++) { - jObj["forecast"][i]["plz"] = vecForecast[i].plz; - jObj["forecast"][i]["lngCode"] = vecForecast[i].lngCode; - jObj["forecast"][i]["sunrise"] = vecForecast[i].sunrise; - jObj["forecast"][i]["sunset"] = vecForecast[i].sunset; - jObj["forecast"][i]["visibility"] = vecForecast[i].visibility; - jObj["forecast"][i]["temp"] = vecForecast[i].temp; - jObj["forecast"][i]["tempFeelsLike"] = vecForecast[i].tempFeelsLike; - jObj["forecast"][i]["tempMin"] = vecForecast[i].tempMin; - jObj["forecast"][i]["tempMax"] = vecForecast[i].tempMax; - jObj["forecast"][i]["humidity"] = vecForecast[i].humidity; - jObj["forecast"][i]["pressure"] = vecForecast[i].pressure; - jObj["forecast"][i]["windSpeed"] = vecForecast[i].windSpeed; - jObj["forecast"][i]["windDeg"] = vecForecast[i].windDeg; - jObj["forecast"][i]["clouds"] = vecForecast[i].clouds; - jObj["forecast"][i]["rain1h"] = vecForecast[i].rain1h; - jObj["forecast"][i]["rain3h"] = vecForecast[i].rain3h; - jObj["forecast"][i]["snow1h"] = vecForecast[i].snow1h; - jObj["forecast"][i]["snow3h"] = vecForecast[i].snow3h; - jObj["forecast"][i]["icons"] = vecForecast[i].icons; - jObj["forecast"][i]["from"] = vecForecast[i].from; - } - jObj["current"]["plz"] = sWeather.plz; - jObj["current"]["lngCode"] = sWeather.lngCode; - jObj["current"]["sunrise"] = sWeather.sunrise; - jObj["current"]["sunset"] = sWeather.sunset; - jObj["current"]["visibility"] = sWeather.visibility; - jObj["current"]["temp"] = sWeather.temp; - jObj["current"]["tempFeelsLike"] = sWeather.tempFeelsLike; - jObj["current"]["tempMin"] = sWeather.tempMin; - jObj["current"]["tempMax"] = sWeather.tempMax; - jObj["current"]["humidity"] = sWeather.humidity; - jObj["current"]["pressure"] = sWeather.pressure; - jObj["current"]["windSpeed"] = sWeather.windSpeed; - jObj["current"]["windDeg"] = sWeather.windDeg; - jObj["current"]["clouds"] = sWeather.clouds; - jObj["current"]["rain1h"] = sWeather.rain1h; - jObj["current"]["rain3h"] = sWeather.rain3h; - jObj["current"]["snow1h"] = sWeather.snow1h; - jObj["current"]["snow3h"] = sWeather.snow3h; - jObj["current"]["icons"] = sWeather.icons; - return jObj.dump(); } - std::string getFrontendJson() { + string getFrontendJson() { nlohmann::json combinedjObj; } - void setSWeather(weatherData wd) { + void setSWeather(WeatherData wd) { this->sWeather = wd; } - void setSForecast(std::vector<weatherData> fc) { + void setSForecast(std::vector<WeatherData> fc) { this->vecForecast = fc; } void querySettings() { - if (DEBUG) std::cout << "dbSqlite::querySettings()" << std::endl; + if (DEBUG) cout << "dbSqlite::querySettings()" << endl; Session session("SQLite", this->dbFile); Statement select(session); @@ -153,22 +173,63 @@ public: select.execute(); } - std::vector<WeatherConditions> queryConditions() { - if (DEBUG) std::cout << "dbSqlite::queryConditions()" << std::endl; + std::vector<Region> queryRegions() { + if (DEBUG) cout << "dbSqlite::queryRegions()" << endl; + Session session("SQLite", this->dbFile); + std::vector<Region> result; + Region region; + + Statement select(session); + select << "SELECT plz, lngCode FROM settings_frontend GROUP BY plz;", + into(region.plz), + into(region.lngCode), + range(0, 1); // iterate over result set one row at a time + + while (!select.done()) { + select.execute(); + result.push_back(region); + } + + return result; + } + + std::vector<Frontend> queryFrontendsByPlz(string plz) { + if (DEBUG) cout << "dbSqlite::queryFrontendsByPlz(" << plz << ")" << endl; + Session session("SQLite", this->dbFile); + std::vector<Frontend> result; + Frontend frontend; + + Statement select(session); + select << "SELECT frontendId, lngCode, plz FROM settings_frontend WHERE plz = \"" + plz + "\";", + into(frontend.frontendId), + into(frontend.lngCode), + into(frontend.plz), + range(0, 1); // iterate over result set one row at a time + + while (!select.done()) { + select.execute(); + result.push_back(frontend); + } + + return result; + } + + std::vector<Frontend> queryFrontends() { + if (DEBUG) cout << "dbSqlite::queryFrontends()" << endl; Session session("SQLite", this->dbFile); - std::vector<WeatherConditions> result; - WeatherConditions wc; + std::vector<Frontend> result; + Frontend frontend; Statement select(session); - select << "SELECT * FROM weather_conditions;", - into(wc.condition_id), - into(wc.main), - into(wc.description), + select << "SELECT frontendId, lngCode, plz FROM settings_frontend;", + into(frontend.frontendId), + into(frontend.lngCode), + into(frontend.plz), range(0, 1); // iterate over result set one row at a time while (!select.done()) { select.execute(); - result.push_back(wc); + result.push_back(frontend); } return result; diff --git a/influxdb.h b/influxdb.h index 380f744da5c2f2fbe817ace38e9f933e02767b89..be8029fb20495d180b000956a8ea2bc970959dc6 100644 --- a/influxdb.h +++ b/influxdb.h @@ -11,6 +11,7 @@ #include <cstring> #include <cstdio> #include <cstdlib> +#include <WinSock2.h> #ifdef _WIN32 #define NOMINMAX diff --git a/openweathermap.h b/openweathermap.h index 49bf4f18e3f0112ff842b6c2435435e8a8da5aa3..d33fb0d738ef5fce58088dce0bfc86408ebd1748 100644 --- a/openweathermap.h +++ b/openweathermap.h @@ -20,22 +20,21 @@ #include "json.h" #include "structs.h" -#define DEBUG false +#define DEBUG true class openweathermap { private: std::string appid; std::string plz; std::string lngCode; - weatherData sWeather; - std::vector<weatherData> vecForecast; + WeatherData sWeather; + std::vector<WeatherData> vecForecast; dbSqlite* db; public: openweathermap(dbSqlite* db_new) { if (DEBUG) std::cout << "openweathermap::openweathermap()" << std::endl; this->db = db_new; - //db = new dbSqlite(); } std::string str_tolower(std::string s) { @@ -46,17 +45,18 @@ public: return s; } - weatherData getSWeather() { + WeatherData getSWeather() { if (DEBUG) std::cout << "openweathermap::getSWeather()" << std::endl; return this->sWeather; } - std::vector<weatherData> getSForecast() { + std::vector<WeatherData> getSForecast() { if (DEBUG) std::cout << "openweathermap::getSForecast()" << std::endl; return this->vecForecast; } void setSWeather(json::JSON jObj, std::string plz, std::string lngCode) { + if (DEBUG) std::cout << "openweathermap::setSWeather(" << plz << ")" << std::endl; this->sWeather.plz = plz; this->sWeather.lngCode = lngCode; @@ -76,14 +76,20 @@ public: this->sWeather.rain3h = jObj["rain"]["3h"].ToFloat(); this->sWeather.snow1h = jObj["snow"]["1h"].ToFloat(); this->sWeather.snow3h = jObj["snow"]["3h"].ToFloat(); - this->sWeather.icons = jObj["weather"].dump(); + this->sWeather.icon1Id = jObj["weather"][0]["id"].ToInt(); + this->sWeather.icon1 = jObj["weather"][0]["icon"].ToString(); + if (jObj["weather"].size() == 2) { + this->sWeather.icon2Id = jObj["weather"][1]["id"].ToInt(); + this->sWeather.icon2 = jObj["weather"][1]["icon"].ToString(); + } db->setSWeather(this->sWeather); } void setSForecast(json::JSON jObj, std::string plz, std::string lngCode) { if (DEBUG) std::cout << "openweathermap::setSForecast(" << plz << ") " << jObj["cnt"] << std::endl; for (int i = 0; i < jObj["cnt"].ToInt(); i++) { - weatherData item; + WeatherData item; + item.plz = plz; item.lngCode = lngCode; item.sunrise = jObj["city"]["sunrise"].ToInt(); @@ -97,8 +103,13 @@ public: item.windSpeed = jObj["list"][i]["wind"]["speed"].ToFloat(); item.windDeg = jObj["list"][i]["wind"]["deg"].ToInt(); item.clouds = jObj["list"][i]["clouds"]["all"].ToInt(); - item.icons = jObj["list"][i]["weather"].dump(); item.from = jObj["list"][i]["dt_txt"].ToString(); + item.icon1Id = jObj["list"][i]["weather"][0]["id"].ToInt(); + item.icon1 = jObj["list"][i]["weather"][0]["icon"].ToString(); + if(jObj["list"][i]["weather"].size() == 2) { + item.icon2Id = jObj["list"][i]["weather"][1]["id"].ToInt(); + item.icon2 = jObj["list"][i]["weather"][1]["icon"].ToString(); + } if (vecForecast.size() != jObj["cnt"].ToInt()) { this->vecForecast.push_back(item); } @@ -167,7 +178,10 @@ public: .field("snow1h", this->sWeather.snow1h) .field("snow3h", this->sWeather.snow3h) .field("clouds", this->sWeather.clouds) - .field("icons", this->sWeather.icons) + .field("icon1Id", this->sWeather.icon1Id) + .field("icon1", this->sWeather.icon1) + .field("icon2Id", this->sWeather.icon2Id) + .field("icon2", this->sWeather.icon2) .post_http(si); } diff --git a/structs.h b/structs.h index 5084c677cdc0c87d6426bf7f2147981960553641..63e03d4ddbd8245223986305a1e02649dbb5f4af 100644 --- a/structs.h +++ b/structs.h @@ -1,12 +1,6 @@ #pragma once #include <iostream> -struct WeatherConditions { - int condition_id; - std::string main; - std::string description; -}; - struct Settings { std::string owm_appid; std::string owm_plz; @@ -26,7 +20,7 @@ struct Settings { int mqtt_port; }; -struct weatherData { +struct WeatherData { std::string plz; std::string lngCode; int sunrise; @@ -45,6 +39,20 @@ struct weatherData { double rain3h; double snow1h; double snow3h; - std::string icons; + int icon1Id; + std::string icon1; + int icon2Id; + std::string icon2; std::string from; +}; + +struct Frontend { + std::string frontendId; + std::string plz; + std::string lngCode; +}; + +struct Region { + std::string plz; + std::string lngCode; }; \ No newline at end of file diff --git a/weatherstation.db b/weatherstation.db index 0480848860acbce2f325143c95034c0a5b63b980..ab058e1b6b1f02359d4a1a033614290c92cc6b8e 100644 Binary files a/weatherstation.db and b/weatherstation.db differ