#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include <SPI.h>
#include <TFT_eSPI.h>
#include <Wire.h>
#include <SD.h>
#include <WiFi.h>
// Home-WLAN
//char* ssid = "HUAWEI_E5785_9C01";
//char* password = "E2NTBJ9YTHG";
// TEST-WLAN
char* ssid = "Wokwi-GUEST";
char* password = "";
#define TFT_DC 2
#define TFT_CS 15
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
// Meter colour schemes
#define RED2RED 0
#define GREEN2GREEN 1
#define BLUE2BLUE 2
#define BLUE2RED 3
#define GREEN2RED 4
#define RED2GREEN 5
#define LRED2LGREEN 6
#define ILI9341_GREY 0x2104 // Dark grey 16 bit colour
#define COLOR_SCHEME 0x94b2 // Rahmenfarbe
#define BACK_COLOR 0x3186 //Hintergrundfarbe
uint32_t runTime = -99999; // time for next update
uint32_t runTime_rot = 0; // Zeitstempel für Pumpensymbol
uint32_t aktTime = 0; // Zeitstempel für Pumpensymbol
int d = 1; // Variable used for the sinewave test waveform
int a = 0; // Zähler für Pumpensymbol
// Status
int WorkMode = 0;
int BypassMode = 0;
char* WorkModeStr = "AUTO";
char* BypassModeStr = "OFF";
bool PumpMode_C = false;
bool PumpMode_W = false;
//für Routine Daten einlesen
String power_id = "po";
String PumpeK_id = "pk";
String PumpeW_id = "pw";
String Mode_id = "mo";
String Bypass_id = "by";
char symend = '$'; // Datenende = $-zeichen
//Messdaten
String incomingData; // Messdaten vom Sender
float 01_tempCin = 0; // Messwert 1 Temp Cold in
float 02_tempCout = 0; // Messwert 2 Temp Cold out
float 03_tempWin = 0; //
int _power = 9672; //wird errechnet
File Textdatei; // Datei zum Speichern der Messdaten
//----------------------------------------------------------
void setup() {
Serial.begin(9600);
tft.begin();
/* mainscreen();
triangle_rota_25_static (44, 99, COLOR_SCHEME, "C");
triangle_rota_25_static (44, 163, COLOR_SCHEME, "W");
ringMeter(0, 0, 200, 105, 25, 100, "", GREEN2GREEN); // Draw empty analogue meter
// WIFI initialisieren
WiFi.begin(ssid, password);
aktTime = millis();
tft.setTextColor(COLOR_SCHEME);
while (WiFi.status() != WL_CONNECTED) {
if (millis()>= aktTime + 10000) {
tft.setTextColor(ILI9341_GREY);
tft.setCursor(275,8);
tft.print("no WIFI");
break;
}
delay(300);
tft.setTextColor(COLOR_SCHEME);
tft.setCursor(292,8);
tft.print("WIFI");
delay(300);
tft.setTextColor(BACK_COLOR);
tft.setCursor(292,8);
tft.print("WIFI ");
}
if (WiFi.status() == WL_CONNECTED) {
tft.setTextColor(COLOR_SCHEME);
tft.setCursor(292,8);
tft.print("WIFI");
}
// SD prüfen und initialisieren
if (!SD.begin(5)) { // Wenn die SD-Karte nicht (!SD.begin) gefunden werden kann, ...
tft.setTextColor(ILI9341_GREY);
tft.setCursor(285,19);
tft.print("no SD");
return;
}
else {
Textdatei = SD.open("Messdaten.dat", FILE_WRITE); // An dieser Stelle wird die Textdatei erstellt. Unsere Textdatei soll "test" heißen und im Format ".txt" (Text) erstellt werden.
tft.setTextColor(COLOR_SCHEME);
tft.setCursor(300,19);
tft.print("SD");
} */
// TEST DATASCREEN
datascreen();
}
void loop() { /*
if (millis() - runTime >= 200L) { // Execute every 1s
runTime = millis();
if (Serial.available() > 0) {
datadissect();
}
if (PumpMode_C == true) {
triangle_rota_25 (44, 99, COLOR_SCHEME, "C");
}
if (PumpMode_W == true) {
triangle_rota_25 (44, 163, COLOR_SCHEME, "W");
}
ringMeter(power, 0, 200, 105, 25, 100, "Watts", GREEN2RED); // Draw analogue meter
} */
}
void mainscreen() {
tft.fillScreen(BACK_COLOR);
tft.setRotation(1);
tft.setTextSize(1);
tft.fillRoundRect(2,2,110,25,13, COLOR_SCHEME);
tft.fillRoundRect(42,4,66,21,11, BACK_COLOR);
tft.fillRoundRect(2,40,85,160,13, COLOR_SCHEME);
tft.fillRoundRect(4,65,81,133,11, BACK_COLOR);
tft.fillRoundRect(2,213,110,25,13, COLOR_SCHEME);
tft.fillRoundRect(63,215,45,21,11, BACK_COLOR);
tft.fillRoundRect(268,213,49,25,13, COLOR_SCHEME);
tft.setTextColor(ILI9341_BLACK);
tft.setCursor(12,10);
tft.print("MODE");
tft.setCursor(12,49);
tft.print("PUMPS");
tft.setCursor(12,222);
tft.print("BYPASS");
tft.setCursor(279,222);
tft.print("SETUP");
tft.setTextColor(ILI9341_WHITE);
tft.setCursor(62,10);
tft.print(WorkMode);
tft.setCursor(78,222);
tft.print(BypassMode);
}
void datascreen() {
tft.setRotation(1);
tft.setCursor(0,0);
tft.fillScreen(BACK_COLOR);
tft.setTextSize(2);
tft.setTextColor(ILI9341_WHITE);
tft.setCursor(0,0);
tft.println("Temp amb: ");
tft.println("Humidity amb: ");
tft.println("Temp Cold in: ");
tft.println("Temp Cold out: ");
tft.println("Temp Warm in: ");
tft.println("Temp Warm out: ");
tft.println("Delta Temp Cold: ");
tft.println("Delta Temp Warm: ");
tft.println("Delta Warm/Cold in: ");
tft.println("Delta Warm/Cold out: ");
tft.println("Voltage: ");
tft.println("Current: ");
tft.print("Power: ");
tft.println(power);
}
void wifiscreen() {
tft.setRotation(1);
tft.setCursor(0,0);
tft.fillScreen(BACK_COLOR);
tft.setTextSize(2);
tft.setTextColor(ILI9341_WHITE);
tft.setCursor(0,0);
tft.print("WIFI: ");
tft.println(WiFi.localIP());
tft.print("SSID: ");
tft.println(ssid);
}
void setupscreen() {
tft.fillScreen(BACK_COLOR);
tft.setRotation(1);
tft.setTextSize(1);
}
void datadissect(){
if (Serial.available() > 0) {
incomingData = Serial.readStringUntil(symend);
if (incomingData.indexOf(power_id) == 0) {
String raw_str = incomingData.substring(2, 6);// der gesendete Wert als STRING
Power = raw_str.toInt();
}
if (incomingData.indexOf(PumpeK_id) == 0) {
String raw_str = incomingData.substring(2, 3);// der gesendete Wert als STRING
PumpMode_C = raw_str.toInt();
}
if (incomingData.indexOf(PumpeW_id) == 0) {
String raw_str = incomingData.substring(2, 3);// der gesendete Wert als STRING
PumpMode_W = raw_str.toInt();
}
if (incomingData.indexOf(Mode_id) == 0) {
String raw_str = incomingData.substring(2, 3);// der gesendete Wert als STRING
WorkMode = raw_str.toInt();
if ( WorkMode == 1) {
WorkModeStr = "MANUAL";
tft.fillSmoothRoundRect(42,4,66,21,11, BACK_COLOR, COLOR_SCHEME); // Status Modus
tft.setCursor(58,10);
tft.print(WorkModeStr);
}
else{
WorkModeStr = "AUTO";
tft.fillSmoothRoundRect(42,4,66,21,11, BACK_COLOR, COLOR_SCHEME); // Status Modus
tft.setCursor(62,10);
tft.print(WorkModeStr);
}
}
if (incomingData.indexOf(Bypass_id) == 0) {
String raw_str = incomingData.substring(2, 3);// der gesendete Wert als STRING
BypassMode = raw_str.toInt();
if ( BypassMode == 1) {
BypassModeStr = "ON";
tft.fillSmoothRoundRect(63,215,45,21,11, BACK_COLOR, COLOR_SCHEME); // Bypass Modus
tft.setCursor(81,222);
tft.print(BypassModeStr);
}
else{
BypassModeStr = "OFF";
tft.fillSmoothRoundRect(63,215,45,21,11, BACK_COLOR, COLOR_SCHEME); // Bypass Modus
tft.setCursor(78,222);
tft.print(BypassModeStr);
}
}
}
}
void triangle_rota_25_static (int x_center, int y_center, int farbe, char* Zeichen){ //Pumpensymbol statisch
tft.fillTriangle (x_center-21, y_center-12, x_center+21, y_center-12, x_center, y_center+25, BACK_COLOR);
tft.fillTriangle (x_center-21, y_center+12, x_center+21, y_center+12, x_center, y_center-25, farbe);
tft.drawCircle(x_center, y_center, 25, farbe);
tft.fillCircle(x_center, y_center, 10, BACK_COLOR);
tft.setTextColor(ILI9341_WHITE);
tft.setCursor(x_center-2,y_center-3);
tft.print(Zeichen);
}
void triangle_rota_25 (int x_center, int y_center, int farbe, char* Zeichen){ //Pumpensymbol dynamisch
aktTime = millis();
if (aktTime >= (runTime_rot + 200)) {
a = a+1;
runTime_rot = aktTime;
}
if (a == 5) {a = 1;}
if (a == 1) {
tft.fillTriangle (x_center+12, y_center-21, x_center+12, y_center+21, x_center-25, y_center, BACK_COLOR); // den vorherigen löschen
tft.fillTriangle (x_center-21, y_center+12, x_center+21, y_center+12, x_center, y_center-25, farbe); // Spitze nach oben
tft.drawCircle(x_center, y_center, 25, farbe);
tft.fillCircle(x_center, y_center, 10, BACK_COLOR);
tft.setTextColor(ILI9341_WHITE);
tft.setCursor(x_center-2,y_center-3);
tft.print(Zeichen);
}
if (a == 2) {
tft.fillTriangle (x_center-21, y_center+12, x_center+21, y_center+12, x_center, y_center-25, BACK_COLOR);
tft.fillTriangle (x_center-12, y_center-21, x_center-12, y_center+21, x_center+25, y_center, farbe); // SPitze nach rechts
tft.drawCircle(x_center, y_center, 25, farbe);
tft.fillCircle(x_center, y_center, 10, BACK_COLOR);
tft.setTextColor(ILI9341_WHITE);
tft.setCursor(x_center-2,y_center-3);
tft.print(Zeichen);
}
if (a == 3) {
tft.fillTriangle (x_center-12, y_center-21, x_center-12, y_center+21, x_center+25, y_center, BACK_COLOR);
tft.fillTriangle (x_center-21, y_center-12, x_center+21, y_center-12, x_center, y_center+25, farbe); // Spitze nach unten
tft.drawCircle(x_center, y_center, 25, farbe);
tft.fillCircle(x_center, y_center, 10, BACK_COLOR);
tft.setTextColor(ILI9341_WHITE);
tft.setCursor(x_center-2,y_center-3);
tft.print(Zeichen);
}
if (a == 4) {
tft.fillTriangle (x_center-21, y_center-12, x_center+21, y_center-12, x_center, y_center+25, BACK_COLOR);
tft.fillTriangle (x_center+12, y_center-21, x_center+12, y_center+21, x_center-25, y_center, farbe); // Spitze nach links
tft.drawCircle(x_center, y_center, 25, farbe);
tft.fillCircle(x_center, y_center, 10, BACK_COLOR);
tft.setTextColor(ILI9341_WHITE);
tft.setCursor(x_center-2,y_center-3);
tft.print(Zeichen);
}
}
int ringMeter(int value, int vmin, int vmax, int x, int y, int r, char *units, byte scheme){
// Minimum value of r is about 52 before value text intrudes on ring
// drawing the text first is an option
x += r; y += r; // Calculate coords of centre of ring
int w = r / 4; // Width of outer ring is 1/4 of radius
int angle = 130; // Half the sweep angle of meter (300 degrees)
int text_colour = 0; // To hold the text colour
int v = map(value, vmin, vmax, -angle, angle); // Map the value to an angle v
byte seg = 5; // Segments are 5 degrees wide = 60 segments for 300 degrees
byte inc = 8; // Draw segments every 5 degrees, increase to 10 for segmented ring
// Draw colour blocks every inc degrees
for (int i = -angle; i < angle; i += inc) {
// Choose colour from scheme
int colour = 0;
switch (scheme) {
case 0: colour = ILI9341_RED; break; // Fixed colour
case 1: colour = ILI9341_GREEN; break; // Fixed colour
case 2: colour = ILI9341_BLUE; break; // Fixed colour
case 3: colour = rainbow(map(i, -angle, angle, 0, 127)); break; // Full spectrum blue to red
case 4: colour = rainbow(map(i, -angle, angle, 63, 127)); break; // Green to red (high temperature etc)
case 5: colour = rainbow(map(i, -angle, angle, 127, 63)); break; // Red to green (low battery etc)
case 6: colour = rainbow(map(i, -angle, angle, 100, 63)); break; // Red to green (low battery etc)
default: colour = ILI9341_BLUE; break; // Fixed colour
}
// Calculate pair of coordinates for segment start
float sx = cos((i - 90) * 0.0174532925);
float sy = sin((i - 90) * 0.0174532925);
uint16_t x0 = sx * (r - w) + x;
uint16_t y0 = sy * (r - w) + y;
uint16_t x1 = sx * r + x;
uint16_t y1 = sy * r + y;
// Calculate pair of coordinates for segment end
float sx2 = cos((i + seg - 90) * 0.0174532925);
float sy2 = sin((i + seg - 90) * 0.0174532925);
int x2 = sx2 * (r - w) + x;
int y2 = sy2 * (r - w) + y;
int x3 = sx2 * r + x;
int y3 = sy2 * r + y;
if (i < v) { // Fill in coloured segments with 2 triangles
tft.fillTriangle(x0, y0, x1, y1, x2, y2, colour);
tft.fillTriangle(x1, y1, x2, y2, x3, y3, colour);
text_colour = colour; // Save the last colour drawn
}
else // Fill in blank segments
{
tft.fillTriangle(x0, y0, x1, y1, x2, y2, ILI9341_GREY);
tft.fillTriangle(x1, y1, x2, y2, x3, y3, ILI9341_GREY);
}
}
// Convert value to a string
char buf[10];
byte len = 4; if (value > 999) len = 5;
dtostrf(value, len, 0, buf);
// Set the text colour to default
tft.setTextColor(ILI9341_WHITE, 0x188);
// Uncomment next line to set the text colour to the last segment value!
tft.setTextColor(text_colour, 0x188);
// Print value, if the meter is large then use big font 6, othewise use 4
/*
if (r > 84) tft.drawCentreString(buf, x - 5, y - 20, 6); // Value in middle
else tft.drawCentreString(buf, x - 5, y - 20, 4); // Value in middle
// Print units, if the meter is large then use big font 4, othewise use 2
tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
if (r > 84) tft.drawCentreString(units, x, y + 30, 4); // Units display
else tft.drawCentreString(units, x, y + 5, 2); // Units display
*/
// Calculate and return right hand side x coordinate
return x + r;
}
unsigned int rainbow(byte value){
// Value is expected to be in range 0-127
// The value is converted to a spectrum colour from 0 = blue through to 127 = red
byte red = 0; // Red is the top 5 bits of a 16 bit colour value
byte green = 0;// Green is the middle 6 bits
byte blue = 0; // Blue is the bottom 5 bits
byte quadrant = value / 32;
if (quadrant == 0) {
blue = 31;
green = 2 * (value % 32);
red = 0;
}
if (quadrant == 1) {
blue = 31 - (value % 32);
green = 63;
red = 0;
}
if (quadrant == 2) {
blue = 0;
green = 63;
red = value % 32;
}
if (quadrant == 3) {
blue = 0;
green = 63 - 2 * (value % 32);
red = 31;
}
return (red << 11) + (green << 5) + blue;
}
// #########################################################################
// Return a value in range -1 to +1 for a given phase angle in degrees
// #########################################################################
float sineWave(int phase) {
return sin(phase * 0.0174532925);
}