Arduino Schnittstelle

Hallo miteinander,

das Hardwareprojekt von Dennis mit einem Waveshare Controler und dem E-Ink Display finde ich sehr spannend und möchte mich daran trauen.
https://www.knx-und-ich.de/2021/11/06/knx-wetterstation-fuer-das-schlafzimmer/
Er hat die Daten aus der KNX allerdings über eine REST-Api bezogen. Nach Recherchen hie im Forum empfiehlt man aber wohl eher MQTT. Ich habe hier in PHP schon einige Projekte gemacht, allerdings noch nicht mit MQTT und in Arduino, welches über C ähnlichen Syntax programmiert wird, bin ich auch noch neu. Den Code von Dennis kann man sicherlich einfach für die eigenen Bedürfnisse mit TryAndError ausprobieren. Die Datenschnittstelle zu IPS hinzubekommen fällt mir allerdings etwas schwerer. Wäre es möglich, dass hier jemand folgenden Code ein Beispiel aufmacht?
Ich befürchte, dass dies etwas meine bisherigen Erfahrungen in IPS übersteigt. In der Anleitung der IPS zum Thema MQTT steht sehr wenig an Beispielen. Vielleicht nochmals ein Verbesserungsvorschlag an die Macher die Beipiele etwas auszuweiten.

Für etwas Unterstützung wäre ich sehr dankbar.

Folgend der Code der Arduino von Dennis, der auch frei auf seiner Homepage heruntergeladen werden kann:

#define ROOM_TEMP_WOHNZIMMER "a1122"
#define ROOM_TEMP_FLUREG "a1128"
#define ROOM_TEMP_KUECHE "a1118"
#define ROOM_TEMP_SPORT "a1126"
#define ROOM_TEMP_BUERO "a1124"
#define ROOM_TEMP_HWR "a1132"
#define ROOM_TEMP_ELERN "a1138"
#define ROOM_TEMP_KIND1 "a1134"
#define ROOM_TEMP_KIND2 "a1135"
#define ROOM_TEMP_KIND3 "a1136"
#define ROOM_TEMP_BAD "a1133"
#define ROOM_TEMP_WERKSTATT "a2931"

#define KNXOBJ_TEMP_AUSSEN "CO@0_0_5"
#define KNXOBJ_WIND "CO@0_0_6"
#define KNXOBJ_HELLIGKEIT_OST "CO@0_0_1"
#define KNXOBJ_HELLIGKEIT_SUED "CO@0_0_2"
#define KNXOBJ_HELLIGKEIT_WEST "CO@0_0_3"
#define KNXOBJ_REGEN "CO@0_1_1"

#include "DEV_Config.h"
#include "EPD.h"
#include "GUI_Paint.h"
#include <stdlib.h>
#include "WiFi.h" 
#include "HTTPClient.h"
#include <ArduinoJson.h>
#include <TimeLib.h>

struct Measurement
{
  String name;
  double value;
};

struct ForecastH
{
  long dt;
  double temp;
  byte clouds;
  double wind_speed;
  int wind_deg;
  double wind_gust;
  String description;
  String icon;
  double pop;
  double rain;
};

struct ForecastD
{
  long dt;
  double temp_day;
  double temp_min;
  double temp_max;
  double temp_night;
  double temp_eve;
  double temp_morn;
  byte clouds;
  double wind_speed;
  int wind_deg;
  double wind_gust;
  String description;
  String icon;
  double pop;
  double rain;
  String sunrise;
  String sunset;
};

const char *SSID = "WLAN-SSID";
const char *WiFiPassword = "*geheim*";
IPAddress local_IP(192, 168, X, Y);
IPAddress gateway(192, 168, X, Z);
IPAddress subnet(255, 255, 255, 0);
IPAddress primaryDNS(192, 168, X, Z);
HTTPClient http;

String HSApiToken = "";
String HSWSSApiKey = "**apikey**";
DynamicJsonDocument doc(32768);

struct Measurement measurements[12];
struct ForecastH forecast2D[12];
struct ForecastD forecast7D[8];
double knxIstAussenTemperatur, knxIstWind, knxIstRegen;
String currentTime;

const unsigned char epd_bitmap_09d_2x [] PROGMEM = {
	0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x00, 
	0x7f, 0xff, 0xff, 0xff, 0x8c, 0x00, 0x3f, 0xff, 0xff, 0xf8, 0x60, 0x00, 0x0f, 0xff, 0xff, 0xf1, 
	0x18, 0x00, 0x1f, 0xff, 0xff, 0xe6, 0xe5, 0x00, 0x00, 0x7f, 0xff, 0xc2, 0xb5, 0x00, 0x00, 0x3f, 
	0xff, 0xba, 0xb5, 0x80, 0x00, 0x3f, 0xff, 0x8a, 0x94, 0x40, 0x00, 0x3f, 0xff, 0x35, 0x6b, 0x80, 
	0x00, 0x1f, 0xff, 0x96, 0xb5, 0x50, 0x00, 0x0f, 0xff, 0x2b, 0x55, 0x5e, 0x00, 0x07, 0xfc, 0x94, 
	0xb5, 0x53, 0x80, 0x00, 0xfa, 0x6b, 0x55, 0xaa, 0x40, 0x00, 0xe2, 0xa9, 0xac, 0xad, 0xc0, 0x00, 
	0xea, 0xac, 0xa6, 0xa6, 0x40, 0x00, 0x16, 0xf6, 0xda, 0xd9, 0x40, 0x00, 0x2b, 0x0b, 0x35, 0x56, 
	0xac, 0x00, 0x29, 0xe9, 0x96, 0xaa, 0xb6, 0x02, 0x6c, 0xad, 0x53, 0x6d, 0xa2, 0x03, 0x2b, 0x55, 
	0xed, 0x52, 0xbb, 0x2f, 0x55, 0x6a, 0x15, 0x5b, 0x44, 0xbf, 0x55, 0x2d, 0xda, 0xaa, 0xbf, 0x3f, 
	0x5b, 0xa6, 0xaa, 0xb6, 0xa5, 0x3f, 0x0c, 0xd9, 0x55, 0x51, 0xb2, 0xbf, 0xd3, 0x56, 0xae, 0xad, 
	0x4d, 0x7f, 0xcc, 0xb2, 0x63, 0x56, 0xa6, 0x7f, 0xe2, 0x98, 0x3a, 0xd3, 0x70, 0xff, 0xf9, 0x45, 
	0x81, 0x14, 0x09, 0xff, 0xfc, 0x00, 0x00, 0x01, 0x01, 0xff, 0xff, 0xe7, 0xff, 0xe7, 0xff, 0xff, 
	0xff, 0xe7, 0x9f, 0xe7, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xe7, 0xff, 0xff, 0xff, 0xc7, 0xff, 0x3f, 
	0xff, 0xff, 0xff, 0xc7, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xc7, 0x3f, 0x3f, 0xff, 0xff, 0xff, 0xff, 
	0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xfc, 0x7f, 0xff, 0xff, 
	0xff, 0x8e, 0x7c, 0x7f, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff
};

const unsigned char epd_bitmap_04d_2x [] PROGMEM = {
	0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x01, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 
	0x7f, 0xff, 0xff, 0xfe, 0x18, 0x00, 0x3f, 0xff, 0xff, 0xf0, 0xc0, 0x00, 0x3f, 0xff, 0xff, 0xf7, 
	0xf8, 0x00, 0x1f, 0xff, 0xff, 0x8f, 0xfc, 0x00, 0x11, 0xff, 0xff, 0xad, 0x6e, 0x00, 0x00, 0x7f, 
	0xff, 0x3f, 0xff, 0x00, 0x00, 0x3f, 0xff, 0x77, 0x6f, 0x00, 0x00, 0x3f, 0xfe, 0xff, 0xfb, 0xc0, 
	0x00, 0x3f, 0xfe, 0x75, 0xbf, 0x84, 0x00, 0x3f, 0xfe, 0xbe, 0xf5, 0xfe, 0x00, 0x07, 0xfe, 0xff, 
	0xdf, 0xf7, 0x80, 0x03, 0xe0, 0xf7, 0xfe, 0xdf, 0x80, 0x00, 0xcf, 0x7e, 0xef, 0xfb, 0xc0, 0x00, 
	0xdb, 0xb7, 0xf6, 0xef, 0xc0, 0x00, 0xaf, 0xfe, 0xbf, 0xbd, 0xc0, 0x00, 0x3f, 0x6f, 0xfd, 0xff, 
	0x68, 0x00, 0xfb, 0xfb, 0xee, 0xef, 0xfe, 0x00, 0xbf, 0x7e, 0xff, 0xfd, 0xd6, 0x01, 0xed, 0xdb, 
	0xfb, 0x6f, 0x7f, 0x03, 0xff, 0xef, 0xaf, 0xfb, 0xff, 0x87, 0x6e, 0xf7, 0xfd, 0xbf, 0x55, 0xbf, 
	0xf7, 0xfa, 0xdf, 0xfb, 0xff, 0xbf, 0xff, 0x7f, 0xf6, 0xdf, 0xff, 0x3f, 0x6f, 0xdf, 0xff, 0xfb, 
	0x6d, 0xbf, 0x7b, 0xf5, 0x7b, 0xdf, 0xf7, 0xbf, 0x2d, 0xff, 0xbd, 0xfe, 0xff, 0x3f, 0x9f, 0x5e, 
	0xff, 0x6b, 0xba, 0x7f, 0xcf, 0xf7, 0xd7, 0xff, 0xfd, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x01, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};

const unsigned char epd_bitmap_10d_2x [] PROGMEM = {
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf0, 
	0x00, 0x3f, 0xff, 0xff, 0x83, 0xe0, 0x00, 0x1f, 0xff, 0xfc, 0x28, 0x80, 0x00, 0x07, 0xff, 0xf1, 
	0x94, 0x00, 0x00, 0x07, 0xff, 0xfa, 0x53, 0x00, 0x00, 0x03, 0xff, 0xe5, 0x5a, 0xc0, 0x00, 0x03, 
	0xff, 0xe5, 0x4a, 0x00, 0x00, 0x01, 0xff, 0xd5, 0x51, 0xe0, 0x00, 0x01, 0xff, 0xca, 0x4e, 0x10, 
	0x00, 0x01, 0xff, 0xa5, 0x61, 0xc0, 0x00, 0x01, 0xff, 0xb2, 0x34, 0x75, 0x80, 0x01, 0xfe, 0x0b, 
	0x9b, 0x0a, 0x60, 0x01, 0xf9, 0x54, 0x64, 0xb5, 0x90, 0x01, 0xf8, 0xab, 0x13, 0x4a, 0x50, 0x01, 
	0xe6, 0xa9, 0xd9, 0x6b, 0x50, 0x01, 0xd2, 0x55, 0x25, 0x10, 0xa8, 0x01, 0xcd, 0xaa, 0x55, 0x6e, 
	0x90, 0x01, 0xb0, 0xa9, 0xaa, 0x92, 0xab, 0x03, 0x9c, 0xac, 0xaa, 0x52, 0xa9, 0x83, 0x85, 0x15, 
	0x25, 0xaa, 0x54, 0x67, 0x9a, 0xe2, 0xd4, 0x55, 0xab, 0x97, 0x85, 0x3a, 0x53, 0x14, 0x94, 0x57, 
	0xb2, 0x89, 0x59, 0xa4, 0xcb, 0x57, 0x89, 0x66, 0xaa, 0xdb, 0x34, 0x87, 0xb6, 0x95, 0x45, 0x24, 
	0xc3, 0x77, 0x92, 0x55, 0x74, 0x96, 0x78, 0x87, 0xcb, 0x4a, 0x16, 0xd2, 0x0e, 0x6f, 0xf1, 0x28, 
	0xd1, 0x55, 0xe1, 0x8f, 0xfa, 0xaa, 0x0d, 0x2a, 0x1a, 0x3f, 0xfc, 0x28, 0x24, 0x81, 0xa4, 0x3f, 
	0xf9, 0x00, 0x80, 0x24, 0x01, 0xff, 0xf9, 0xfe, 0x3f, 0x8f, 0xf1, 0xff, 0xff, 0xfe, 0x3f, 0x8f, 
	0xf1, 0xff, 0xff, 0xfe, 0x3f, 0x8f, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xf1, 
	0xff, 0xff, 0x8f, 0xff, 0xff, 0xf1, 0xfc, 0x7f, 0x8f, 0xff, 0xff, 0xf1, 0xfc, 0x7f, 0x8f, 0xff, 
	0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};

const unsigned char epd_bitmap_03d_2x [] PROGMEM = {
	0xff, 0xff, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xfe, 0x55, 0x3f, 0xff, 0xff, 0xff, 0xf8, 0x92, 0x9f, 
	0xff, 0xff, 0xff, 0xf9, 0x5a, 0xcf, 0xff, 0xff, 0xff, 0xe5, 0x4a, 0x6f, 0xff, 0xff, 0xff, 0xe2, 
	0xb5, 0x83, 0xff, 0xff, 0xff, 0xcd, 0x4a, 0x69, 0xff, 0xff, 0xff, 0xc2, 0xa5, 0x35, 0xff, 0xff, 
	0xff, 0xb9, 0x55, 0x14, 0x07, 0xff, 0xff, 0x8d, 0x6a, 0xd1, 0x51, 0xff, 0xff, 0x92, 0x95, 0x56, 
	0x94, 0xff, 0xff, 0x95, 0x55, 0x52, 0xd6, 0xff, 0xfc, 0x15, 0x55, 0x52, 0x52, 0x7f, 0xf1, 0xb5, 
	0x52, 0xab, 0x4a, 0x7f, 0xc2, 0x52, 0xad, 0x2c, 0xb5, 0x7f, 0xdd, 0x4a, 0xa5, 0xa2, 0x95, 0x7f, 
	0x85, 0x6a, 0xaa, 0xba, 0xd4, 0x0f, 0x35, 0x55, 0x29, 0x4a, 0x2b, 0x63, 0x8a, 0x92, 0xd6, 0x95, 
	0xd4, 0x89, 0x72, 0xda, 0x50, 0xea, 0x4b, 0x74, 0x19, 0x4b, 0x5e, 0x25, 0x69, 0x1a, 0xca, 0xa8, 
	0xa1, 0xb5, 0x96, 0xc9, 0x35, 0x56, 0xad, 0x4a, 0x52, 0x66, 0x94, 0xaa, 0x94, 0xa9, 0x5b, 0x39, 
	0xd6, 0xaa, 0xd6, 0x55, 0x49, 0x4d, 0x29, 0x52, 0x4a, 0xd6, 0x65, 0x22, 0x52, 0x8a, 0xb9, 0x29, 
	0x9a, 0xdd, 0x1d, 0x6a, 0x95, 0x94, 0xa5, 0x22, 0xc5, 0x5a, 0x94, 0xd6, 0xb5, 0xba, 0xca, 0xa5, 
	0x6a, 0xaa, 0x4a, 0x44, 0xe5, 0x4a, 0x95, 0x49, 0xb5, 0xa9, 0xf2, 0xaa, 0xd5, 0x6c, 0x8a, 0x53, 
	0xf0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};

const unsigned char epd_bitmap_02d_2x [] PROGMEM = {
	0xff, 0xff, 0xff, 0xfc, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x7f, 0xff, 0xff, 0x8f, 0xe0, 
	0x00, 0x1f, 0xff, 0xfc, 0x21, 0xc0, 0x00, 0x0f, 0xff, 0xf1, 0xfc, 0x00, 0x00, 0x07, 0xff, 0xe7, 
	0x57, 0x00, 0x00, 0x03, 0xff, 0xed, 0xfd, 0x80, 0x00, 0x03, 0xff, 0x9d, 0x2f, 0xc0, 0x00, 0x01, 
	0xff, 0xaf, 0xf5, 0x40, 0x00, 0x00, 0xff, 0xb6, 0xab, 0xe0, 0x00, 0x00, 0xff, 0x1b, 0xdf, 0x60, 
	0x00, 0x00, 0xff, 0x7e, 0xf5, 0x72, 0x80, 0x00, 0xff, 0x53, 0x5f, 0xaf, 0xc0, 0x00, 0xfc, 0x6f, 
	0xf5, 0xfa, 0xe8, 0x00, 0xf1, 0xbd, 0x5e, 0xaf, 0xb0, 0x00, 0xe6, 0xb7, 0xd7, 0xea, 0xf0, 0x00, 
	0x9b, 0xda, 0xfa, 0xff, 0x38, 0x00, 0xae, 0xf7, 0xad, 0x55, 0xe0, 0x00, 0x37, 0x5d, 0x77, 0xfe, 
	0xba, 0x01, 0xbb, 0xef, 0xbe, 0xab, 0xdf, 0x83, 0xed, 0x75, 0xd6, 0xfe, 0xea, 0xc3, 0x7b, 0xbb, 
	0x6b, 0xab, 0x5f, 0x67, 0xad, 0xcd, 0xbe, 0xfd, 0xf5, 0xd7, 0xee, 0xff, 0xd7, 0xaf, 0x5f, 0x77, 
	0xbb, 0xaa, 0xf9, 0xd5, 0xeb, 0xb7, 0xee, 0xdf, 0xae, 0xff, 0x76, 0xe7, 0xbb, 0x69, 0x7b, 0xa9, 
	0xdd, 0xb7, 0x2d, 0xff, 0xaa, 0xbf, 0x6e, 0xd7, 0xb6, 0xad, 0xff, 0xd5, 0xef, 0x67, 0x9f, 0xf6, 
	0xb5, 0xfe, 0xb5, 0x8f, 0xcd, 0x5b, 0xef, 0x2b, 0xdf, 0xbf, 0xe5, 0xfe, 0xbb, 0xba, 0xea, 0xbf, 
	0xf0, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};

const unsigned char epd_bitmap_01d_2x [] PROGMEM = {
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x3f, 
	0xff, 0xff, 0xff, 0xff, 0xc1, 0x03, 0xff, 0xff, 0xff, 0xfe, 0x2d, 0x50, 0xff, 0xff, 0xff, 0xfc, 
	0x91, 0x2d, 0x3f, 0xff, 0xff, 0xf1, 0x66, 0x92, 0x5f, 0xff, 0xff, 0xf4, 0x32, 0x49, 0x4f, 0xff, 
	0xff, 0xe6, 0x89, 0x4a, 0x4f, 0xff, 0xff, 0xc2, 0x6a, 0xa9, 0x67, 0xff, 0xff, 0x99, 0x89, 0x52, 
	0x93, 0xff, 0xff, 0x84, 0xa4, 0x4a, 0x51, 0xff, 0xff, 0x69, 0x56, 0xa5, 0x29, 0xff, 0xff, 0x15, 
	0x28, 0x92, 0x8d, 0xff, 0xfe, 0xaa, 0x46, 0x6c, 0x50, 0xff, 0xfe, 0x22, 0xb1, 0x23, 0x54, 0x7f, 
	0xfd, 0x12, 0x95, 0x29, 0x15, 0x7f, 0xfc, 0xd9, 0x4a, 0x94, 0xca, 0x7f, 0xfe, 0x22, 0x29, 0x55, 
	0x30, 0xff, 0xfe, 0x9d, 0x54, 0x44, 0x9a, 0x7f, 0xfc, 0xc2, 0x96, 0xaa, 0x8a, 0x7f, 0xfe, 0x29, 
	0x41, 0x54, 0xb1, 0x7f, 0xfe, 0x96, 0x5a, 0x4a, 0x8c, 0xff, 0xfe, 0x51, 0x45, 0x22, 0x62, 0xff, 
	0xff, 0x2d, 0x31, 0x55, 0x28, 0xff, 0xff, 0x10, 0xce, 0x92, 0x95, 0xff, 0xff, 0xa7, 0x11, 0x2d, 
	0x69, 0xff, 0xff, 0x90, 0xa9, 0x40, 0x03, 0xff, 0xff, 0xd6, 0x95, 0x36, 0xf3, 0xff, 0xff, 0xc2, 
	0x54, 0xc9, 0x0f, 0xff, 0xff, 0xf4, 0xa1, 0x52, 0xa7, 0xff, 0xff, 0xf9, 0x56, 0x29, 0x1f, 0xff, 
	0xff, 0xfc, 0x52, 0x95, 0x3f, 0xff, 0xff, 0xfe, 0x11, 0x48, 0xff, 0xff, 0xff, 0xff, 0xc4, 0xa1, 
	0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};

const unsigned char epd_bitmap_11d_2x [] PROGMEM = {
	0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xfc, 0x00, 
	0x3f, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xf1, 0x10, 0x00, 0x1f, 0xff, 0xff, 0xc4, 
	0xa0, 0x00, 0x11, 0xff, 0xff, 0xc4, 0x44, 0x00, 0x00, 0x7f, 0xff, 0xa2, 0x54, 0x00, 0x00, 0x3f, 
	0xff, 0x12, 0x42, 0x00, 0x00, 0x3f, 0xff, 0x29, 0x29, 0x00, 0x00, 0x3f, 0xff, 0x42, 0x42, 0x00, 
	0x00, 0x3f, 0xfe, 0x59, 0x18, 0x80, 0x00, 0x07, 0xfe, 0x09, 0x44, 0x94, 0x00, 0x03, 0xf0, 0x64, 
	0xaa, 0x4a, 0x00, 0x00, 0xc5, 0x11, 0x01, 0x21, 0x00, 0x00, 0x90, 0x94, 0xb4, 0xa8, 0x80, 0x00, 
	0x8a, 0x44, 0x12, 0x14, 0x80, 0x00, 0x24, 0x2b, 0x49, 0x45, 0x00, 0x00, 0x49, 0x40, 0xa2, 0x28, 
	0xa0, 0x00, 0x25, 0x28, 0x29, 0x44, 0x90, 0x01, 0x91, 0x2a, 0x24, 0x24, 0x54, 0x03, 0x24, 0x85, 
	0x92, 0xaa, 0x09, 0x07, 0x52, 0x5b, 0xe9, 0x40, 0xd2, 0x3f, 0x09, 0x04, 0x1c, 0x9a, 0x49, 0x3f, 
	0xa5, 0x58, 0x08, 0x82, 0x44, 0xbf, 0x11, 0x08, 0x0c, 0x69, 0x12, 0x3f, 0x84, 0xb8, 0x2a, 0x84, 
	0xa9, 0x3f, 0xd4, 0x90, 0x1c, 0x32, 0x44, 0xff, 0xc4, 0x60, 0x06, 0x89, 0x30, 0xff, 0xf1, 0x50, 
	0x04, 0xa2, 0x43, 0xff, 0xf8, 0x40, 0x04, 0x00, 0x03, 0xff, 0xff, 0xe0, 0x1f, 0xff, 0xff, 0xff, 
	0xff, 0xc8, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};

const unsigned char epd_bitmap_13d_2x [] PROGMEM = {
	0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 
	0xff, 0xff, 0xff, 0xff, 0xce, 0x3d, 0xff, 0xff, 0xff, 0xff, 0x86, 0x30, 0xff, 0xff, 0xff, 0xff, 
	0x82, 0x20, 0xff, 0xff, 0xff, 0xf9, 0xc0, 0x01, 0xc7, 0xff, 0xff, 0xf0, 0xe0, 0x03, 0xc7, 0xff, 
	0xff, 0xf0, 0xf0, 0x07, 0x87, 0xff, 0xff, 0xf8, 0xf8, 0x0f, 0x87, 0xff, 0xfe, 0x38, 0xfc, 0x1f, 
	0x8e, 0x3f, 0xfe, 0x00, 0x7e, 0x1f, 0x80, 0x3f, 0xfe, 0x00, 0x7e, 0x3f, 0x00, 0x3f, 0xff, 0x80, 
	0x7e, 0x3f, 0x00, 0xff, 0xff, 0xc0, 0x3c, 0x1e, 0x01, 0xff, 0xff, 0xc0, 0x18, 0x0c, 0x01, 0xff, 
	0xfc, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xf8, 0x1f, 0xc1, 0xc0, 
	0xfc, 0x1f, 0xff, 0xff, 0xc3, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xe1, 0xff, 0xff, 0xff, 0xff, 
	0xe3, 0xe1, 0xff, 0xff, 0xf8, 0x1f, 0xc1, 0xc0, 0xfc, 0x1f, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x1f, 
	0xfc, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0x80, 0x18, 0x0c, 0x00, 0xff, 0xff, 0xc0, 0x3c, 0x1e, 
	0x01, 0xff, 0xff, 0x80, 0x7e, 0x3f, 0x00, 0xff, 0xfe, 0x00, 0x7e, 0x3f, 0x00, 0x3f, 0xfe, 0x08, 
	0x7e, 0x3f, 0x80, 0x3f, 0xfe, 0x18, 0xfc, 0x1f, 0x8e, 0x3f, 0xff, 0xf8, 0xf8, 0x0f, 0x87, 0x7f, 
	0xff, 0xf0, 0xf0, 0x07, 0x87, 0xff, 0xff, 0xf0, 0xe0, 0x03, 0xc7, 0xff, 0xff, 0xf9, 0xc0, 0x01, 
	0xc7, 0xff, 0xff, 0xff, 0x82, 0x20, 0xff, 0xff, 0xff, 0xff, 0x86, 0x30, 0xff, 0xff, 0xff, 0xff, 
	0xce, 0x38, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 
	0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};

const unsigned char epd_bitmap_50d_2x [] PROGMEM = {
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4a, 0xaf, 0xff, 0xff, 0xff, 0xff, 0x20, 0x0f, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 
	0xbf, 0xaf, 0xff, 0xff, 0xff, 0x20, 0x00, 0x51, 0xff, 0xff, 0xff, 0xbf, 0xff, 0x6f, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x10, 0x00, 
	0x20, 0x9f, 0xff, 0xff, 0x4a, 0xba, 0x9c, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xf9, 0x4a, 0xad, 0x4a, 0xff, 0xff, 0xfc, 0x08, 0x40, 0x20, 0x7f, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf5, 0x5b, 0xbe, 
	0xb7, 0xff, 0xff, 0xe4, 0x80, 0x02, 0x11, 0xff, 0xff, 0xf6, 0xff, 0xdb, 0xdf, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbb, 0x7f, 0xff, 0xff, 0xff, 0xfe, 0x89, 0x00, 0x7f, 0xff, 
	0xff, 0xff, 0x44, 0x94, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};

const unsigned char epd_bitmap_regen [] PROGMEM = {
	0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xe1, 
	0xff, 0xff, 0xff, 0xfc, 0x7f, 0xfc, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xf3, 
	0xff, 0xff, 0x1f, 0xff, 0xff, 0xe7, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xef, 0xff, 0xff, 0xcf, 0xff, 
	0xff, 0xcf, 0xff, 0xff, 0xc0, 0x7f, 0xff, 0xdf, 0xff, 0xff, 0x0c, 0x1f, 0xff, 0x9f, 0xff, 0xfc, 
	0x7f, 0xcf, 0xfc, 0x3f, 0xff, 0xf9, 0xff, 0xe7, 0xf0, 0xff, 0xff, 0xfb, 0xff, 0xf3, 0xe7, 0xff, 
	0xff, 0xff, 0xff, 0xf9, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x9f, 0xff, 0xff, 0xff, 0xff, 0xfc, 
	0x9f, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, 
	0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 
	0xff, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xf9, 
	0x9f, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xe7, 0xff, 0xff, 0xff, 
	0xff, 0xc7, 0xf1, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xf8, 0x3e, 0x7e, 0xfd, 0xf8, 0x3f, 0xff, 0x3e, 
	0x7c, 0xfd, 0xfb, 0xff, 0xff, 0xfe, 0xfc, 0xf9, 0xff, 0xff, 0xff, 0xfc, 0xfd, 0xf9, 0xff, 0xff, 
	0xff, 0xfc, 0xf9, 0xfb, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xf7, 0xf7, 0xff, 0xff, 0xff, 0xfb, 
	0xf3, 0xe7, 0xff, 0xff, 0xff, 0xf3, 0xe7, 0xef, 0xff, 0xff, 0xff, 0xf7, 0xe7, 0xcf, 0xff, 0xff, 
	0xff, 0xe7, 0xef, 0xcf, 0xff, 0xff, 0xff, 0xe7, 0xef, 0xdf, 0xff, 0xff
};


void setup()
{
  DEV_Module_Init();
  esp_sleep_enable_timer_wakeup(3600000000); // Eine Stunde

  ConnectToWiFi();

  GetWeatherForecast();
  ReadHSData();
  currentTime = GetCurrentTime();  

  DrawOutput();

  Serial.println("starting deepsleep...");
  esp_deep_sleep_start();
}

void loop()
{
  // nix zu tun
}

void DrawOutput()
{
  EPD_7IN5B_V2_Init();
  DEV_Delay_ms(500);

  // Init Display Buffer
  UBYTE *BImage, *RImage;
  UWORD Imagesize = ((EPD_7IN5B_V2_WIDTH % 8 == 0) ? (EPD_7IN5B_V2_WIDTH / 8 ) : (EPD_7IN5B_V2_WIDTH / 8 + 1)) * EPD_7IN5B_V2_HEIGHT;
  if ((BImage = (UBYTE *)malloc(Imagesize)) == NULL) {
    Serial.write("Kein Speicher black memory...\r\n");
    while (1);
  }
  if ((RImage = (UBYTE *)malloc(Imagesize)) == NULL) {
    Serial.write("Kein Speicher red memory...\r\n");
    while(1);
  }  

  // Prepare Display Buffer
  Paint_NewImage(BImage, EPD_7IN5B_V2_WIDTH, EPD_7IN5B_V2_HEIGHT, 0, WHITE);
  Paint_NewImage(RImage, EPD_7IN5B_V2_WIDTH, EPD_7IN5B_V2_HEIGHT, 0, WHITE);
  Paint_SelectImage(BImage); Paint_Clear(WHITE);
  Paint_SelectImage(RImage); Paint_Clear(WHITE);   

  // Draw Raster
  Paint_SelectImage(BImage);
  Paint_DrawLine(220, 0+4, 220, EPD_7IN5B_V2_HEIGHT-4, BLACK, DOT_PIXEL_4X4, LINE_STYLE_SOLID);
  Paint_DrawLine(582, 0+4, 582, EPD_7IN5B_V2_HEIGHT-4, BLACK, DOT_PIXEL_4X4, LINE_STYLE_SOLID);  
  Paint_DrawLine(0, 68, 220, 68, BLACK, DOT_PIXEL_4X4, LINE_STYLE_SOLID);  
  Paint_DrawLine(0, 464-16, 220, 464-16, BLACK, DOT_PIXEL_4X4, LINE_STYLE_SOLID);  


  // *** LINKS ***

  // Ausgbe IST Temperaturen AUSSEN, links oben
  Paint_SelectImage(RImage);
  Paint_DrawString_EN(32, 4, (" " + String(knxIstAussenTemperatur, 1) + (String)"C ").c_str(), &Font24, BLACK, WHITE);  
  Paint_DrawString_EN(0, 24+8, ("Wind: " + String(knxIstWind, 0) + (String)" km/h").c_str(), &Font16, WHITE, BLACK);
  if (knxIstRegen != 0)
  {
      Paint_SelectImage(BImage);
      Paint_DrawImage(epd_bitmap_regen, 220-48-4-4, 68-42-4-16, 48, 42);
  }
    
  // Ausgabe IST Temperaturen HAUS links mitte
  Paint_SelectImage(BImage);
  for (int i = 0 ; i < 12 ; i++)
  {
    Paint_DrawString_EN(0, 80 + (i*24), measurements[i].name.c_str(), &Font24, WHITE, BLACK);
  }
  Paint_SelectImage(RImage);
  for (int i = 0 ; i < 12 ; i++)
  {
    Paint_DrawString_EN(118, 80 + (i*24), (String(measurements[i].value, 1) + (String)"C").c_str(), &Font24, WHITE, BLACK);
  }

  // Ausgabe aktuelle Uhrzeit, links unten
  Paint_SelectImage(BImage);
  Paint_DrawString_EN(0, 464, currentTime.c_str(), &Font16, WHITE, BLACK);


  // *** MITTE ***

  // Ausgabe stunden Vorhersage
  for (int i = 0 ; i < 10 ; i++)
  {
    String dateString = GetDatetimeString(forecast2D[i].dt, true);    

    String detailString = String(forecast2D[i].pop,0) + "% ";
    detailString += String(forecast2D[i].rain,0) + "ml";

    Paint_SelectImage(BImage);
    Paint_DrawString_EN(228, 1 + (i*47), dateString.c_str(), &Font16, WHITE, BLACK);
    Paint_DrawString_EN(228, 1 + 16 + (i*47), RemoveUmlaute(forecast2D[i].description).c_str(), &Font12, WHITE, BLACK);

    Paint_SelectImage(RImage);    
    Paint_DrawString_EN(408, 6 + (i*47), (String(forecast2D[i].temp,0) + "C").c_str(), &Font20, WHITE, BLACK);
    Paint_DrawString_EN(408, 6 + 20 + 4 + (i*47), detailString.c_str(), &Font12, WHITE, BLACK);

    if (forecast2D[i].icon.charAt(2) == 'd')
      Paint_SelectImage(RImage);
    else
      Paint_SelectImage(BImage);

    if (forecast2D[i].icon == "04d" || forecast2D[i].icon == "04n")
      Paint_DrawImage(epd_bitmap_04d_2x, 526, 1+(i*47), 48, 42);
    if (forecast2D[i].icon == "09d" || forecast2D[i].icon == "09n")
      Paint_DrawImage(epd_bitmap_04d_2x, 526, 1+(i*47), 48, 42);
    if (forecast2D[i].icon == "10d" || forecast2D[i].icon == "10n")
      Paint_DrawImage(epd_bitmap_10d_2x, 526, 1+(i*47), 48, 42);
    if (forecast2D[i].icon == "03d" || forecast2D[i].icon == "03n")
      Paint_DrawImage(epd_bitmap_03d_2x, 526, 1+(i*47), 48, 42);
    if (forecast2D[i].icon == "02d" || forecast2D[i].icon == "02n")
      Paint_DrawImage(epd_bitmap_02d_2x, 526, 1+(i*47), 48, 42);
    if (forecast2D[i].icon == "01d" || forecast2D[i].icon == "01n")
      Paint_DrawImage(epd_bitmap_01d_2x, 526, 1+(i*47), 48, 42);      
    if (forecast2D[i].icon == "11d" || forecast2D[i].icon == "11n")
      Paint_DrawImage(epd_bitmap_11d_2x, 526, 1+(i*47), 48, 42);       
    if (forecast2D[i].icon == "13d" || forecast2D[i].icon == "13n")
      Paint_DrawImage(epd_bitmap_13d_2x, 526, 1+(i*47), 48, 42);         
    if (forecast2D[i].icon == "50d" || forecast2D[i].icon == "50n")
      Paint_DrawImage(epd_bitmap_50d_2x, 526, 1+(i*47), 48, 42);

    Paint_SelectImage(RImage);
    Paint_DrawRectangle(228, 1+(i*47), 582-4-4, 45+(i*47), BLACK, DOT_PIXEL_1X1, DRAW_FILL_EMPTY);    
  }  


  // *** RECHTS ***

  // Ausgabe Lanzeit Vorhersage
  for (int i = 0 ; i < 7 ; i++)
  {	  
    String dateString = GetDatetimeString(forecast7D[i].dt, false);    
	String tempString = "Min:" + String(forecast7D[i].temp_min,0) + "C Max:" + String(forecast7D[i].temp_max,0) + "C";
    String rainAndWindString = "Regen:" + String(forecast7D[i].pop,0) + "% (" + String(forecast7D[i].rain,0) + "ml)";
	
    Paint_SelectImage(BImage);
    Paint_DrawString_EN(582+4+4, 4+(i*68), dateString.c_str(), &Font16, WHITE, BLACK);
    Paint_SelectImage(RImage);
    Paint_DrawString_EN(582+4+4 + 68, 4+(i*68), (" " + String(forecast7D[i].temp_day,0) + "C ").c_str(), &Font20, BLACK, WHITE);
	 
    Paint_SelectImage(BImage);
    Paint_DrawString_EN(582+4+4+1, 1+24+(i*68), tempString.c_str(), &Font12, WHITE, BLACK);	
    Paint_DrawString_EN(582+4+4+1, 1+24+12+(i*68), rainAndWindString.c_str(), &Font12, WHITE, BLACK);
    Paint_DrawString_EN(582+4+4+1, 1+24+12+12+(i*68), RemoveUmlaute(forecast7D[i].description).substring(0,18).c_str(), &Font16, WHITE, BLACK);    

    Paint_SelectImage(BImage);
    if (forecast7D[i].icon == "04d" || forecast7D[i].icon == "04n")
      Paint_DrawImage(epd_bitmap_04d_2x, 799-48-4, 4+(i*68), 48, 42);
    if (forecast7D[i].icon == "09d" || forecast7D[i].icon == "09n")
      Paint_DrawImage(epd_bitmap_04d_2x, 799-48-4, 4+(i*68), 48, 42);
    if (forecast7D[i].icon == "10d" || forecast7D[i].icon == "10n")
      Paint_DrawImage(epd_bitmap_10d_2x, 799-48-4, 4+(i*68), 48, 42);
    if (forecast7D[i].icon == "03d" || forecast7D[i].icon == "03n")
      Paint_DrawImage(epd_bitmap_03d_2x, 799-48-4, 4+(i*68), 48, 42);
    if (forecast7D[i].icon == "02d" || forecast7D[i].icon == "02n")
      Paint_DrawImage(epd_bitmap_02d_2x, 799-48-4, 4+(i*68), 48, 42);
    if (forecast7D[i].icon == "01d" || forecast7D[i].icon == "01n")
      Paint_DrawImage(epd_bitmap_01d_2x, 799-48-4, 4+(i*68), 48, 42);      
    if (forecast7D[i].icon == "11d" || forecast7D[i].icon == "11n")
      Paint_DrawImage(epd_bitmap_11d_2x, 799-48-4, 4+(i*68), 48, 42);       
    if (forecast7D[i].icon == "13d" || forecast7D[i].icon == "13n")
      Paint_DrawImage(epd_bitmap_13d_2x, 799-48-4, 4+(i*68), 48, 42);         
    if (forecast7D[i].icon == "50d" || forecast7D[i].icon == "50n")
      Paint_DrawImage(epd_bitmap_50d_2x, 799-48-4, 4+(i*68), 48, 42);               

    Paint_SelectImage(RImage);
    Paint_DrawRectangle(582+4+4, 1+(i*68), 799, 66+(i*68), BLACK, DOT_PIXEL_1X1, DRAW_FILL_EMPTY);    
  } 
  

  // Output to Display
  Serial.write("startint output\r\n");
  EPD_7IN5B_V2_Display(BImage, RImage);
  Serial.write("finished output\r\n");

  Serial.write("put display to sleep...\r\n");
  EPD_7IN5B_V2_Sleep();
  
  free(BImage);
  free(RImage);
  BImage = NULL;
  RImage = NULL;
}

void ConnectToWiFi()
{ 
  WiFi.mode(WIFI_STA);
  WiFi.config(local_IP, gateway, subnet, primaryDNS, primaryDNS);
  WiFi.begin(SSID, WiFiPassword);  
  Serial.print("Connecting to "); Serial.println(SSID);
 
  uint8_t i = 0;
  while (WiFi.status() != WL_CONNECTED)
  {
    Serial.print('.');
    delay(500);
 
    if ((++i % 16) == 0)
    {
      Serial.println(F(" still trying to connect"));
    }
  }
 
  Serial.print(F("Connected. My IP address is: "));
  Serial.println(WiFi.localIP());
}

void ReadHSData()
{  
  Serial.print("get HS authentication token...");
  String request = "https://IP-HOMESERVER/api/v2/clients";      
  http.setAuthorization("HOMESERVER-USER", "HOMESERVER-PASSWORD");
  http.addHeader("Content-Type", "application/json");
  http.setTimeout(60);
  http.setReuse(false);  
  http.begin(request);
  int httpResponseCode = http.POST("{\"client\":\"local.domain.clients.weatherstation\"}"); 	
  delay(500);
  String response = http.getString();    
  http.end();
  
  DeserializationError error = deserializeJson(doc, response);
  if(error) {
     Serial.print(F("ReadHSData deserializeJson() failed: "));
     Serial.println(error.f_str());
     return;
  }

  HSApiToken = doc["token"].as<char*>();
  Serial.println(". done getting token = '"+ HSApiToken + "'");

  measurements[0].name = "Wohnen"; measurements[0].value = ReadHSRoomTemperature(ROOM_TEMP_WOHNZIMMER);
  measurements[1].name = "Flur"; measurements[1].value = ReadHSRoomTemperature(ROOM_TEMP_FLUREG);
  measurements[2].name = "Kueche"; measurements[2].value = ReadHSRoomTemperature(ROOM_TEMP_KUECHE);
  measurements[3].name = "Sport"; measurements[3].value = ReadHSRoomTemperature(ROOM_TEMP_SPORT);
  measurements[4].name = "Buero"; measurements[4].value = ReadHSRoomTemperature(ROOM_TEMP_BUERO);
  measurements[5].name = "HWR"; measurements[5].value = ReadHSRoomTemperature(ROOM_TEMP_HWR);
  measurements[6].name = "Eltern"; measurements[6].value = ReadHSRoomTemperature(ROOM_TEMP_ELERN);
  measurements[7].name = "Kind 1"; measurements[7].value = ReadHSRoomTemperature(ROOM_TEMP_KIND1);
  measurements[8].name = "Kind 2"; measurements[8].value = ReadHSRoomTemperature(ROOM_TEMP_KIND2);
  measurements[9].name = "Kind 3"; measurements[9].value = ReadHSRoomTemperature(ROOM_TEMP_KIND3);
  measurements[10].name = "Bad"; measurements[10].value = ReadHSRoomTemperature(ROOM_TEMP_BAD);
  measurements[11].name = "Werken"; measurements[11].value = ReadHSRoomTemperature(ROOM_TEMP_WERKSTATT);

  knxIstAussenTemperatur = ReadHsKnxObj(KNXOBJ_TEMP_AUSSEN);
  knxIstWind = ReadHsKnxObj(KNXOBJ_WIND);
  knxIstRegen = ReadHsKnxObj(KNXOBJ_REGEN);
}

double ReadHSRoomTemperature(String roomUid)
{ 
  Serial.print("start ReadHSRoomTemperature for " + roomUid + "..."); 
  String request = "https://IP-HOMESERVER/api/v2/values/" + roomUid + "?token=" + HSApiToken;  
  http.addHeader("Content-Type", "application/json");
  http.setReuse(false);
  http.setTimeout(60);  
  http.begin(request);
  int httpResponseCode = http.GET();
  delay(50);  
  String response = http.getString();
  http.end();  
        
  DeserializationError error = deserializeJson(doc, response);
  if(error) {
     Serial.print(F("ReadHSRoomTemperature deserializeJson() failed: "));
     Serial.println(error.f_str());
     return -1;
  }
  double result = doc["values"][0]["value"].as<double>();
  Serial.println(". done getting temperature = '" + (String)result + "'");
      
  return result;
}

double ReadHsKnxObj(String objectId)
{
  Serial.print("start ReadHsKnxObj for " + objectId + "...");
  String request = "https://IP-HOMESERVER/endpoints/call?key=" + objectId + "&method=get&authorization=" + HSWSSApiKey;  
  http.setTimeout(60);
  http.setReuse(false);  
  http.begin(request);
  int httpResponseCode = http.GET();
  delay(50);
  String response = http.getString();
  http.end();
      
  DeserializationError error = deserializeJson(doc, response);
  if(error) {
     Serial.print(F("ReadHsKnxObj deserializeJson() failed: "));
     Serial.println(error.f_str());
     return -1;
  }

  double result = doc["data"]["value"].as<double>();
  Serial.println(". done reading knx objekt = '" + (String)result + "'");
      
  return result;
}

String GetCurrentTime()
{
  int timeoutCnt = 0;
  int httpResponseCode = -1;
  String response;
  do {
    timeoutCnt++ ;

    Serial.print((String)timeoutCnt + ", start GetCurrentTime...");
    String request = "https://worldtimeapi.org/api/timezone/Europe/Berlin";    
    http.setTimeout(60 * 1000);
    http.setReuse(false);  
    http.begin(request);
    httpResponseCode = http.GET();
    delay(500);  
    response = http.getString();
    http.end();
    Serial.println(". request done (" + (String)httpResponseCode + ")");
  } while (httpResponseCode != 200 && timeoutCnt < 5);

  if (timeoutCnt >= 5)
  {
     Serial.println("error getting current time after 5 retrys");
     return "01.01.1990 00:00:00";    
  }

  Serial.print("start parsing...") ;
  DeserializationError error = deserializeJson(doc, response);
  if(error) {
     Serial.print(F("GetCurrentTime deserializeJson() failed: "));
     Serial.println(error.f_str());
     return "01.01.1990 00:00:00";    
  }

  response = doc["datetime"].as<String>();
  String dateStr = getStringSplitValue(response, 'T', 0); // 2021-11-01     
  String timeStr = getStringSplitValue(response, 'T', 1); // 00:57:26.041817+01:00
  timeStr = getStringSplitValue(timeStr, '.', 0);
  
  String result = getStringSplitValue(dateStr, '-', 2) + "." + getStringSplitValue(dateStr, '-', 1) + "." + getStringSplitValue(dateStr, '-', 0);
  result = result + " " + timeStr;

  Serial.println("... done parsing = '" + result + "'") ;

  return result;
}

String getStringSplitValue(String data, char separator, int index)
{
  int found = 0;
  int strIndex[] = {0, -1};
  int maxIndex = data.length()-1;

  for(int i=0; i<=maxIndex && found<=index; i++){
    if(data.charAt(i)==separator || i==maxIndex){
        found++;
        strIndex[0] = strIndex[1]+1;
        strIndex[1] = (i == maxIndex) ? i+1 : i;
    }
  }

  return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
}

void GetWeatherForecast()
{
  int timeoutCnt = 0;
  int httpResponseCode = -1;
  String response;
  do {
    timeoutCnt++ ;

    Serial.print((String)timeoutCnt + ", start GetWeatherForecast...");
    String request = "https://api.openweathermap.org/data/2.5/onecall?lat=1.1234&appid=**APIKEY**&exclude=current,minutely,alerts&units=metric&lang=de&lon=5.1234";  
    http.setTimeout(60 * 1000);
    http.setReuse(false);  
    http.begin(request);
    httpResponseCode = http.GET();
    delay(1000 * (timeoutCnt -1));  
    response = http.getString();
    http.end();
    Serial.println(". request done (" + (String)httpResponseCode + ")");
  } while (httpResponseCode != 200 && timeoutCnt < 5);

  if (timeoutCnt >= 5)
  {
     Serial.println("error getting weather forecast after 5 retrys");
     return;    
  }
  
  Serial.print("start parsing...");

  DeserializationError error = deserializeJson(doc, response);
  if(error) {
     Serial.print(F("GetWeatherForecast deserializeJson() failed: "));
     Serial.println(error.f_str());
     return;
  }

  Serial.println("parsing done");

  Serial.print("hour size " + (String)doc["hourly"].size());
  Serial.println("daily size " + (String)doc["daily"].size());

  int cnt = 0;
  for (int i = 0 ; i < 20 ; i = i + 2)
  {
    forecast2D[cnt].dt = doc["hourly"][i+1]["dt"].as<long>();
    forecast2D[cnt].description = doc["hourly"][i+1]["weather"][0]["description"].as<String>();
    forecast2D[cnt].icon = doc["hourly"][i+1]["weather"][0]["icon"].as<String>();
    forecast2D[cnt].clouds = (byte)doc["hourly"][i+1]["clouds"].as<double>();
    forecast2D[cnt].pop = doc["hourly"][i+1]["pop"].as<double>();
    forecast2D[cnt].rain = doc["hourly"][i+1]["rain"]["1h"].as<double>();
    forecast2D[cnt].temp = doc["hourly"][i+1]["temp"].as<double>();
    forecast2D[cnt].wind_deg = doc["hourly"][i+1]["wind_deg"].as<int>();
    forecast2D[cnt].wind_speed = doc["hourly"][i+1]["wind_speed"].as<double>();
    forecast2D[cnt].wind_gust = doc["hourly"][i+1]["wind_gust"].as<double>();
    cnt++;
  }

  for (int i = 0 ; i < doc["daily"].size()-1 ; i++)
  {
    forecast7D[i].dt = doc["daily"][i]["dt"].as<long>();
    forecast7D[i].description = doc["daily"][i]["weather"][0]["description"].as<String>();
    forecast7D[i].icon = doc["daily"][i]["weather"][0]["icon"].as<String>();
    forecast7D[i].clouds = (byte)doc["daily"][i]["clouds"].as<double>();
    forecast7D[i].pop = doc["daily"][i]["pop"].as<double>();
    forecast7D[i].rain = doc["daily"][i]["rain"].as<double>();    
    forecast7D[i].wind_deg = doc["daily"][i]["wind_deg"].as<int>();
    forecast7D[i].wind_speed = doc["daily"][i]["wind_speed"].as<double>();
    forecast7D[i].wind_gust = doc["daily"][i]["wind_gust"].as<double>();
    forecast7D[i].sunrise = doc["daily"][i]["sunrise"].as<String>();
    forecast7D[i].sunset = doc["daily"][i]["sunset"].as<String>();

    forecast7D[i].temp_day = doc["daily"][i]["temp"]["day"].as<double>();
    forecast7D[i].temp_min = doc["daily"][i]["temp"]["min"].as<double>();
    forecast7D[i].temp_max = doc["daily"][i]["temp"]["max"].as<double>();
    forecast7D[i].temp_night = doc["daily"][i]["temp"]["night"].as<double>();
    forecast7D[i].temp_eve = doc["daily"][i]["temp"]["eve"].as<double>();
    forecast7D[i].temp_morn = doc["daily"][i]["temp"]["morn"].as<double>();
  }  
}

String GetDatetimeString(long dt, bool withTime)
{
  time_t unixtime = (time_t)dt;

  String sDay = (String)day(unixtime);
  if (sDay.length() == 1)
    sDay = "0" + sDay;

  String sMonth = (String)month(unixtime);
  if (sMonth.length() == 1)
    sMonth = "0" + sMonth;

  String sHour = (String)hour(unixtime);
  if (sHour.length() == 1)
    sHour = "0" + sHour;

  String sMinute = (String)minute(unixtime);
  if (sMinute.length() == 1)
    sMinute = "0" + sMinute;

  if (withTime)
	return sDay + "." + sMonth + " " + sHour + ":" + sMinute;
  else
	return sDay + "." + sMonth;
}

String RemoveUmlaute(String text)
{
  text.replace("ä", "ae");
  text.replace("ü", "ue");
  text.replace("ö", "oe");
  text.replace("Ä", "AE");
  text.replace("Ü", "UE");
  text.replace("Ö", "OE");
  text.replace("ß", "ss");
  return text;
}

Wenn ich Geräte baue, die mit IPS reden sollen, dann benutze ich die Library PubSubClient für die MQTT-Implementierung.

Vielen Dank für die Info. Das ist sicher ein super Ansatz. Ich befürchte, dass ich damit alleine nicht weiter kommen werde. Für etwas mehr Beispiel oder Muster auf Seiten Arduino Programmierung und auf Seiten IPS wäre ich sehr dankbar. Einbindung der PubSub in das Script und wie ich dann die Daten von Variablen der IPS abfragen kann beispielsweise?

Es gibt ja Beispiele. Damit habe ich auch mal angefangen…

Bei konkreten Fragen kann ich versuchen, zu helfen.