From daea5f93cce848fc81d5a746c2f8977377a4546d Mon Sep 17 00:00:00 2001
From: "de@itstall.de" <de@itstall.de>
Date: Mon, 27 Jan 2020 14:37:14 +0100
Subject: [PATCH] Initial commit

---
 .gitignore              |   5 +
 backend.cpp             |  58 ++++
 header/dbSqlite.h       |  94 ++++++
 header/influxdb.h       | 320 ++++++++++++++++++++
 header/json.h           | 646 ++++++++++++++++++++++++++++++++++++++++
 header/openweathermap.h | 196 ++++++++++++
 6 files changed, 1319 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 backend.cpp
 create mode 100644 header/dbSqlite.h
 create mode 100644 header/influxdb.h
 create mode 100644 header/json.h
 create mode 100644 header/openweathermap.h

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2c31b73
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+################################################################################
+# Diese .gitignore-Datei wurde von Microsoft(R) Visual Studio automatisch erstellt.
+################################################################################
+
+/.vs
diff --git a/backend.cpp b/backend.cpp
new file mode 100644
index 0000000..fbb0aa9
--- /dev/null
+++ b/backend.cpp
@@ -0,0 +1,58 @@
+#include <iostream>
+#include <thread>
+#include "openweathermap.h"
+#include "dbSqlite.h"
+#include <vector>
+
+using namespace std;
+
+dbSqlite* db;
+
+void schedulerWeather(int time) {
+    std::cout << "Wetterstation::schedulerWeather" << std::endl;
+    while (1) {
+        openweathermap owmw;
+
+        owmw.getWeather(db->getSettings().owm_plz, db->getSettings().owm_lngCode);
+        Sleep(time);
+    }
+}
+
+void schedulerForecast(int time) {
+    std::cout << "Wetterstation::schedulerForecast" << std::endl;
+    while (1) {
+        openweathermap owmw;
+
+        owmw.getForecast(db->getSettings().owm_plz, db->getSettings().owm_lngCode);
+        Sleep(time);
+    }
+}
+
+int main() {
+    std::cout << "Wetterstation::main" << std::endl;
+    WSADATA wsaData;
+
+    int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
+    if (iResult != 0) {
+        printf("WSAStartup failed: %d\n", iResult);
+        return 1;
+    }
+
+    db = new dbSqlite();
+
+    std::thread thrWeather{ schedulerWeather, 60000 };
+    Sleep(50);
+    std::thread thrForecast{ schedulerForecast, 900000 };
+
+    std::vector<WeatherConditions> cond = db->getConditions();
+
+    /*for (int i = 0; i < cond.size(); i++) {
+        cout << cond[i].condition_id << endl;
+        cout << cond[i].description << endl;
+        cout << "------------------------" << endl;
+    }*/
+
+    while (1) {
+        Sleep(1000);
+    }
+}
\ No newline at end of file
diff --git a/header/dbSqlite.h b/header/dbSqlite.h
new file mode 100644
index 0000000..696fefa
--- /dev/null
+++ b/header/dbSqlite.h
@@ -0,0 +1,94 @@
+#pragma once
+#include <iostream>
+#include <string>
+#include <vector>
+#include "Poco/Data/Session.h"
+#include "Poco/Data/SQLite/Connector.h"
+
+using namespace Poco::Data::Keywords;
+using Poco::Data::Session;
+using Poco::Data::Statement;
+using std::string;
+using std::cout;
+
+struct WeatherConditions {
+    int condition_id;
+    std::string main;
+    std::string description;
+};
+
+struct Settings {
+    std::string owm_appid;
+    std::string owm_plz;
+    std::string owm_lngCode;
+    std::string influx_host;
+    int influx_port;
+    std::string influx_db;
+    std::string influx_user;
+    std::string influx_pass;
+};
+
+class dbSqlite {
+private:
+    std::vector<WeatherConditions> weatherConditions;
+    Settings settings;
+
+public:
+    string dbFile;
+
+    dbSqlite() {
+        std::cout << "sbSqlite()" << std::endl;
+        Poco::Data::SQLite::Connector::registerConnector();
+        this->dbFile = "weatherstation.db";
+        this->weatherConditions = this->queryConditions();
+        this->querySettings();
+    };
+
+    Settings getSettings() {
+        std::cout << "dbSqlite::getSettings()" << std::endl;
+        std::cout << "owm_plz: " << this->settings.owm_plz << std::endl;
+        return this->settings;
+    }
+
+    std::vector<WeatherConditions> getConditions() {
+        return this->weatherConditions;
+    }
+
+    void querySettings() {
+        std::cout << "dbSqlite::querySettings()" << std::endl;
+        Session session("SQLite", this->dbFile);
+
+        Statement select(session);
+        select << "SELECT * FROM settings LIMIT 1;",
+            into(this->settings.owm_appid),
+            into(this->settings.owm_plz),
+            into(this->settings.owm_lngCode),
+            into(this->settings.influx_host),
+            into(this->settings.influx_port),
+            into(this->settings.influx_db),
+            into(this->settings.influx_user),
+            into(this->settings.influx_pass),
+            range(0, 1); // iterate over result set one row at a time
+        select.execute();
+    }
+
+    std::vector<WeatherConditions> queryConditions() {
+        std::cout << "dbSqlite::queryConditions()" << std::endl;
+        Session session("SQLite", this->dbFile);
+        WeatherConditions wc;
+
+        Statement select(session);
+        select << "SELECT * FROM weather_conditions;",
+            into(wc.condition_id),
+            into(wc.main),
+            into(wc.description),
+            range(0, 1); // iterate over result set one row at a time
+
+        while (!select.done()) {
+            select.execute();
+            weatherConditions.push_back(wc);
+        }
+
+        return weatherConditions;
+    }
+};
\ No newline at end of file
diff --git a/header/influxdb.h b/header/influxdb.h
new file mode 100644
index 0000000..9c0c57d
--- /dev/null
+++ b/header/influxdb.h
@@ -0,0 +1,320 @@
+/*
+  influxdb-cpp -- 💜 C++ client for InfluxDB.
+
+  Copyright (c) 2010-2018 <http://ez8.co> <orca.zhang@yahoo.com>
+  This library is released under the MIT License.
+
+  Please see LICENSE file or visit https://github.com/orca-zhang/influxdb-cpp for details.
+ */
+#include <sstream>
+#include <cstring>
+#include <cstdio>
+#include <cstdlib>
+
+#ifdef _WIN32
+#define NOMINMAX
+#include <windows.h>
+#include <algorithm>
+#pragma comment(lib, "ws2_32")
+#pragma warning(disable:4996)
+typedef struct iovec { void* iov_base; size_t iov_len; } iovec;
+inline __int64 writev(int sock, struct iovec* iov, int cnt) {
+    __int64 r = send(sock, (const char*)iov->iov_base, iov->iov_len, 0);
+    return (r < 0 || cnt == 1) ? r : r + writev(sock, iov + 1, cnt - 1);
+}
+#else
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#define closesocket close
+#endif
+
+namespace influxdb_cpp {
+    struct server_info {
+        std::string host_;
+        int port_;
+        std::string db_;
+        std::string usr_;
+        std::string pwd_;
+        std::string precision_;
+        server_info(const std::string& host, int port, const std::string& db = "", const std::string& usr = "", const std::string& pwd = "") {
+            port_ = port;
+            db_ = db;
+            usr_ = usr;
+            pwd_ = pwd;
+
+            //convert hostname to ip-address
+            hostent* record = gethostbyname(host.c_str());
+            if (record == NULL) {
+                printf("Cannot resolve IP address from hostname: %s is unavailable. Try to ping the host.\n", host.c_str());
+                std::exit(-1);
+            }
+            in_addr* address = (in_addr*)record->h_addr;
+            std::string ip_address = inet_ntoa(*address);
+
+            host_ = ip_address;
+        }
+    };
+    namespace detail {
+        struct meas_caller;
+        struct tag_caller;
+        struct field_caller;
+        struct ts_caller;
+        struct inner {
+            static int http_request(const char*, const char*, const std::string&, const std::string&, const server_info&, std::string*);
+            static inline unsigned char to_hex(unsigned char x) { return  x > 9 ? x + 55 : x + 48; }
+            static void url_encode(std::string& out, const std::string& src);
+        };
+    }
+
+    inline int query(std::string& resp, const std::string& query, const server_info& si) {
+        std::string qs("&q=");
+        detail::inner::url_encode(qs, query);
+        return detail::inner::http_request("GET", "query", qs, "", si, &resp);
+    }
+    inline int create_db(std::string& resp, const std::string& db_name, const server_info& si) {
+        std::string qs("&q=create+database+");
+        detail::inner::url_encode(qs, db_name);
+        return detail::inner::http_request("POST", "query", qs, "", si, &resp);
+    }
+
+    struct builder {
+        detail::tag_caller& meas(const std::string& m) {
+            lines_.imbue(std::locale("C"));
+            lines_.clear();
+            return _m(m);
+        }
+    protected:
+        detail::tag_caller& _m(const std::string& m) {
+            _escape(m, ", ");
+            return (detail::tag_caller&) * this;
+        }
+        detail::tag_caller& _t(const std::string& k, const std::string& v) {
+            lines_ << ',';
+            _escape(k, ",= ");
+            lines_ << '=';
+            _escape(v, ",= ");
+            return (detail::tag_caller&) * this;
+        }
+        detail::field_caller& _f_s(char delim, const std::string& k, const std::string& v) {
+            lines_ << delim;
+            _escape(k, ",= ");
+            lines_ << "=\"";
+            _escape(v, "\"");
+            lines_ << '\"';
+            return (detail::field_caller&) * this;
+        }
+        detail::field_caller& _f_i(char delim, const std::string& k, long long v) {
+            lines_ << delim;
+            _escape(k, ",= ");
+            lines_ << '=';
+            lines_ << v << 'i';
+            return (detail::field_caller&) * this;
+        }
+        detail::field_caller& _f_f(char delim, const std::string& k, double v, int prec) {
+            lines_ << delim;
+            _escape(k, ",= ");
+            lines_.precision(prec);
+            lines_ << '=' << v;
+            return (detail::field_caller&) * this;
+        }
+        detail::field_caller& _f_b(char delim, const std::string& k, bool v) {
+            lines_ << delim;
+            _escape(k, ",= ");
+            lines_ << '=' << (v ? 't' : 'f');
+            return (detail::field_caller&) * this;
+        }
+        detail::ts_caller& _ts(long long ts) {
+            lines_ << ' ' << ts;
+            return (detail::ts_caller&) * this;
+        }
+        int _post_http(const server_info& si, std::string* resp) {
+            return detail::inner::http_request("POST", "write", "", lines_.str(), si, resp);
+        }
+        int _send_udp(const std::string& host, int port) {
+            int sock, ret = 0;
+            struct sockaddr_in addr;
+
+            addr.sin_family = AF_INET;
+            addr.sin_port = htons(port);
+            if ((addr.sin_addr.s_addr = inet_addr(host.c_str())) == INADDR_NONE) return -1;
+
+            if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) return -2;
+
+            lines_ << '\n';
+            if (sendto(sock, &lines_.str()[0], lines_.str().length(), 0, (struct sockaddr*) & addr, sizeof(addr)) < (int)lines_.str().length())
+                ret = -3;
+
+            closesocket(sock);
+            return ret;
+        }
+        void _escape(const std::string& src, const char* escape_seq) {
+            size_t pos = 0, start = 0;
+            while ((pos = src.find_first_of(escape_seq, start)) != std::string::npos) {
+                lines_.write(src.c_str() + start, pos - start);
+                lines_ << '\\' << src[pos];
+                start = ++pos;
+            }
+            lines_.write(src.c_str() + start, src.length() - start);
+        }
+
+        std::stringstream lines_;
+    };
+
+    namespace detail {
+        struct tag_caller : public builder {
+            detail::tag_caller& tag(const std::string& k, const std::string& v) { return _t(k, v); }
+            detail::field_caller& field(const std::string& k, const std::string& v) { return _f_s(' ', k, v); }
+            detail::field_caller& field(const std::string& k, bool v) { return _f_b(' ', k, v); }
+            detail::field_caller& field(const std::string& k, short v) { return _f_i(' ', k, v); }
+            detail::field_caller& field(const std::string& k, int v) { return _f_i(' ', k, v); }
+            detail::field_caller& field(const std::string& k, long v) { return _f_i(' ', k, v); }
+            detail::field_caller& field(const std::string& k, long long v) { return _f_i(' ', k, v); }
+            detail::field_caller& field(const std::string& k, double v, int prec = 2) { return _f_f(' ', k, v, prec); }
+        private:
+            detail::tag_caller& meas(const std::string& m);
+        };
+        struct ts_caller : public builder {
+            detail::tag_caller& meas(const std::string& m) { lines_ << '\n'; return _m(m); }
+            int post_http(const server_info& si, std::string* resp = NULL) { return _post_http(si, resp); }
+            int send_udp(const std::string& host, int port) { return _send_udp(host, port); }
+        };
+        struct field_caller : public ts_caller {
+            detail::field_caller& field(const std::string& k, const std::string& v) { return _f_s(',', k, v); }
+            detail::field_caller& field(const std::string& k, bool v) { return _f_b(',', k, v); }
+            detail::field_caller& field(const std::string& k, short v) { return _f_i(',', k, v); }
+            detail::field_caller& field(const std::string& k, int v) { return _f_i(',', k, v); }
+            detail::field_caller& field(const std::string& k, long v) { return _f_i(',', k, v); }
+            detail::field_caller& field(const std::string& k, long long v) { return _f_i(',', k, v); }
+            detail::field_caller& field(const std::string& k, double v, int prec = 2) { return _f_f(',', k, v, prec); }
+            detail::ts_caller& timestamp(unsigned long long ts) { return _ts(ts); }
+        };
+        inline void inner::url_encode(std::string& out, const std::string& src) {
+            size_t pos = 0, start = 0;
+            while ((pos = src.find_first_not_of("abcdefghijklmnopqrstuvwxyqABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~", start)) != std::string::npos) {
+                out.append(src.c_str() + start, pos - start);
+                if (src[pos] == ' ')
+                    out += "+";
+                else {
+                    out += '%';
+                    out += to_hex((unsigned char)src[pos] >> 4);
+                    out += to_hex((unsigned char)src[pos] & 0xF);
+                }
+                start = ++pos;
+            }
+            out.append(src.c_str() + start, src.length() - start);
+        }
+        inline int inner::http_request(const char* method, const char* uri,
+            const std::string& querystring, const std::string& body, const server_info& si, std::string* resp) {
+            std::string header;
+            struct iovec iv[2];
+            struct sockaddr_in addr;
+            int sock, ret_code = 0, content_length = 0, len = 0;
+            char ch;
+            unsigned char chunked = 0;
+
+            addr.sin_family = AF_INET;
+            addr.sin_port = htons(si.port_);
+            if ((addr.sin_addr.s_addr = inet_addr(si.host_.c_str())) == INADDR_NONE) return -1;
+
+            if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) return -2;
+
+            if (connect(sock, (struct sockaddr*)(&addr), sizeof(addr)) < 0) {
+                closesocket(sock);
+                return -3;
+            }
+
+            header.resize(len = 0x100);
+
+            for (;;) {
+                iv[0].iov_len = snprintf(&header[0], len,
+                    "%s /%s?db=%s&u=%s&p=%s&precision=%s%s HTTP/1.1\r\nHost: %s\r\nContent-Length: %d\r\n\r\n",
+                    method, uri, si.db_.c_str(), si.usr_.c_str(), si.pwd_.c_str(), si.precision_.c_str(),
+                    querystring.c_str(), si.host_.c_str(), (int)body.length());
+                if ((int)iv[0].iov_len >= len)
+                    header.resize(len *= 2);
+                else
+                    break;
+            }
+            iv[0].iov_base = &header[0];
+            iv[1].iov_base = (void*)&body[0];
+            iv[1].iov_len = body.length();
+
+            if (writev(sock, iv, 2) < (int)(iv[0].iov_len + iv[1].iov_len)) {
+                ret_code = -6;
+                goto END;
+            }
+
+            iv[0].iov_len = len;
+
+#define _NO_MORE() (len >= (int)iv[0].iov_len && \
+    (iv[0].iov_len = recv(sock, &header[0], header.length(), len = 0)) == size_t(-1))
+#define _GET_NEXT_CHAR() (ch = _NO_MORE() ? 0 : header[len++])
+#define _LOOP_NEXT(statement) for(;;) { if(!(_GET_NEXT_CHAR())) { ret_code = -7; goto END; } statement }
+#define _UNTIL(c) _LOOP_NEXT( if(ch == c) break; )
+#define _GET_NUMBER(n) _LOOP_NEXT( if(ch >= '0' && ch <= '9') n = n * 10 + (ch - '0'); else break; )
+#define _GET_CHUNKED_LEN(n, c) _LOOP_NEXT( if(ch >= '0' && ch <= '9') n = n * 16 + (ch - '0'); \
+            else if(ch >= 'A' && ch <= 'F') n = n * 16 + (ch - 'A') + 10; \
+            else if(ch >= 'a' && ch <= 'f') n = n * 16 + (ch - 'a') + 10; else {if(ch != c) { ret_code = -8; goto END; } break;} )
+#define _(c) if((_GET_NEXT_CHAR()) != c) break;
+#define __(c) if((_GET_NEXT_CHAR()) != c) { ret_code = -9; goto END; }
+
+            if (resp) resp->clear();
+
+            _UNTIL(' ')_GET_NUMBER(ret_code)
+                for (;;) {
+                    _UNTIL('\n')
+                        switch (_GET_NEXT_CHAR()) {
+                        case 'C':_('o')_('n')_('t')_('e')_('n')_('t')_('-')
+                            _('L')_('e')_('n')_('g')_('t')_('h')_(':')_(' ')
+                            _GET_NUMBER(content_length)
+                            break;
+                        case 'T':_('r')_('a')_('n')_('s')_('f')_('e')_('r')_('-')
+                            _('E')_('n')_('c')_('o')_('d')_('i')_('n')_('g')_(':')
+                            _(' ')_('c')_('h')_('u')_('n')_('k')_('e')_('d')
+                            chunked = 1;
+                            break;
+                        case '\r':__('\n')
+                            switch (chunked) {
+                                do {
+                                    __('\r')__('\n')
+                            case 1:
+                                _GET_CHUNKED_LEN(content_length, '\r')__('\n')
+                                    if (!content_length) {
+                                        __('\r')__('\n')
+                                            goto END;
+                                    }
+                            case 0:
+                                while (content_length > 0 && !_NO_MORE()) {
+                                    content_length -= (iv[1].iov_len = (content_length < ((int)iv[0].iov_len - len) ? content_length : ((int)iv[0].iov_len - len)));
+                                    if (resp) resp->append(&header[len], iv[1].iov_len);
+                                    len += iv[1].iov_len;
+                                }
+                                } while (chunked);
+                            }
+                                 goto END;
+                        }
+                    if (!ch) {
+                        ret_code = -10;
+                        goto END;
+                    }
+                }
+            ret_code = -11;
+        END:
+            closesocket(sock);
+            return ret_code / 100 == 2 ? 0 : ret_code;
+#undef _NO_MORE
+#undef _GET_NEXT_CHAR
+#undef _LOOP_NEXT
+#undef _UNTIL
+#undef _GET_NUMBER
+#undef _GET_CHUNKED_LEN
+#undef _
+#undef __
+        }
+    }
+}
\ No newline at end of file
diff --git a/header/json.h b/header/json.h
new file mode 100644
index 0000000..8676bd7
--- /dev/null
+++ b/header/json.h
@@ -0,0 +1,646 @@
+#pragma once
+
+#include <cstdint>
+#include <cmath>
+#include <cctype>
+#include <string>
+#include <deque>
+#include <map>
+#include <type_traits>
+#include <initializer_list>
+#include <ostream>
+#include <iostream>
+
+namespace json {
+
+    using std::map;
+    using std::deque;
+    using std::string;
+    using std::enable_if;
+    using std::initializer_list;
+    using std::is_same;
+    using std::is_convertible;
+    using std::is_integral;
+    using std::is_floating_point;
+
+    namespace {
+        string json_escape(const string& str) {
+            string output;
+            for (unsigned i = 0; i < str.length(); ++i)
+                switch (str[i]) {
+                case '\"': output += "\\\""; break;
+                case '\\': output += "\\\\"; break;
+                case '\b': output += "\\b";  break;
+                case '\f': output += "\\f";  break;
+                case '\n': output += "\\n";  break;
+                case '\r': output += "\\r";  break;
+                case '\t': output += "\\t";  break;
+                default: output += str[i]; break;
+                }
+            return std::move(output);
+        }
+    }
+
+    class JSON {
+        union BackingData {
+            BackingData(double d) : Float(d) {}
+            BackingData(long   l) : Int(l) {}
+            BackingData(bool   b) : Bool(b) {}
+            BackingData(string s) : String(new string(s)) {}
+            BackingData() : Int(0) {}
+
+            deque<JSON>* List;
+            map<string, JSON>* Map;
+            string* String;
+            double              Float;
+            long                Int;
+            bool                Bool;
+        } Internal;
+
+    public:
+        enum class Class {
+            Null,
+            Object,
+            Array,
+            String,
+            Floating,
+            Integral,
+            Boolean
+        };
+
+        template <typename Container>
+        class JSONWrapper {
+            Container* object;
+
+        public:
+            JSONWrapper(Container* val) : object(val) {}
+            JSONWrapper(std::nullptr_t) : object(nullptr) {}
+
+            typename Container::iterator begin() { return object ? object->begin() : typename Container::iterator(); }
+            typename Container::iterator end() { return object ? object->end() : typename Container::iterator(); }
+            typename Container::const_iterator begin() const { return object ? object->begin() : typename Container::iterator(); }
+            typename Container::const_iterator end() const { return object ? object->end() : typename Container::iterator(); }
+        };
+
+        template <typename Container>
+        class JSONConstWrapper {
+            const Container* object;
+
+        public:
+            JSONConstWrapper(const Container* val) : object(val) {}
+            JSONConstWrapper(std::nullptr_t) : object(nullptr) {}
+
+            typename Container::const_iterator begin() const { return object ? object->begin() : typename Container::const_iterator(); }
+            typename Container::const_iterator end() const { return object ? object->end() : typename Container::const_iterator(); }
+        };
+
+        JSON() : Internal(), Type(Class::Null) {}
+
+        JSON(initializer_list<JSON> list)
+            : JSON() {
+            SetType(Class::Object);
+            for (auto i = list.begin(), e = list.end(); i != e; ++i, ++i)
+                operator[](i->ToString()) = *std::next(i);
+        }
+
+        JSON(JSON&& other)
+            : Internal(other.Internal)
+            , Type(other.Type) {
+            other.Type = Class::Null; other.Internal.Map = nullptr;
+        }
+
+        JSON& operator=(JSON&& other) {
+            ClearInternal();
+            Internal = other.Internal;
+            Type = other.Type;
+            other.Internal.Map = nullptr;
+            other.Type = Class::Null;
+            return *this;
+        }
+
+        JSON(const JSON& other) {
+            switch (other.Type) {
+            case Class::Object:
+                Internal.Map =
+                    new map<string, JSON>(other.Internal.Map->begin(),
+                        other.Internal.Map->end());
+                break;
+            case Class::Array:
+                Internal.List =
+                    new deque<JSON>(other.Internal.List->begin(),
+                        other.Internal.List->end());
+                break;
+            case Class::String:
+                Internal.String =
+                    new string(*other.Internal.String);
+                break;
+            default:
+                Internal = other.Internal;
+            }
+            Type = other.Type;
+        }
+
+        JSON& operator=(const JSON& other) {
+            ClearInternal();
+            switch (other.Type) {
+            case Class::Object:
+                Internal.Map =
+                    new map<string, JSON>(other.Internal.Map->begin(),
+                        other.Internal.Map->end());
+                break;
+            case Class::Array:
+                Internal.List =
+                    new deque<JSON>(other.Internal.List->begin(),
+                        other.Internal.List->end());
+                break;
+            case Class::String:
+                Internal.String =
+                    new string(*other.Internal.String);
+                break;
+            default:
+                Internal = other.Internal;
+            }
+            Type = other.Type;
+            return *this;
+        }
+
+        ~JSON() {
+            switch (Type) {
+            case Class::Array:
+                delete Internal.List;
+                break;
+            case Class::Object:
+                delete Internal.Map;
+                break;
+            case Class::String:
+                delete Internal.String;
+                break;
+            default:;
+            }
+        }
+
+        template <typename T>
+        JSON(T b, typename enable_if<is_same<T, bool>::value>::type* = 0) : Internal(b), Type(Class::Boolean) {}
+
+        template <typename T>
+        JSON(T i, typename enable_if<is_integral<T>::value && !is_same<T, bool>::value>::type* = 0) : Internal((long)i), Type(Class::Integral) {}
+
+        template <typename T>
+        JSON(T f, typename enable_if<is_floating_point<T>::value>::type* = 0) : Internal((double)f), Type(Class::Floating) {}
+
+        template <typename T>
+        JSON(T s, typename enable_if<is_convertible<T, string>::value>::type* = 0) : Internal(string(s)), Type(Class::String) {}
+
+        JSON(std::nullptr_t) : Internal(), Type(Class::Null) {}
+
+        static JSON Make(Class type) {
+            JSON ret; ret.SetType(type);
+            return ret;
+        }
+
+        static JSON Load(const string&);
+
+        template <typename T>
+        void append(T arg) {
+            SetType(Class::Array); Internal.List->emplace_back(arg);
+        }
+
+        template <typename T, typename... U>
+        void append(T arg, U... args) {
+            append(arg); append(args...);
+        }
+
+        template <typename T>
+        typename enable_if<is_same<T, bool>::value, JSON&>::type operator=(T b) {
+            SetType(Class::Boolean); Internal.Bool = b; return *this;
+        }
+
+        template <typename T>
+        typename enable_if<is_integral<T>::value && !is_same<T, bool>::value, JSON&>::type operator=(T i) {
+            SetType(Class::Integral); Internal.Int = i; return *this;
+        }
+
+        template <typename T>
+        typename enable_if<is_floating_point<T>::value, JSON&>::type operator=(T f) {
+            SetType(Class::Floating); Internal.Float = f; return *this;
+        }
+
+        template <typename T>
+        typename enable_if<is_convertible<T, string>::value, JSON&>::type operator=(T s) {
+            SetType(Class::String); *Internal.String = string(s); return *this;
+        }
+
+        JSON& operator[](const string& key) {
+            SetType(Class::Object); return Internal.Map->operator[](key);
+        }
+
+        JSON& operator[](unsigned index) {
+            SetType(Class::Array);
+            if (index >= Internal.List->size()) Internal.List->resize(index + 1);
+            return Internal.List->operator[](index);
+        }
+
+        JSON& at(const string& key) {
+            return operator[](key);
+        }
+
+        const JSON& at(const string& key) const {
+            return Internal.Map->at(key);
+        }
+
+        JSON& at(unsigned index) {
+            return operator[](index);
+        }
+
+        const JSON& at(unsigned index) const {
+            return Internal.List->at(index);
+        }
+
+        int length() const {
+            if (Type == Class::Array)
+                return Internal.List->size();
+            else
+                return -1;
+        }
+
+        bool hasKey(const string& key) const {
+            if (Type == Class::Object)
+                return Internal.Map->find(key) != Internal.Map->end();
+            return false;
+        }
+
+        int size() const {
+            if (Type == Class::Object)
+                return Internal.Map->size();
+            else if (Type == Class::Array)
+                return Internal.List->size();
+            else
+                return -1;
+        }
+
+        Class JSONType() const { return Type; }
+
+        /// Functions for getting primitives from the JSON object.
+        bool IsNull() const { return Type == Class::Null; }
+
+        string ToString() const { bool b; return std::move(ToString(b)); }
+        string ToString(bool& ok) const {
+            ok = (Type == Class::String);
+            return ok ? std::move(json_escape(*Internal.String)) : string("");
+        }
+
+        double ToFloat() const { bool b; return ToFloat(b); }
+        double ToFloat(bool& ok) const {
+            ok = (Type == Class::Floating);
+            return ok ? Internal.Float : 0.0;
+        }
+
+        long ToInt() const { bool b; return ToInt(b); }
+        long ToInt(bool& ok) const {
+            ok = (Type == Class::Integral);
+            return ok ? Internal.Int : 0;
+        }
+
+        bool ToBool() const { bool b; return ToBool(b); }
+        bool ToBool(bool& ok) const {
+            ok = (Type == Class::Boolean);
+            return ok ? Internal.Bool : false;
+        }
+
+        JSONWrapper<map<string, JSON>> ObjectRange() {
+            if (Type == Class::Object)
+                return JSONWrapper<map<string, JSON>>(Internal.Map);
+            return JSONWrapper<map<string, JSON>>(nullptr);
+        }
+
+        JSONWrapper<deque<JSON>> ArrayRange() {
+            if (Type == Class::Array)
+                return JSONWrapper<deque<JSON>>(Internal.List);
+            return JSONWrapper<deque<JSON>>(nullptr);
+        }
+
+        JSONConstWrapper<map<string, JSON>> ObjectRange() const {
+            if (Type == Class::Object)
+                return JSONConstWrapper<map<string, JSON>>(Internal.Map);
+            return JSONConstWrapper<map<string, JSON>>(nullptr);
+        }
+
+
+        JSONConstWrapper<deque<JSON>> ArrayRange() const {
+            if (Type == Class::Array)
+                return JSONConstWrapper<deque<JSON>>(Internal.List);
+            return JSONConstWrapper<deque<JSON>>(nullptr);
+        }
+
+        string dump(int depth = 1, string tab = "  ") const {
+            string pad = "";
+            for (int i = 0; i < depth; ++i, pad += tab);
+
+            switch (Type) {
+            case Class::Null:
+                return "null";
+            case Class::Object: {
+                string s = "{\n";
+                bool skip = true;
+                for (auto& p : *Internal.Map) {
+                    if (!skip) s += ",\n";
+                    s += (pad + "\"" + p.first + "\" : " + p.second.dump(depth + 1, tab));
+                    skip = false;
+                }
+                s += ("\n" + pad.erase(0, 2) + "}");
+                return s;
+            }
+            case Class::Array: {
+                string s = "[";
+                bool skip = true;
+                for (auto& p : *Internal.List) {
+                    if (!skip) s += ", ";
+                    s += p.dump(depth + 1, tab);
+                    skip = false;
+                }
+                s += "]";
+                return s;
+            }
+            case Class::String:
+                return "\"" + json_escape(*Internal.String) + "\"";
+            case Class::Floating:
+                return std::to_string(Internal.Float);
+            case Class::Integral:
+                return std::to_string(Internal.Int);
+            case Class::Boolean:
+                return Internal.Bool ? "true" : "false";
+            default:
+                return "";
+            }
+            return "";
+        }
+
+        friend std::ostream& operator<<(std::ostream&, const JSON&);
+
+    private:
+        void SetType(Class type) {
+            if (type == Type)
+                return;
+
+            ClearInternal();
+
+            switch (type) {
+            case Class::Null:      Internal.Map = nullptr;                break;
+            case Class::Object:    Internal.Map = new map<string, JSON>(); break;
+            case Class::Array:     Internal.List = new deque<JSON>();     break;
+            case Class::String:    Internal.String = new string();           break;
+            case Class::Floating:  Internal.Float = 0.0;                    break;
+            case Class::Integral:  Internal.Int = 0;                      break;
+            case Class::Boolean:   Internal.Bool = false;                  break;
+            }
+
+            Type = type;
+        }
+
+    private:
+        /* beware: only call if YOU know that Internal is allocated. No checks performed here.
+           This function should be called in a constructed JSON just before you are going to
+          overwrite Internal...
+        */
+        void ClearInternal() {
+            switch (Type) {
+            case Class::Object: delete Internal.Map;    break;
+            case Class::Array:  delete Internal.List;   break;
+            case Class::String: delete Internal.String; break;
+            default:;
+            }
+        }
+
+    private:
+
+        Class Type = Class::Null;
+    };
+
+    JSON Array() {
+        return std::move(JSON::Make(JSON::Class::Array));
+    }
+
+    template <typename... T>
+    JSON Array(T... args) {
+        JSON arr = JSON::Make(JSON::Class::Array);
+        arr.append(args...);
+        return std::move(arr);
+    }
+
+    JSON Object() {
+        return std::move(JSON::Make(JSON::Class::Object));
+    }
+
+    std::ostream& operator<<(std::ostream& os, const JSON& json) {
+        os << json.dump();
+        return os;
+    }
+
+    namespace {
+        JSON parse_next(const string&, size_t&);
+
+        void consume_ws(const string& str, size_t& offset) {
+            while (isspace(str[offset])) ++offset;
+        }
+
+        JSON parse_object(const string& str, size_t& offset) {
+            JSON Object = JSON::Make(JSON::Class::Object);
+
+            ++offset;
+            consume_ws(str, offset);
+            if (str[offset] == '}') {
+                ++offset; return std::move(Object);
+            }
+
+            while (true) {
+                JSON Key = parse_next(str, offset);
+                consume_ws(str, offset);
+                if (str[offset] != ':') {
+                    std::cerr << "Error: Object: Expected colon, found '" << str[offset] << "'\n";
+                    break;
+                }
+                consume_ws(str, ++offset);
+                JSON Value = parse_next(str, offset);
+                Object[Key.ToString()] = Value;
+
+                consume_ws(str, offset);
+                if (str[offset] == ',') {
+                    ++offset; continue;
+                }
+                else if (str[offset] == '}') {
+                    ++offset; break;
+                }
+                else {
+                    std::cerr << "ERROR: Object: Expected comma, found '" << str[offset] << "'\n";
+                    break;
+                }
+            }
+
+            return std::move(Object);
+        }
+
+        JSON parse_array(const string& str, size_t& offset) {
+            JSON Array = JSON::Make(JSON::Class::Array);
+            unsigned index = 0;
+
+            ++offset;
+            consume_ws(str, offset);
+            if (str[offset] == ']') {
+                ++offset; return std::move(Array);
+            }
+
+            while (true) {
+                Array[index++] = parse_next(str, offset);
+                consume_ws(str, offset);
+
+                if (str[offset] == ',') {
+                    ++offset; continue;
+                }
+                else if (str[offset] == ']') {
+                    ++offset; break;
+                }
+                else {
+                    std::cerr << "ERROR: Array: Expected ',' or ']', found '" << str[offset] << "'\n";
+                    return std::move(JSON::Make(JSON::Class::Array));
+                }
+            }
+
+            return std::move(Array);
+        }
+
+        JSON parse_string(const string& str, size_t& offset) {
+            JSON String;
+            string val;
+            for (char c = str[++offset]; c != '\"'; c = str[++offset]) {
+                if (c == '\\') {
+                    switch (str[++offset]) {
+                    case '\"': val += '\"'; break;
+                    case '\\': val += '\\'; break;
+                    case '/': val += '/'; break;
+                    case 'b': val += '\b'; break;
+                    case 'f': val += '\f'; break;
+                    case 'n': val += '\n'; break;
+                    case 'r': val += '\r'; break;
+                    case 't': val += '\t'; break;
+                    case 'u': {
+                        val += "\\u";
+                        for (unsigned i = 1; i <= 4; ++i) {
+                            c = str[offset + i];
+                            if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
+                                val += c;
+                            else {
+                                std::cerr << "ERROR: String: Expected hex character in unicode escape, found '" << c << "'\n";
+                                return std::move(JSON::Make(JSON::Class::String));
+                            }
+                        }
+                        offset += 4;
+                    } break;
+                    default: val += '\\'; break;
+                    }
+                }
+                else
+                    val += c;
+            }
+            ++offset;
+            String = val;
+            return std::move(String);
+        }
+
+        JSON parse_number(const string& str, size_t& offset) {
+            JSON Number;
+            string val, exp_str;
+            char c;
+            bool isDouble = false;
+            long exp = 0;
+            while (true) {
+                c = str[offset++];
+                if ((c == '-') || (c >= '0' && c <= '9'))
+                    val += c;
+                else if (c == '.') {
+                    val += c;
+                    isDouble = true;
+                }
+                else
+                    break;
+            }
+            if (c == 'E' || c == 'e') {
+                c = str[offset++];
+                if (c == '-') { ++offset; exp_str += '-'; }
+                while (true) {
+                    c = str[offset++];
+                    if (c >= '0' && c <= '9')
+                        exp_str += c;
+                    else if (!isspace(c) && c != ',' && c != ']' && c != '}') {
+                        std::cerr << "ERROR: Number: Expected a number for exponent, found '" << c << "'\n";
+                        return std::move(JSON::Make(JSON::Class::Null));
+                    }
+                    else
+                        break;
+                }
+                exp = std::stol(exp_str);
+            }
+            else if (!isspace(c) && c != ',' && c != ']' && c != '}') {
+                std::cerr << "ERROR: Number: unexpected character '" << c << "'\n";
+                return std::move(JSON::Make(JSON::Class::Null));
+            }
+            --offset;
+
+            if (isDouble)
+                Number = std::stod(val) * std::pow(10, exp);
+            else {
+                if (!exp_str.empty())
+                    Number = std::stol(val) * std::pow(10, exp);
+                else
+                    Number = std::stol(val);
+            }
+            return std::move(Number);
+        }
+
+        JSON parse_bool(const string& str, size_t& offset) {
+            JSON Bool;
+            if (str.substr(offset, 4) == "true")
+                Bool = true;
+            else if (str.substr(offset, 5) == "false")
+                Bool = false;
+            else {
+                std::cerr << "ERROR: Bool: Expected 'true' or 'false', found '" << str.substr(offset, 5) << "'\n";
+                return std::move(JSON::Make(JSON::Class::Null));
+            }
+            offset += (Bool.ToBool() ? 4 : 5);
+            return std::move(Bool);
+        }
+
+        JSON parse_null(const string& str, size_t& offset) {
+            JSON Null;
+            if (str.substr(offset, 4) != "null") {
+                std::cerr << "ERROR: Null: Expected 'null', found '" << str.substr(offset, 4) << "'\n";
+                return std::move(JSON::Make(JSON::Class::Null));
+            }
+            offset += 4;
+            return std::move(Null);
+        }
+
+        JSON parse_next(const string& str, size_t& offset) {
+            char value;
+            consume_ws(str, offset);
+            value = str[offset];
+            switch (value) {
+            case '[': return std::move(parse_array(str, offset));
+            case '{': return std::move(parse_object(str, offset));
+            case '\"': return std::move(parse_string(str, offset));
+            case 't':
+            case 'f': return std::move(parse_bool(str, offset));
+            case 'n': return std::move(parse_null(str, offset));
+            default: if ((value <= '9' && value >= '0') || value == '-')
+                return std::move(parse_number(str, offset));
+            }
+            std::cerr << "ERROR: Parse: Unknown starting character '" << value << "'\n";
+            return JSON();
+        }
+    }
+
+    JSON JSON::Load(const string& str) {
+        size_t offset = 0;
+        return std::move(parse_next(str, offset));
+    }
+}
\ No newline at end of file
diff --git a/header/openweathermap.h b/header/openweathermap.h
new file mode 100644
index 0000000..47155ed
--- /dev/null
+++ b/header/openweathermap.h
@@ -0,0 +1,196 @@
+#pragma once
+#include <iostream>
+#include <sstream>
+#include <vector>
+
+#include "Poco/Data/Session.h"
+#include "Poco/Data/SQLite/Connector.h"
+#include <Poco/JSON/JSON.h>
+#include <Poco/JSON/Parser.h>
+#include <Poco/Dynamic/Var.h>
+#include <Poco/URI.h>
+#include <Poco/Net/HTTPClientSession.h>
+#include <Poco/Net/HTTPRequest.h>
+#include <Poco/Net/HTTPResponse.h>
+#include <Poco/StreamCopier.h>
+#include <Poco/Path.h>
+#include <Poco/Exception.h>
+#include "influxdb.h"
+#include "json.h"
+#include "dbSqlite.h"
+
+struct weatherData {
+    std::string plz;
+    std::string lngCode;
+    int sunrise;
+    int sunset;
+    int visibility;
+    double temp;
+    double tempFeelsLike;
+    double tempMin;
+    double tempMax;
+    int humidity;
+    int pressure;
+    double windSpeed;
+    int windDeg;
+    int clouds;
+    double rain1h;
+    double rain3h;
+    double snow1h;
+    double snow3h;
+    std::string icons;
+    std::string from;
+};
+
+class openweathermap {
+private:
+    std::string appid;
+    std::string plz;
+    std::string lngCode;
+    weatherData sWeather;
+    std::vector<weatherData> vecForecast;
+    dbSqlite* db;
+public:
+    openweathermap() {
+        std::cout << "openweathermap::openweathermap()" << std::endl;
+        db = new dbSqlite();
+    }
+
+    std::string str_tolower(std::string s) {
+        std::cout << "openweathermap::str_tolower()" << std::endl;
+        std::transform(s.begin(), s.end(), s.begin(),
+            [](unsigned char c) { return std::tolower(c); }
+        );
+        return s;
+    }
+
+    weatherData getSWeather() {
+        std::cout << "openweathermap::getSWeather()" << std::endl;
+        return this->sWeather;
+    }
+
+    std::vector<weatherData> getSForecast() {
+        std::cout << "openweathermap::getSForecast()" << std::endl;
+        return this->vecForecast;
+    }
+
+    void setSWeather(json::JSON jObj, std::string plz, std::string lngCode) {
+        std::cout << "openweathermap::setSWeather()" << std::endl;
+        this->sWeather.plz = plz;
+        this->sWeather.lngCode = lngCode;
+        this->sWeather.visibility = jObj["visibility"].ToInt();
+        this->sWeather.sunrise = jObj["sys"]["sunrise"].ToInt();
+        this->sWeather.sunset = jObj["sys"]["sunset"].ToInt();
+        this->sWeather.temp = jObj["main"]["temp"].ToFloat();
+        this->sWeather.tempFeelsLike = jObj["main"]["feels_like"].ToFloat();
+        this->sWeather.tempMin = jObj["main"]["temp_min"].ToFloat();
+        this->sWeather.tempMax = jObj["main"]["temp_max"].ToFloat();
+        this->sWeather.humidity = jObj["main"]["humidity"].ToInt();
+        this->sWeather.pressure = jObj["main"]["pressure"].ToInt();
+        this->sWeather.windSpeed = jObj["wind"]["speed"].ToFloat();
+        this->sWeather.windDeg = jObj["wind"]["deg"].ToInt();
+        this->sWeather.clouds = jObj["clouds"]["all"].ToInt();
+        this->sWeather.rain1h = jObj["rain"]["1h"].ToFloat();
+        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();
+    }
+
+    void setSForecast(json::JSON jObj, std::string plz, std::string lngCode) {
+        std::cout << "openweathermap::setSForecast()" << std::endl;
+        for (int i = 0; i < jObj["cnt"].ToInt(); i++) {
+            weatherData item;
+            item.plz = plz;
+            item.lngCode = lngCode;
+            item.sunrise = jObj["city"]["sunrise"].ToInt();
+            item.sunset = jObj["city"]["sunset"].ToInt();
+            item.temp = jObj["list"][i]["main"]["temp"].ToFloat();
+            item.tempFeelsLike = jObj["list"][i]["main"]["feels_like"].ToFloat();
+            item.tempMin = jObj["list"][i]["main"]["temp_min"].ToFloat();
+            item.tempMax = jObj["list"][i]["main"]["temp_max"].ToFloat();
+            item.humidity = jObj["list"][i]["main"]["humidity"].ToInt();
+            item.pressure = jObj["list"][i]["main"]["pressure"].ToInt();
+            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();
+            if (vecForecast.size() != jObj["cnt"].ToInt()) {
+                this->vecForecast.push_back(item);
+            }
+            else {
+                this->vecForecast[i] = item;
+            }
+        }
+    }
+
+    std::string getResponse(std::string url) {
+        std::cout << "openweathermap::getResponse()" << std::endl;
+        try {
+            // prepare session
+            Poco::URI uri(url);
+            Poco::Net::HTTPClientSession session(uri.getHost(), uri.getPort());
+
+            // prepare path
+            std::string path(uri.getPathAndQuery());
+            if (path.empty()) path = "/";
+
+            // send request
+            Poco::Net::HTTPRequest req(Poco::Net::HTTPRequest::HTTP_GET, path, Poco::Net::HTTPMessage::HTTP_1_1);
+            session.sendRequest(req);
+
+            // get response
+            Poco::Net::HTTPResponse res;
+            std::cout << res.getStatus() << " " << res.getReason() << std::endl;
+
+            // copy response to output string stream
+            std::istream& is = session.receiveResponse(res);
+            std::ostringstream oss;
+            Poco::StreamCopier::copyStream(is, oss);
+
+            return oss.str();
+        }
+        catch (Poco::Exception & ex) {
+            std::cerr << ex.displayText() << std::endl;
+        }
+    }
+
+    void getWeather(std::string plz, std::string lngCode) {
+        std::cout << "openweathermap::getWeather" << std::endl;
+        lngCode = str_tolower(lngCode);
+        this->setSWeather(json::JSON::Load(this->getResponse("http://api.openweathermap.org/data/2.5/weather?zip=" + plz + "," + lngCode + "&appid=" + db->getSettings().owm_appid + "&mode=json&units=metric&lang=de")), plz, lngCode);
+
+        std::cout << "owm_appid: " << db->getSettings().owm_appid << std::endl;
+
+        influxdb_cpp::server_info si(db->getSettings().influx_host, db->getSettings().influx_port, db->getSettings().influx_db, db->getSettings().influx_user, db->getSettings().influx_pass);
+        std::cout << "Influx Result: " << influxdb_cpp::builder()
+            .meas("Weather")
+            .tag("plz", this->sWeather.plz)
+            .tag("lngCode", this->sWeather.lngCode)
+            .field("sunrise", this->sWeather.sunrise)
+            .field("sunset", this->sWeather.sunset)
+            .field("visibility", this->sWeather.visibility)
+            .field("temp", this->sWeather.temp)
+            .field("temp_feels_like", this->sWeather.tempFeelsLike)
+            .field("temp_min", this->sWeather.tempMin)
+            .field("temp_max", this->sWeather.tempMax)
+            .field("humidity", this->sWeather.humidity)
+            .field("pressure", this->sWeather.pressure)
+            .field("wind_speed", this->sWeather.windSpeed)
+            .field("wind_deg", this->sWeather.windDeg)
+            .field("rain1h", this->sWeather.rain1h)
+            .field("rain3h", this->sWeather.rain3h)
+            .field("snow1h", this->sWeather.snow1h)
+            .field("snow3h", this->sWeather.snow3h)
+            .field("clouds", this->sWeather.clouds)
+            .field("icons", this->sWeather.icons)
+            .post_http(si);
+    }
+
+    void getForecast(std::string plz, std::string lngCode) {
+        std::cout << "openweathermap::getForecast" << std::endl;
+        lngCode = str_tolower(lngCode);
+        this->setSForecast(json::JSON::Load(this->getResponse("http://api.openweathermap.org/data/2.5/forecase?zip=" + plz + "," + lngCode + "&appid=" + db->getSettings().owm_appid + "&mode=json&units=metric&lang=de")), plz, lngCode);
+    }
+};
\ No newline at end of file
-- 
GitLab