From 2bc5984f6ffb28f8ff1830ad44479bdea71838d2 Mon Sep 17 00:00:00 2001
From: kdmukai <kdmukai@gmail.com>
Date: Wed, 18 Dec 2024 15:58:12 -0600
Subject: [PATCH] Add mining pool daily/expected earnings

---
 lib/btclock/mining_pool_stats_handler.cpp | 84 ++++++++++++++++++++---
 lib/btclock/mining_pool_stats_handler.hpp |  3 +-
 src/lib/config.cpp                        |  1 +
 src/lib/defaults.hpp                      |  2 +-
 src/lib/mining_pool_stats_fetch.cpp       | 26 +++----
 src/lib/mining_pool_stats_fetch.hpp       |  2 +-
 src/lib/screen_handler.cpp                |  9 +--
 src/lib/shared.hpp                        |  1 +
 8 files changed, 95 insertions(+), 33 deletions(-)

diff --git a/lib/btclock/mining_pool_stats_handler.cpp b/lib/btclock/mining_pool_stats_handler.cpp
index 17eb4c8..6802e42 100644
--- a/lib/btclock/mining_pool_stats_handler.cpp
+++ b/lib/btclock/mining_pool_stats_handler.cpp
@@ -41,16 +41,10 @@ std::array<std::string, NUM_SCREENS> parseMiningPoolStatsHashRate(std::string mi
     // Account for the position of the mining pool logo and the hashrate label
     std::size_t startIndex = NUM_SCREENS - 1 - textLength;
 
-    std::cout << "miningPoolName: " << miningPoolName << std::endl;
-
-    // Insert the mining pool logo icon just before the digits
+    // Insert the pickaxe icon just before the digits
     if (startIndex > 0)
     {
-        if (miningPoolName == "ocean") {
-            ret[startIndex - 1] = "mdi:braiins_logo";
-        } else if (miningPoolName == "braiins") {
-            ret[startIndex - 1] = "mdi:braiins_logo";
-        }
+        ret[startIndex - 1] = "mdi:pickaxe";
     }
 
     // Place the digits
@@ -60,7 +54,79 @@ std::array<std::string, NUM_SCREENS> parseMiningPoolStatsHashRate(std::string mi
     }
 
     ret[NUM_SCREENS - 1] = label;
-    ret[0] = "POOL/STATS";
+
+    // Set the mining pool logo
+    if (miningPoolName == "ocean") {
+        ret[0] = "mdi:ocean_logo";
+    } else if (miningPoolName == "braiins") {
+        ret[0] = "mdi:braiins_logo";
+    }
+
+    return ret;
+}
+
+
+std::array<std::string, NUM_SCREENS> parseMiningPoolStatsDailyEarnings(std::string miningPoolName, int sats)
+{
+    std::array<std::string, NUM_SCREENS> ret;
+    ret.fill(""); // Initialize all elements to empty strings
+    std::string satsDisplay = std::to_string(sats);
+    std::string label;
+
+    if (miningPoolName == "braiins") {
+        // fpps guarantees payout; report current daily earnings
+        label = "sats/earned";
+    } else {
+        // TIDES can only estimate earnings on the next block Ocean finds
+        label = "sats/block";
+    }
+
+    if (sats >= 100000000) {
+        // A whale mining 1+ BTC per day! No decimal points; whales scoff at such things.
+        label = "BTC" + label.substr(4);
+        satsDisplay = satsDisplay.substr(0, satsDisplay.length() - 8);
+    } else if (sats >= 10000000) {
+        // 10.0M to 99.9M you get one decimal point
+        satsDisplay = satsDisplay.substr(0, satsDisplay.length() - 6) + "." + satsDisplay[2] + "M";
+    } else if (sats >= 1000000) {
+        // 1.00M to 9.99M you get two decimal points
+        satsDisplay = satsDisplay.substr(0, satsDisplay.length() - 6) + "." + satsDisplay.substr(2, 2) + "M";
+    } else if (sats >= 100000) {
+        // 100K to 999K you get no extra precision
+        satsDisplay = satsDisplay.substr(0, satsDisplay.length() - 3) + "K";
+    } else if (sats >= 10000) {
+        // 10.0K to 99.9K you get one decimal point
+        satsDisplay = satsDisplay.substr(0, satsDisplay.length() - 3) + "." + satsDisplay[2] + "K";
+    } else {
+        // Pleb miner! 4 digit or fewer sats will fit as-is. no-op.
+    }
+
+    std::size_t textLength = satsDisplay.length();
+
+    // Calculate the position where the digits should start
+    // Account for the position of the mining pool logo
+    std::size_t startIndex = NUM_SCREENS - 1 - textLength;
+
+    // Insert the pickaxe icon just before the digits if there's room
+    if (startIndex > 0)
+    {
+        ret[startIndex - 1] = "mdi:pickaxe";
+    }
+
+    // Place the digits
+    for (std::size_t i = 0; i < textLength; ++i)
+    {
+        ret[startIndex + i] = satsDisplay.substr(i, 1);
+    }
+
+    ret[NUM_SCREENS - 1] = label;
+
+    // Set the mining pool logo
+    if (miningPoolName == "ocean") {
+        ret[0] = "mdi:ocean_logo";
+    } else if (miningPoolName == "braiins") {
+        ret[0] = "mdi:braiins_logo";
+    }
 
     return ret;
 }
\ No newline at end of file
diff --git a/lib/btclock/mining_pool_stats_handler.hpp b/lib/btclock/mining_pool_stats_handler.hpp
index b79d8f9..495c7db 100644
--- a/lib/btclock/mining_pool_stats_handler.hpp
+++ b/lib/btclock/mining_pool_stats_handler.hpp
@@ -1,4 +1,5 @@
 #include <array>
 #include <string>
 
-std::array<std::string, NUM_SCREENS> parseMiningPoolStatsHashRate(std::string miningPoolName, std::string text);
\ No newline at end of file
+std::array<std::string, NUM_SCREENS> parseMiningPoolStatsHashRate(std::string miningPoolName, std::string text);
+std::array<std::string, NUM_SCREENS> parseMiningPoolStatsDailyEarnings(std::string miningPoolName, int sats);
diff --git a/src/lib/config.cpp b/src/lib/config.cpp
index f764b54..d8e71ef 100644
--- a/src/lib/config.cpp
+++ b/src/lib/config.cpp
@@ -340,6 +340,7 @@ void setupPreferences()
   if (preferences.getBool("miningPoolStatsEnabled", DEFAULT_MINING_POOL_STATS_ENABLED))
   {
     addScreenMapping(SCREEN_MINING_POOL_STATS_HASHRATE, "Mining Pool Hashrate");
+    addScreenMapping(SCREEN_MINING_POOL_STATS_EARNINGS, "Mining Pool Earnings");
   }
 }
 
diff --git a/src/lib/defaults.hpp b/src/lib/defaults.hpp
index 8380f46..3d28829 100644
--- a/src/lib/defaults.hpp
+++ b/src/lib/defaults.hpp
@@ -61,7 +61,7 @@
 #define MINING_POOL_NAME_OCEAN "ocean"
 #define MINING_POOL_NAME_BRAIINS "braiins"
 
-#define DEFAULT_MINING_POOL_STATS_ENABLED true
+#define DEFAULT_MINING_POOL_STATS_ENABLED false
 #define DEFAULT_MINING_POOL_NAME MINING_POOL_NAME_OCEAN
 #define DEFAULT_MINING_POOL_USER "38Qkkei3SuF1Eo45BaYmRHUneRD54yyTFy"  // Random actual Ocean hasher
 
diff --git a/src/lib/mining_pool_stats_fetch.cpp b/src/lib/mining_pool_stats_fetch.cpp
index 6fd3914..9de1cd7 100644
--- a/src/lib/mining_pool_stats_fetch.cpp
+++ b/src/lib/mining_pool_stats_fetch.cpp
@@ -3,13 +3,17 @@
 TaskHandle_t miningPoolStatsFetchTaskHandle;
 
 std::string miningPoolStatsHashrate;
-std::string miningPoolStatsBestDiff;
+int miningPoolStatsDailyEarnings;
 
 std::string getMiningPoolStatsHashRate()
 {
     return miningPoolStatsHashrate;
 }
 
+int getMiningPoolStatsDailyEarnings()
+{
+    return miningPoolStatsDailyEarnings;
+}
 
 void taskMiningPoolStatsFetch(void *pvParameters)
 {
@@ -21,25 +25,15 @@ void taskMiningPoolStatsFetch(void *pvParameters)
         http.setUserAgent(USER_AGENT);
         String miningPoolStatsApiUrl;
 
-        // TODO: Remove when webui gets proper update
-        Serial.println("FORCING miningPoolUser");
-        preferences.putString("miningPoolName", MINING_POOL_NAME_OCEAN);
-
-        Serial.println("miningPoolName: \"" + preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME) + "\"");
-        Serial.println("miningPoolUser: \"" + preferences.getString("miningPoolUser", DEFAULT_MINING_POOL_USER) + "\"");
-
         std::string httpHeaderKey = "";
         std::string httpHeaderValue;
         if (preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME) == MINING_POOL_NAME_OCEAN) {
             miningPoolStatsApiUrl = "https://api.ocean.xyz/v1/statsnap/" + preferences.getString("miningPoolUser", DEFAULT_MINING_POOL_USER);
-            Serial.println(miningPoolStatsApiUrl);
-
         }
         else if (preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME) == MINING_POOL_NAME_BRAIINS) {
             miningPoolStatsApiUrl = "https://pool.braiins.com/accounts/profile/json/btc/";
             httpHeaderKey = "Pool-Auth-Token";
             httpHeaderValue = preferences.getString("miningPoolUser", DEFAULT_MINING_POOL_USER).c_str();
-            Serial.println(miningPoolStatsApiUrl);
         }
         else
         {
@@ -64,14 +58,12 @@ void taskMiningPoolStatsFetch(void *pvParameters)
             Serial.println(doc.as<String>());
 
             if (preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME) == MINING_POOL_NAME_OCEAN) {
-                Serial.println(doc["result"].as<String>());
-                Serial.println(doc["result"]["hashrate_300s"].as<String>());
                 miningPoolStatsHashrate = doc["result"]["hashrate_300s"].as<std::string>();
+                miningPoolStatsDailyEarnings = int(doc["result"]["estimated_earn_next_block"].as<float>() * 100000000);
             }
             else if (preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME) == MINING_POOL_NAME_BRAIINS) {
                 // Reports hashrate in specific hashrate units (e.g. Gh/s); we want raw total hashes per second.
                 std::string hashrateUnit = doc["btc"]["hash_rate_unit"].as<std::string>();
-                Serial.println(doc["btc"]["hash_rate_unit"].as<String>());
                 int multiplier = 0;
                 if (hashrateUnit == "Zh/s") {
                     multiplier = 21;
@@ -91,11 +83,11 @@ void taskMiningPoolStatsFetch(void *pvParameters)
 
                 // Add zeroes to pad to a full h/s output
                 miningPoolStatsHashrate = std::to_string(static_cast<int>(std::round(doc["btc"]["hash_rate_5m"].as<float>()))) + std::string(multiplier, '0');
-                Serial.println(miningPoolStatsHashrate.c_str());
+
+                miningPoolStatsDailyEarnings = int(doc["btc"]["today_reward"].as<float>() * 100000000);
             }
 
-            // if (workQueue != nullptr && (getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE || getCurrentScreen() == SCREEN_MINING_POOL_STATS_BESTDIFF))
-            if (workQueue != nullptr && (getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE))
+            if (workQueue != nullptr && (getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE || getCurrentScreen() == SCREEN_MINING_POOL_STATS_EARNINGS))
             {
                 WorkItem priceUpdate = {TASK_MINING_POOL_STATS_UPDATE, 0};
                 xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
diff --git a/src/lib/mining_pool_stats_fetch.hpp b/src/lib/mining_pool_stats_fetch.hpp
index f06207b..bae5267 100644
--- a/src/lib/mining_pool_stats_fetch.hpp
+++ b/src/lib/mining_pool_stats_fetch.hpp
@@ -12,4 +12,4 @@ void setupMiningPoolStatsFetchTask();
 void taskMiningPoolStatsFetch(void *pvParameters);
 
 std::string getMiningPoolStatsHashRate();
-// std::string getMiningPoolStatsBestDiff();
\ No newline at end of file
+int getMiningPoolStatsDailyEarnings();
diff --git a/src/lib/screen_handler.cpp b/src/lib/screen_handler.cpp
index 5d8c41c..84f91d6 100644
--- a/src/lib/screen_handler.cpp
+++ b/src/lib/screen_handler.cpp
@@ -39,9 +39,9 @@ void workerTask(void *pvParameters) {
           if (getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE) {
           taskEpdContent =
                 parseMiningPoolStatsHashRate(preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str(), getMiningPoolStatsHashRate());
-          // } else if (getCurrentScreen() == SCREEN_BITAXE_BESTDIFF) {
-          // taskEpdContent =
-          //       parseBitaxeBestDiff(getBitaxeBestDiff());
+          } else if (getCurrentScreen() == SCREEN_MINING_POOL_STATS_EARNINGS) {
+          taskEpdContent =
+                parseMiningPoolStatsDailyEarnings(preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str(), getMiningPoolStatsDailyEarnings());
           }
           setEpdContent(taskEpdContent);
           break;
@@ -190,7 +190,8 @@ void setCurrentScreen(uint newScreen) {
       }
       break;
     }
-	  case SCREEN_MINING_POOL_STATS_HASHRATE: {
+	  case SCREEN_MINING_POOL_STATS_HASHRATE:
+	  case SCREEN_MINING_POOL_STATS_EARNINGS: {
       if (preferences.getBool("miningPoolStatsEnabled", DEFAULT_MINING_POOL_STATS_ENABLED)) {
         WorkItem miningPoolStatsUpdate = {TASK_MINING_POOL_STATS_UPDATE, 0};
         xQueueSend(workQueue, &miningPoolStatsUpdate, portMAX_DELAY);
diff --git a/src/lib/shared.hpp b/src/lib/shared.hpp
index 5fc2c2b..22e40b2 100644
--- a/src/lib/shared.hpp
+++ b/src/lib/shared.hpp
@@ -61,6 +61,7 @@ const PROGMEM int SCREEN_BITAXE_HASHRATE = 80;
 const PROGMEM int SCREEN_BITAXE_BESTDIFF = 81;
 
 const PROGMEM int SCREEN_MINING_POOL_STATS_HASHRATE = 85;
+const PROGMEM int SCREEN_MINING_POOL_STATS_EARNINGS = 86;
 
 const PROGMEM int SCREEN_COUNTDOWN = 98;
 const PROGMEM int SCREEN_CUSTOM = 99;