From 9a594e05cc2b69802497f7b82ec580c2f09053b8 Mon Sep 17 00:00:00 2001
From: "de@itstall.de" <de@itstall.de>
Date: Mon, 3 Feb 2020 04:02:27 +0100
Subject: [PATCH] closes #3 closes #2

---
 MqttClient.h      |   9 +-
 backend.cpp       |  83 ++++++++++++------
 dbSqlite.h        | 209 ++++++++++++++++++++++++++++++----------------
 influxdb.h        |   1 +
 openweathermap.h  |  34 +++++---
 structs.h         |  24 ++++--
 weatherstation.db | Bin 552960 -> 552960 bytes
 7 files changed, 238 insertions(+), 122 deletions(-)

diff --git a/MqttClient.h b/MqttClient.h
index bda20d2..0708316 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 8963d22..b1f07ee 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 6bb7667..ff71ca5 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 380f744..be8029f 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 49bf4f1..d33fb0d 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 5084c67..63e03d4 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
GIT binary patch
delta 1293
zcmb``$y3u%9Ki9=KucTTQ56c}62OHW+CTw!ma0{#VN+b8B`Kh_Ae2Q=%c6BWiR1s^
zc!q<21pW_l@t_`hV#XORe&Yx_gANxn^LcqmetGYg-+NiuC|=koUMX@_NRspt=~zbo
zn<_Q0LaHen&CdBO$<CCNwd_pgd~<&P;2O-FcP18HR-3!FHf^yh9tuZ|Nh2N~jSWu@
zL?*^!aU-Vhx{=Y=?QiMzE4?kP9e$-`*YgrbnZv&Qc0gCALlZ+Ip@}MoeLOn1edVZ9
zqOsw&F+I=NzNP3!Bs3L`b1q+7&I(%+;+15zS{I9KHg^vRwv5JfV|LekJDCRbfvLZT
zSbnA47Yuau`ISJh-QTb5IZ(owb=b#Zy91T7-=9}bjc3gA75?|~RZ{(b*00<lwj^1s
zOJY-`#JahddE)I#?)$b<xzpYpYVd^(eaI6I>ydih6Rz`wb;GNwAvH1-@it}1B2AUe
z)@$JdGCU4iS)?SfWsbKq+Q-D7k?FFqdk8d-B_v^m4VkdR9LR|*WFrRxxo}}0_TvEZ
zkPkNsP>6#l!XX@%q=a;Y&QT~RMhQxB499T-Cs77-G0Y#J5>=>14Qf#bGkGsm)T04D
zG@=R3IEB+VgR{&pouhLe7tn%Mw4oh-T*M_@MgUiE6&>hA5Z9og3*G2JFZysDH_(rp
zxP{xegS*Tx-NOI|5keS4&|x5gVT@oD_wfKxJVXp*7{?<_U=ndmVHz`-#beB29#2sH
zl;#=CL>91!B`o7PUO<M$v{vB#lASF!*-ERDSQTHzr=6|zI#`*O-syJjwKba?>l;+v
zu*<S=s|`M{ui0*)>-E*Es=0nnx94Zbl9trclA0x{$w@6esbwTJYf`hl(=wGG!6FRL

delta 7361
zcmdT}iGNd7_D^2+<-JFnwrRSMgsy2?=*!E?OBBR{2#Ty_aT&n0eQ9IU6p~aB#Q0#`
zSF9R0P{iF)25}iTltD!XTo7>iISlf1M4g`-GXDHII^%rrdrceA`2&9ad~zP|e82bJ
zbI&>V+<PCFe&oIMBkzrsMWZzu%@z3N|LAqiykoRxY-5~;N@riIVHYx=*w=0?8dYT9
zy4K!7WtUPWXJw^U7BkU~gtRoVa!G$GGxX3+o;#&&-W1Qgwn=AA@eC=gjaEy4x^GFm
z%M(v#nynV-Jr_n(ojuVM-q5<>tz#hBC8ZP5WLI8k^~v>Glau4L@^TEBO-Re7Xr@O>
zE$Qq}cEvOC{$%=>8tOPpeu)#KhT9LB=1KNvJjsDX0#@}!<H@`Qh5D|nl<rK$my%(B
zfm?mF`ALmvp6+H3uv^(H*=}|gJC?OD?=!z=E@c)mCMHC$pg*T)&>s5{`UU$Ydpo_+
z9<)1b-`RHC*VxwE`fX#))2**qAF^I<U2GMt|FYUFA6uTZ++zL0(r#I8X)CcUv5d1g
zEn55A=FiN3G~aAao0lLw2Ta*wx1MsjsB_vody<l*%3_h|bhQin6TMP$lGG*jX51m@
zcwLREYa57lOR0D|EhQz7sv0eT!0E=QZwsW96i=>{5}7=1S*Bs~8KcqE2Em@7^JZ20
z6gX~aG@2Uf%hSklEdim<=j8QNX@kx)JrPZjpOo@Ui}&?Oi4smvIo&#4duAZjw=kaU
z>gboGWLYb;HPk=a(w#lhf`LSDG#MrT95oJlC-uW=1Icto5u;iZ%_rHJQiqgKM44Y{
zymy4uo#^lEl`NJAH5MZ5dGpJf73PNuvpo|X=vW?4p_@@YrPCJ`l_IQ1G-OSve=Uue
z^DHVk<myZ`)hlIF9vB!MkW$f9CJvu^R5TV%B<dT$Z=?E#`2UIKX{rbB3@V}W&XVGt
zJsEWLtNqs1f;*Aw&U3Rv<hfF}l=NU74UJ!4ql`V25Mck(#FWxx40r<7mG5t;JM~pz
zRCvMgQJt!4YAQOgR7#}P4o7>k06FSh6@<&+l0p~Q=Gdw<MvZ1vlj7N(bE5;DJ&LHR
zL(3MbM{Rkc`L=dVv8!}AtCRi9-J`+hsk2r7u#>XtJ8?JDXwTR)BT;6?BKJzEuiH^q
z$gjB?Hq4?N%2-$cE8|j+gu;{ZM2~lmLTIj1*jDAGUFtzRhGv&8WF!6xqp<??sgzlH
z8Mf{?>JYQa1?D*I&kA#@6ifB@q_7HyP<J^{LHmCSI%P#BCG`yttmvwpAaL66m6vuY
zTVR-?swf5S*M6tG%!o?qw33y|t9_dWPI|d;9lI;Zc$7u$u5e~U2DwT=@M-_95QZnF
zyfKYTW45p}rm-ZTrz$IT^t}F5GTPNY^avO0shab&C$%q4?RWvRMXLU1k0O0WX#OI!
zY|};xR0w!ME@unbzENOL(1r`yg^`;Xm(o%~8NZGJRnUeCsKb*hplLL&GG+e%tIT+s
z6jK+u^5%EwsVuB(E9m5S>pTTrRk0YcMk^MO3(#^q&`NE~FVN&j(H*HonmSrBe{6ep
z#8(9_O?#5cRFhsCcrDuIf^LVVIZPRA)l=0oG@nhCmd7)wJNc)lFP<4ny}rVE)LX!x
zp!rngWlv~OFr{&35NBzQ<U7nim5vi?mFpwn8$gUmPSlvtK-3(}6ARX8+LKqhjUbKF
z>>qm1rr`1A*sMkvWd<;+HT&`{@=v#3Y57k6eb^Csg--{<WX+%Q@A;=<aE}`LK6SZ!
zC{Q`guBq8y^O}+!KCRN*>-k>t&*P`BPz~5$*4V!zyUgY6kL-8s*X-x)$LvA&J$5g<
zn|+miiG3DFi^tdp*^TU->@DmK>{aYqb~U@4%`RhmS&3c3p2N1YGuWwY8+$S<u;W-C
zTf<hfPPT}(u?FU6<_G2&^Cj~sbC~&%Il#Qd>|%B>FEY<CTbM_g`<c6$+nGV;I_3&S
zW>zr+Og|H6I&pSc$jo7;GgFv}OoZW?7N&vmGL=jz!!i~|NB@)lK0zO)|A+pBK16>&
z@1x(KchcMG=jo^D&Gf_cCVD-cqu0^b(3jC!`XV|__tD*Sls=E1PtT&ypeNH4Xp!b<
zKV3(=X&3FFY1%|<?LXST>+6tG-A$4~=d9tH_PrGj^PJcg&u!eGuXOmjp!RZ1>}oMA
z@_ZY%tlTW#Sl;C71mJQpQ}p3bP>c`&r=RFWQYz`|P}(%z^^M4Ltz7Q<)6G@0#zdj?
zyO<4+M1n#<;YU3e_NV$h3!{lHwPD5i;8eP(74dLL5IE8&b_*42Spv+*m9EeRgm73G
zYz=s}dIS5dS;X<Ozs`dE?Z^F)Yd<C{cg=q{L&}HGfV}jhC6L)emq1=}h@8h)|0N80
z@xcX<tNxsVT>0lB$csKCtycUOX|?==F31btzZi1h{W8eRdje$o-LoN62UbBYJ5a8{
z_)GT_pnu<d$mBcAAp71S-6i%0Aba1Q3wgm?L?3^P=zHEA2ig6`49M7?UPx(=9<pn<
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
Gx&IB-F)V@r

-- 
GitLab