Warum ausgerechnet ein E-Paper-Display?
Ein E-Paper-Display ist für dieses Projekt besonders geeignet, da es extrem stromsparend ist. Der entscheidende Vorteil liegt darin, dass das Display nur Energie benötigt, wenn es aktualisiert wird. Nach der Aktualisierung behält es das angezeigte Bild ohne weiteren Stromverbrauch, was es ideal für Anwendungen macht, bei denen die Daten nur in regelmäßigen Abständen aktualisiert werden müssen.
Dank dieser Eigenschaft kann der ESP32-Mikrocontroller zwischen den Updates in den Deep-Sleep-Modus versetzt werden, wodurch der Energieverbrauch des gesamten Systems erheblich reduziert wird. Dies macht das Setup perfekt für den Einsatz in Umgebungen, in denen Effizienz und geringe Betriebskosten im Vordergrund stehen, wie beispielsweise bei der Anzeige von Miner-Daten in Echtzeit.
Technische Daten des 6 Zoll 7-Farben E-Paper-Display von Soldered
Nachfolgend die technischen Daten des verwendeten 6" - 7-Farben E-Paper-Display von Soldered:
SchlüsselmerkmaleDetailsDisplaygröße5,85 Zoll (ca. 15 cm)Auflösung600 x 448 PixelFarbunterstützung7 FarbenBildaktualisierungTeilweise Updates, schnelle InhaltsveränderungMikrocontrollerESP32 mit eingebettetem WiFi und Bluetooth 4.0 (BLE)StromverbrauchSehr gering, 18 µA im Deep-Sleep-ModusStromversorgungLithium-Akku oder USB, integriertes LadegerätSpeicherkartenleserMicroSD KartenleserSchnittstellenZusätzliche GPIO Linien, easyC/Qwiic Kompatibilität, Unterstützung für I²C und SPISoftwareFertige Arduino Bibliothek (100 % kompatibel mit Adafruit GFX) und MicroPythonGehäuseoptionenOptional 3D-gedrucktes GehäuseAkkuoptionenOptional 1200mAh AkkuAbmessungen131,5 x 105,5 x 10 mmAbmessungen mit Gehäuse140 x 119,3 x 13,6 mm
Bitaxe - Dashboard
Nachfolgend das fertige Projekt zum Download. Du musst lediglich in der Datei statics.h die IP-Adresse auf deinen Bitaxe anpassen!
Programm: Dashboard eines Bitaxe auf einem E-Paper-DisplayHerunterladen
kompletter Quellcode des Projektes
Hier nun der komplette Quellcode für dieses Projekt. Was dir noch zusätzlich fehlt sind die Schriftarten welche du unter libslibrariesInkplateLibraryFonts findest.
#include
#include "HTTPClient.h"
#include "Inkplate.h"
#include "WiFi.h"
#include "statics.h"
#include "FreeMono9pt7b.h"
#include "FreeMonoBoldOblique24pt7b.h"
#include "FreeSansOblique9pt7b.h"
#include "FreeSansOblique12pt7b.h"
HTTPClient sender;
WiFiClient wifiClient;
Inkplate display;
struct HashRate {
double hashRate;
String bestDiff;
String bestSessionDiff;
};
struct Power {
double powerConsumption;
double voltage;
};
struct Temperature {
double asicTemp;
double voltageRegulatorTemp;
};
struct PoolData {
String stratumUrl;
int stratumPort;
String stratumUser;
};
struct WiFiConnection {
String ssid;
String macAddr;
String status;
String hostname;
};
struct AsicData {
int frequenz;
double coreVoltage;
String model;
int asicCount;
};
struct BitaxeData {
HashRate hashRate;
Power power;
Temperature temperature;
PoolData poolData;
WiFiConnection wiFiConnection;
AsicData asicData;
long timestamp;
};
BitaxeData bitaxeData;
long lastUpdate = -900000L;
const long PAUSE = 900000;
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_MODE_STA);
WiFi.begin(WIFI_SSID, WIFI_PWD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.print("IP-Adresse lautet: ");
Serial.println(WiFi.localIP());
display.begin();
//Einmaliges setzen der Uhrzeit / des Datums an der RTC.
//Dieser Wert wird durch eine Pufferbatterie gehalten!
display.rtcReset();
display.rtcSetTime(20, 13, 0);
display.rtcSetDate(1, 16, 12, 2024);
}
String readRTC() {
display.rtcGetRtcData();
int minutes = display.rtcGetMinute();
int hour = display.rtcGetHour();
int day = display.rtcGetDay();
int weekday = display.rtcGetWeekday();
int month = display.rtcGetMonth();
int year = display.rtcGetYear();
char buffer;
sprintf(buffer, "d.d.%d - d:d Uhr", day, month, year, hour, minutes);
return buffer;
}
void setText(String text, int coord_x, int coord_y, int color, int textSize) {
display.setTextColor(color);
display.setCursor(coord_x, coord_y);
display.setTextSize(textSize);
display.print(text);
}
void displayHashRate() {
display.drawRect(5, 100, 135, 75, INKPLATE_GREEN);
display.setFont(&FreeSansOblique12pt7b);
setText("HashRate", 20, 120, INKPLATE_GREEN, 1);
display.setFont(&FreeMono9pt7b);
setText(((String)bitaxeData.hashRate.hashRate) + " GH/s", 10, 140, INKPLATE_BLACK, 1);
setText(bitaxeData.hashRate.bestDiff, 10, 160, INKPLATE_BLACK, 1);
}
void displayPower() {
int offsetX = 185;
int offsetY = 100;
display.drawRect(offsetX, offsetY, 135, 75, INKPLATE_ORANGE);
display.setFont(&FreeSansOblique12pt7b);
setText("Power", offsetX + 35, offsetY + 20, INKPLATE_ORANGE, 1);
display.setFont(&FreeMono9pt7b);
setText(((String)bitaxeData.power.powerConsumption) + " W", offsetX + 10, offsetY + 40, INKPLATE_BLACK, 1);
double voltage = bitaxeData.power.voltage / 1000;
setText(((String)voltage) + " V", offsetX + 10, offsetY + 60, INKPLATE_BLACK, 1);
}
void displayTemperature() {
int offsetX = 370;
int offsetY = 100;
display.drawRect(offsetX, offsetY, 185, 75, INKPLATE_BLUE);
display.setFont(&FreeSansOblique12pt7b);
setText("Temperature", offsetX + 20, offsetY + 20, INKPLATE_BLUE, 1);
display.setFont(&FreeMono9pt7b);
setText("ASIC: " + ((String)bitaxeData.temperature.asicTemp) + " °C", offsetX + 10, offsetY + 40, INKPLATE_BLACK, 1);
setText("VR: " + ((String)bitaxeData.temperature.voltageRegulatorTemp) + " °C", offsetX + 10, offsetY + 60, INKPLATE_BLACK, 1);
}
void displayAsicData() {
int offsetX = 5;
int offsetY = 185;
display.drawRect(offsetX, offsetY, 185, 100, INKPLATE_BLACK);
display.setFont(&FreeSansOblique12pt7b);
setText("ASIC Data", offsetX + 20, offsetY + 20, INKPLATE_BLACK, 1);
display.setFont(&FreeMono9pt7b);
setText("Model: " + ((String)bitaxeData.asicData.model), offsetX + 10, offsetY + 40, INKPLATE_BLACK, 1);
setText("Freq.: " + ((String)bitaxeData.asicData.frequenz) + " MHz", offsetX + 10, offsetY + 60, INKPLATE_BLACK, 1);
double voltage = bitaxeData.asicData.coreVoltage / 1000;
setText("Voltage: " + ((String)voltage) + " V", offsetX + 10, offsetY + 80, INKPLATE_BLACK, 1);
}
void displayWiFiConnection() {
int offsetX = 205;
int offsetY = 185;
display.drawRect(offsetX, offsetY, 350, 100, INKPLATE_RED);
display.setFont(&FreeSansOblique12pt7b);
setText("WiFi Connection", offsetX + 100, offsetY + 20, INKPLATE_RED, 1);
display.setFont(&FreeMono9pt7b);
setText("Hostname: " + ((String)bitaxeData.wiFiConnection.hostname), offsetX + 10, offsetY + 40, INKPLATE_BLACK, 1);
setText("SSID: " + ((String)bitaxeData.wiFiConnection.ssid), offsetX + 10, offsetY + 60, INKPLATE_BLACK, 1);
setText("MAC-Address: " + (String)bitaxeData.wiFiConnection.macAddr, offsetX + 10, offsetY + 80, INKPLATE_BLACK, 1);
}
void loop() {
long currentMillis = millis();
if (currentMillis > (lastUpdate + PAUSE)) {
lastUpdate = currentMillis;
display.clearDisplay();
display.display();
display.fillScreen(INKPLATE_WHITE);
display.drawImage(LOGO_URL, 10, 0, true, false);
display.setFont(&FreeMonoBoldOblique24pt7b);
setText("Gamma v601", 195, 50, INKPLATE_BLACK, 1);
display.setFont(&FreeSansOblique12pt7b);
setText(readRTC(), 205, 80, INKPLATE_BLACK, 1);
if ((WiFi.status() == WL_CONNECTED)) {
WiFiClient client;
HTTPClient http;
String apiRequest = API_URL;
Serial.println(apiRequest);
http.begin(client, apiRequest.c_str());
int httpCode = http.GET();
String httpResponse = http.getString();
parseBitaxeJson(httpResponse);
http.end();
} else {
Serial.println("Keiner WiFi Verbindung!");
}
displayHashRate();
displayPower();
displayTemperature();
displayAsicData();
displayWiFiConnection();
//einen Text in den Footerbereich schreiben
display.setTextColor(INKPLATE_BLACK);
display.setCursor(80, 440);
display.setTextSize(1);
display.setFont(&FreeMono9pt7b);
display.print("Stefan Draeger - https://draeger-it.blog");
display.display();
}
}
void parseBitaxeJson(String httpResponse) {
int contentLength = httpResponse.length() + 1;
char json;
httpResponse.toCharArray(json, contentLength);
StaticJsonDocument doc;
DeserializationError error = deserializeJson(doc, json);
if (error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
return;
}
HashRate hashRate;
hashRate.hashRate = (double)doc;
String bestDiff = doc;
hashRate.bestDiff = bestDiff;
String bestSessionDiff = doc;
hashRate.bestSessionDiff = bestSessionDiff;
bitaxeData.hashRate = hashRate;
Power power;
power.powerConsumption = (double)doc;
power.voltage = (double)doc;
bitaxeData.power = power;
Temperature temperature;
temperature.asicTemp = (double)doc;
temperature.voltageRegulatorTemp = (double)doc;
bitaxeData.temperature = temperature;
PoolData poolData;
poolData.stratumPort = (int)doc;
String stratumUrl = doc;
poolData.stratumUrl = stratumUrl;
String stratumUser = doc;
poolData.stratumUser = stratumUser;
bitaxeData.poolData = poolData;
WiFiConnection wiFiConnection;
String hostname = doc;
wiFiConnection.hostname = hostname;
String macAddr = doc;
wiFiConnection.macAddr = macAddr;
String ssid = doc;
wiFiConnection.ssid = ssid;
String status = doc;
wiFiConnection.status = status;
bitaxeData.wiFiConnection = wiFiConnection;
AsicData asicData;
asicData.frequenz = (int)doc;
asicData.coreVoltage = (double)doc;
String model = doc;
asicData.model = model;
asicData.asicCount = (int)doc;
bitaxeData.asicData = asicData;
}
In der Datei statics.h. werden die Verbindungsdaten zum Router, die Adresse zum Bitaxe Logo und die API URL gespeichert.
#define WIFI_SSID "abc"
#define WIFI_PWD "1234567890"
#define LOGO_URL "https://draeger-it.blog/wp-content/uploads/2024/12/bitaxe_logo_klein.bmp"
#define API_URL "http://192.168.178.44/api/system/info"
Das Programmieren umfasst mehrere wichtige Schritte: von der Einrichtung der benötigten Bibliotheken und Konfiguration des ESP32 über die Verarbeitung der API-Daten bis hin zur grafischen Darstellung auf dem E-Paper-Display. Mit der Arduino IDE kannst du den Code einfach anpassen und erweitern, um das Projekt deinen Anforderungen entsprechend zu optimieren.
Wir gehen dabei strukturiert vor, sodass am Ende des Abschnitts dein Display die Miner-Daten korrekt anzeigt und regelmäßig aktualisiert.
Schritt 1 - Installieren des Boardtreibers für das E-Paper-Display
Damit wir das E-Paper-Display in der Arduino IDE programmieren können, müssen wir zunächst den Boardtreiber installieren. Zuvor müssen wir die nachfolgende URL zu den zusätzlichen Boardverwalter URLs hinzufügen.
https://raw.githubusercontent.com/SolderedElectronics/Dasduino-Board-Definitions-for-Arduino-IDE/master/package_Dasduino_Boards_index.json
Im Boardbverwalter (1) suchen wir nun nach Inkplate (2) und wählen am Eintrag "Inkplate Boards von Soldered" die Schaltfläche INSTALLIEREN (3).