API-Daten des Bitaxe Gamma mit ESP32 und E-Paper-Display visualisieren
Der Bitaxe Gamma v601 verfügt über eine leistungsstarke API-Schnittstelle, die es ermöglicht, aktuelle Daten wie Hashrate, Stromverbrauch und Temperatur als JSON abzurufen. In diesem Beitrag zeige ich dir Schritt für Schritt, wie du diese Daten abfragen und weiterverarbeiten kannst. https://youtu.be/sxCrJ0skcAQ Alle wichtigen Informationen zu den verfügbaren API-Endpunkten findest du in der offiziellen englischen Wiki-Seite. Dort wird beschrieben, wie du die Schnittstelle einrichtest und optimal nutzt. Am Ende des Beitrags wirst du wissen, wie du die Daten regelmäßig abrufst und beispielsweise auf einem E-Paper-Display anzeigen kannst.
Bitaxe Gamma v601 mit E-Paper-Display von Soldered Disclaimer: Für diesen Beitrag verwende ich den Bitaxe Gamma v601 von Bitcoinmerch.com sowie das 7-Zoll E-Paper-Display mit ESP32-Chip von Soldered. Beide Geräte wurden mir von den jeweiligen Unternehmen kostenfrei für Review-Zwecke zur Verfügung gestellt. Ich habe die Geräte bereits in separaten Beiträgen vorgestellt und ausführlich getestet. Da ich sie für dieses Projekt als ideal geeignet empfinde, zeige ich hier, wie sich ihre Funktionen optimal kombinieren lassen. Dieser Beitrag spiegelt ausschließlich meine persönliche Meinung wider, und es besteht keine Verpflichtung gegenüber den Herstellern.
Abrufen der Daten via Postman
Zunächst rufen wir die Daten einmal mittels Postman ab. Der Vorteil an Postman ist, dass die empfangenen Daten vernünftig angezeigt werden und man diese von dort auch speichern kann (sowie die gesendeten und empfangenen Daten). Postman ist ein kostenfreies Tool, mit welchem du HTTP & HTTPS Anfragen an Server senden und die Antwort auswerten kannst. Auf diesem Blog habe ich dieses Tool bereits öfters verwendet und verwende dieses ebenso auch in meinem Hauptberuf als Softwareentwickler für diverse Schnittstellen. Aufbau von Postman Postman dient wie erwähnt zum Absenden von HTTP / HTTPS Anfragen (1) dabei kannst du die Anfragemethode (2) frei wählen (GET, POST, PUT, ...). Zusätzlich kannst du noch Header Informationen und Daten für die Autorisierung mitgeben (dieses entfällt bei der Bitaxe API). Über die Schaltfläche "Send" (3) wird die URL inkl. aller Daten abgesendet und wir empfangen im Erfolgsfall die Antwort (5) der Datentyp wird über den übermittelten Content-Typ automatisch erkannt, kann aber auch umgestellt werden (4).
Postman - Bitaxe API Request
Entpoints der Bitaxe API
Die Bitaxe API bietet nachfolgende Endpoints zum Abrufen der Daten: - GET - Datenabfragen - http:///api/system/info - POST - Daten senden, Aktionen ausführen - http:///api/system/restart - http:///api/system/OTA - http:///api/system/OTAWWW - PATCH - Daten ändern - http:///api/system/ Möchtest du mehr über die HTTP Anfragemethoden erfahren, so empfehle ich dir die Seite https://wiki.selfhtml.org/wiki/HTTP/Anfragemethoden wo diese ausführlich behandelt und erläutert werden. Für diesen Beitrag benötigen wir lediglich die Daten, welche über http:///api/system/info abgerufen werden können. Wenn du in nachfolgenden Adressen und Bildern eine IP-Adresse wie 192.168.178.44 findest, so musst du diese gegen deine ersetzen.
E-Paper-Display mit ESP32
Für diesen Beitrag verwende ich das farbige E-Paper-Display mit ESP32 von Soldered welches ich dir bereits im Beitrag Erfahrungsbericht: Wie gut sind die neuen E-Paper Displays von Soldered? vorgestellt habe.
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
Programmieren des E-Paper-Displays in der Arduino IDE
Um das E-Paper-Display mit dem ESP32 zu programmieren, nutzen wir die Arduino IDE. In diesem Abschnitt zeige ich dir, wie du Schritt für Schritt die Steuerung des Displays implementierst, die API-Daten des Bitaxe Gamma v 601 abrufst und diese visuell ansprechend darstellst.
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).
Schritt 2 - Installieren der benötigten Bibliotheken Schritt 2.1 Inkplate für das E-Paper-Display Damit wir Text, Bilder und geometrische Figuren auf dem Display anzeigen lassen können, benötigen wir dazu noch eine Bibliothek. Diese können wir ebenso einfach wie den Boardtreiber installieren. Öffnen wir zunächst dne Bibliotheksverwalter (1) und suchen nach Inkplate (2) am Eintrag "InkplateLibrary von e-radionica.com" wählen wir die Schaltfläche INSTALLIEREN (3).
Schritt 2.2 ArduinoJSON für das parsen der API Daten vom Bitaxe Für das parsen der Daten im JSON-Format vom Bitaxe benötigen wir eine zusätzliche Bibliothek, hier verwende ich ArduinoJson. Read the full article

















