Merge pull request '[Feature] Adds mining pool screens' (#5) from kdmukai/btclock_v3:mining_stats_v2 into main
Reviewed-on: #5
This commit is contained in:
commit
c7ea2f3e4d
30 changed files with 1321 additions and 864 deletions
|
@ -142,7 +142,10 @@ jobs:
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
fs_file=$(find .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }} -name "littlefs*.bin")
|
fs_file=$(find .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }} -name "littlefs*.bin")
|
||||||
shasum -a 256 "$fs_file" | awk '{print $1}' > "${fs_file}.sha256"
|
echo $fs_file
|
||||||
|
fs_name=$(basename "$fs_file")
|
||||||
|
shasum -a 256 "$fs_file" | awk '{print $1}' > "${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${fs_name}.sha256"
|
||||||
|
cat "${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${fs_name}.sha256"
|
||||||
- name: Copy all artifacts to output folder
|
- name: Copy all artifacts to output folder
|
||||||
run: cp .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/*.bin .pio/boot_app0.bin ${{ matrix.chip.name }}_${{ matrix.epd_variant }}
|
run: cp .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/*.bin .pio/boot_app0.bin ${{ matrix.chip.name }}_${{ matrix.epd_variant }}
|
||||||
|
|
||||||
|
|
29
README.md
29
README.md
|
@ -17,7 +17,7 @@ Biggest differences with v2 are:
|
||||||
New features:
|
New features:
|
||||||
- BitAxe integration
|
- BitAxe integration
|
||||||
- Zap notifier
|
- Zap notifier
|
||||||
-
|
- Braiins Pool and Ocean mining stats integration
|
||||||
|
|
||||||
"Steal focus on new block" means that when a new block is mined, the display will switch to the block height screen if it's not on it already.
|
"Steal focus on new block" means that when a new block is mined, the display will switch to the block height screen if it's not on it already.
|
||||||
|
|
||||||
|
@ -28,3 +28,30 @@ Most [information](https://github.com/btclock/btclock_v2/wiki) about BTClock v2
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
Use PlatformIO to build it yourself. Make sure you fetch the [WebUI](https://github.com/btclock/webui) submodule.
|
Use PlatformIO to build it yourself. Make sure you fetch the [WebUI](https://github.com/btclock/webui) submodule.
|
||||||
|
|
||||||
|
|
||||||
|
## Braiins Pool and Ocean integration
|
||||||
|
Enable mining pool stats by accessing your btclock's web UI (point a web browser at the device's IP address).
|
||||||
|
|
||||||
|
Under Settings -> Extra Features: toggle Enable Mining Pool Stats.
|
||||||
|
|
||||||
|
New options will appear. Select your mining pool and enter your pool username (Ocean) or api key (Braiins).
|
||||||
|
|
||||||
|
The Mining Pool Earnings screen displays:
|
||||||
|
* Braiins: Today's mining reward thus far
|
||||||
|
* Ocean: Your estimated earnings if the pool were to find a block right now
|
||||||
|
|
||||||
|
|
||||||
|
### Braiins Pool integration
|
||||||
|
Create an API key based on the steps [here](https://academy.braiins.com/en/braiins-pool/monitoring/#api-configuration).
|
||||||
|
|
||||||
|
The key's permissions should be:
|
||||||
|
* Web Access: no
|
||||||
|
* API Access: yes
|
||||||
|
* Access Permissions: Read-only
|
||||||
|
|
||||||
|
Copy the token that is created for the new key. Enter this as your "Mining Pool username or api key" in the btclock web UI.
|
||||||
|
|
||||||
|
|
||||||
|
### Ocean integration
|
||||||
|
Your "Mining Pool username" is just the onchain withdrawal address that you specify when pointing your miners at Ocean.
|
||||||
|
|
115
lib/btclock/mining_pool_stats_handler.cpp
Normal file
115
lib/btclock/mining_pool_stats_handler.cpp
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
#include "mining_pool_stats_handler.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
std::array<std::string, NUM_SCREENS> parseMiningPoolStatsHashRate(std::string text)
|
||||||
|
{
|
||||||
|
std::array<std::string, NUM_SCREENS> ret;
|
||||||
|
ret.fill(""); // Initialize all elements to empty strings
|
||||||
|
std::string hashrate;
|
||||||
|
std::string label;
|
||||||
|
|
||||||
|
if (text.length() > 21) {
|
||||||
|
// We are massively future-proof!!
|
||||||
|
label = "ZH/S";
|
||||||
|
hashrate = text.substr(0, text.length() - 21);
|
||||||
|
} else if (text.length() > 18) {
|
||||||
|
label = "EH/S";
|
||||||
|
hashrate = text.substr(0, text.length() - 18);
|
||||||
|
} else if (text.length() > 15) {
|
||||||
|
label = "PH/S";
|
||||||
|
hashrate = text.substr(0, text.length() - 15);
|
||||||
|
} else if (text.length() > 12) {
|
||||||
|
label = "TH/S";
|
||||||
|
hashrate = text.substr(0, text.length() - 12);
|
||||||
|
} else if (text.length() > 9) {
|
||||||
|
label = "GH/S";
|
||||||
|
hashrate = text.substr(0, text.length() - 9);
|
||||||
|
} else if (text.length() > 6) {
|
||||||
|
label = "MH/S";
|
||||||
|
hashrate = text.substr(0, text.length() - 6);
|
||||||
|
} else if (text.length() > 3) {
|
||||||
|
label = "KH/S";
|
||||||
|
hashrate = text.substr(0, text.length() - 3);
|
||||||
|
} else {
|
||||||
|
label = "H/S";
|
||||||
|
hashrate = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t textLength = hashrate.length();
|
||||||
|
|
||||||
|
// Calculate the position where the digits should start
|
||||||
|
// Account for the position of the mining pool logo and the hashrate label
|
||||||
|
std::size_t startIndex = NUM_SCREENS - 1 - textLength;
|
||||||
|
|
||||||
|
// Insert the pickaxe icon just before the digits
|
||||||
|
if (startIndex > 0)
|
||||||
|
{
|
||||||
|
ret[startIndex - 1] = "mdi:pickaxe";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Place the digits
|
||||||
|
for (std::size_t i = 0; i < textLength; ++i)
|
||||||
|
{
|
||||||
|
ret[startIndex + i] = hashrate.substr(i, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret[NUM_SCREENS - 1] = label;
|
||||||
|
|
||||||
|
|
||||||
|
ret[0] = "mdi:miningpool";
|
||||||
|
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::array<std::string, NUM_SCREENS> parseMiningPoolStatsDailyEarnings(int sats, std::string label)
|
||||||
|
{
|
||||||
|
std::array<std::string, NUM_SCREENS> ret;
|
||||||
|
ret.fill(""); // Initialize all elements to empty strings
|
||||||
|
std::string satsDisplay = std::to_string(sats);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
ret[0] = "mdi:miningpool";
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
5
lib/btclock/mining_pool_stats_handler.hpp
Normal file
5
lib/btclock/mining_pool_stats_handler.hpp
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
#include <array>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
std::array<std::string, NUM_SCREENS> parseMiningPoolStatsHashRate(std::string text);
|
||||||
|
std::array<std::string, NUM_SCREENS> parseMiningPoolStatsDailyEarnings(int sats, std::string label);
|
1518
src/icons/icons.cpp
1518
src/icons/icons.cpp
File diff suppressed because it is too large
Load diff
|
@ -95,6 +95,11 @@ void setup()
|
||||||
setupBitaxeFetchTask();
|
setupBitaxeFetchTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (preferences.getBool("miningPoolStats", DEFAULT_MINING_POOL_STATS_ENABLED))
|
||||||
|
{
|
||||||
|
setupMiningPoolStatsFetchTask();
|
||||||
|
}
|
||||||
|
|
||||||
setupButtonTask();
|
setupButtonTask();
|
||||||
setupOTA();
|
setupOTA();
|
||||||
|
|
||||||
|
@ -331,6 +336,14 @@ void setupPreferences()
|
||||||
addScreenMapping(SCREEN_BITAXE_HASHRATE, "BitAxe Hashrate");
|
addScreenMapping(SCREEN_BITAXE_HASHRATE, "BitAxe Hashrate");
|
||||||
addScreenMapping(SCREEN_BITAXE_BESTDIFF, "BitAxe Best Difficulty");
|
addScreenMapping(SCREEN_BITAXE_BESTDIFF, "BitAxe Best Difficulty");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (preferences.getBool("miningPoolStats", DEFAULT_MINING_POOL_STATS_ENABLED))
|
||||||
|
{
|
||||||
|
addScreenMapping(SCREEN_MINING_POOL_STATS_HASHRATE, "Mining Pool Hashrate");
|
||||||
|
if (getMiningPool()->supportsDailyEarnings()) {
|
||||||
|
addScreenMapping(SCREEN_MINING_POOL_STATS_EARNINGS, "Mining Pool Earnings");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String replaceAmbiguousChars(String input)
|
String replaceAmbiguousChars(String input)
|
||||||
|
@ -799,6 +812,19 @@ const char* getFirmwareFilename() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* getWebUiFilename() {
|
||||||
|
if (HW_REV == "REV_B_EPD_2_13") {
|
||||||
|
return "littlefs_8MB.bin";
|
||||||
|
} else if (HW_REV == "REV_A_EPD_2_13") {
|
||||||
|
return "littlefs_4MB.bin";
|
||||||
|
} else if (HW_REV == "REV_A_EPD_2_9") {
|
||||||
|
return "littlefs_4MB.bin";
|
||||||
|
} else {
|
||||||
|
return "littlefs_4MB.bin";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// void loadIcons() {
|
// void loadIcons() {
|
||||||
// size_t ocean_logo_size = 886;
|
// size_t ocean_logo_size = 886;
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "lib/ota.hpp"
|
#include "lib/ota.hpp"
|
||||||
#include "lib/nostr_notify.hpp"
|
#include "lib/nostr_notify.hpp"
|
||||||
#include "lib/bitaxe_fetch.hpp"
|
#include "lib/bitaxe_fetch.hpp"
|
||||||
|
#include "lib/mining_pool_stats_fetch.hpp"
|
||||||
|
|
||||||
#include "lib/v2_notify.hpp"
|
#include "lib/v2_notify.hpp"
|
||||||
|
|
||||||
|
@ -84,5 +85,5 @@ void addScreenMapping(int value, const char* name);
|
||||||
int findScreenIndexByValue(int value);
|
int findScreenIndexByValue(int value);
|
||||||
String replaceAmbiguousChars(String input);
|
String replaceAmbiguousChars(String input);
|
||||||
const char* getFirmwareFilename();
|
const char* getFirmwareFilename();
|
||||||
|
const char* getWebUiFilename();
|
||||||
// void loadIcons();
|
// void loadIcons();
|
|
@ -58,6 +58,10 @@
|
||||||
#define DEFAULT_BITAXE_ENABLED false
|
#define DEFAULT_BITAXE_ENABLED false
|
||||||
#define DEFAULT_BITAXE_HOSTNAME "bitaxe1"
|
#define DEFAULT_BITAXE_HOSTNAME "bitaxe1"
|
||||||
|
|
||||||
|
#define DEFAULT_MINING_POOL_STATS_ENABLED false
|
||||||
|
#define DEFAULT_MINING_POOL_NAME "ocean"
|
||||||
|
#define DEFAULT_MINING_POOL_USER "38Qkkei3SuF1Eo45BaYmRHUneRD54yyTFy" // Random actual Ocean hasher
|
||||||
|
|
||||||
#define DEFAULT_ZAP_NOTIFY_ENABLED false
|
#define DEFAULT_ZAP_NOTIFY_ENABLED false
|
||||||
#define DEFAULT_ZAP_NOTIFY_PUBKEY "b5127a08cf33616274800a4387881a9f98e04b9c37116e92de5250498635c422"
|
#define DEFAULT_ZAP_NOTIFY_PUBKEY "b5127a08cf33616274800a4387881a9f98e04b9c37116e92de5250498635c422"
|
||||||
#define DEFAULT_LED_FLASH_ON_ZAP true
|
#define DEFAULT_LED_FLASH_ON_ZAP true
|
||||||
|
|
|
@ -604,20 +604,36 @@ void renderIcon(const uint dispNum, const String &text, bool partial)
|
||||||
displays[dispNum].setTextColor(getFgColor());
|
displays[dispNum].setTextColor(getFgColor());
|
||||||
|
|
||||||
uint iconIndex = 0;
|
uint iconIndex = 0;
|
||||||
|
uint width = 122;
|
||||||
|
uint height = 122;
|
||||||
if (text.endsWith("rocket")) {
|
if (text.endsWith("rocket")) {
|
||||||
iconIndex = 1;
|
iconIndex = 1;
|
||||||
}
|
}
|
||||||
else if (text.endsWith("lnbolt")) {
|
else if (text.endsWith("lnbolt")) {
|
||||||
iconIndex = 3;
|
iconIndex = 2;
|
||||||
}
|
}
|
||||||
else if (text.endsWith("bitaxe")) {
|
else if (text.endsWith("bitaxe")) {
|
||||||
iconIndex = 4;
|
width = 122;
|
||||||
|
height = 250;
|
||||||
|
iconIndex = 3;
|
||||||
|
}
|
||||||
|
else if (text.endsWith("miningpool")) {
|
||||||
|
LogoData logo = getMiningPoolLogo();
|
||||||
|
|
||||||
|
int x_offset = (displays[dispNum].width() - logo.width) / 2;
|
||||||
|
int y_offset = (displays[dispNum].height() - logo.height) / 2;
|
||||||
|
// Close the file
|
||||||
|
|
||||||
|
displays[dispNum].drawInvertedBitmap(x_offset,y_offset, logo.data, logo.width, logo.height, getFgColor());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int x_offset = (displays[dispNum].width() - width) / 2;
|
||||||
|
int y_offset = (displays[dispNum].height() - height) / 2;
|
||||||
|
|
||||||
|
|
||||||
displays[dispNum].drawInvertedBitmap(0,0, epd_icons_allArray[iconIndex], 122, 250, getFgColor());
|
displays[dispNum].drawInvertedBitmap(x_offset,y_offset, epd_icons_allArray[iconIndex], width, height, getFgColor());
|
||||||
|
|
||||||
|
|
||||||
// displays[dispNum].drawInvertedBitmap(0,0, getOceanIcon(), 122, 250, getFgColor());
|
// displays[dispNum].drawInvertedBitmap(0,0, getOceanIcon(), 122, 250, getFgColor());
|
||||||
|
@ -627,6 +643,7 @@ void renderIcon(const uint dispNum, const String &text, bool partial)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void renderQr(const uint dispNum, const String &text, bool partial)
|
void renderQr(const uint dispNum, const String &text, bool partial)
|
||||||
{
|
{
|
||||||
#ifdef USE_QR
|
#ifdef USE_QR
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "lib/config.hpp"
|
#include "lib/config.hpp"
|
||||||
#include "lib/shared.hpp"
|
#include "lib/shared.hpp"
|
||||||
#include "icons/icons.h"
|
#include "icons/icons.h"
|
||||||
|
#include "mining_pool_stats_fetch.hpp"
|
||||||
|
|
||||||
#ifdef USE_QR
|
#ifdef USE_QR
|
||||||
#include "qrcodegen.h"
|
#include "qrcodegen.h"
|
||||||
|
|
32
src/lib/mining_pool/braiins/brains_pool.cpp
Normal file
32
src/lib/mining_pool/braiins/brains_pool.cpp
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#include "brains_pool.hpp"
|
||||||
|
|
||||||
|
void BraiinsPool::prepareRequest(HTTPClient& http) const {
|
||||||
|
http.addHeader("Pool-Auth-Token", poolUser.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BraiinsPool::getApiUrl() const {
|
||||||
|
return "https://pool.braiins.com/accounts/profile/json/btc/";
|
||||||
|
}
|
||||||
|
|
||||||
|
PoolStats BraiinsPool::parseResponse(const JsonDocument &doc) const
|
||||||
|
{
|
||||||
|
std::string unit = doc["btc"]["hash_rate_unit"].as<std::string>();
|
||||||
|
|
||||||
|
static const std::unordered_map<std::string, int> multipliers = {
|
||||||
|
{"Zh/s", 21}, {"Eh/s", 18}, {"Ph/s", 15}, {"Th/s", 12}, {"Gh/s", 9}, {"Mh/s", 6}, {"Kh/s", 3}};
|
||||||
|
|
||||||
|
int multiplier = multipliers.at(unit);
|
||||||
|
float hashValue = doc["btc"]["hash_rate_5m"].as<float>();
|
||||||
|
|
||||||
|
return PoolStats{
|
||||||
|
.hashrate = std::to_string(static_cast<int>(std::round(hashValue))) + std::string(multiplier, '0'),
|
||||||
|
.dailyEarnings = static_cast<int64_t>(doc["btc"]["today_reward"].as<float>() * 100000000)};
|
||||||
|
}
|
||||||
|
|
||||||
|
LogoData BraiinsPool::getLogo() const {
|
||||||
|
return LogoData{
|
||||||
|
.data = epd_icons_allArray[5],
|
||||||
|
.width = 122,
|
||||||
|
.height = 250
|
||||||
|
};
|
||||||
|
}
|
18
src/lib/mining_pool/braiins/brains_pool.hpp
Normal file
18
src/lib/mining_pool/braiins/brains_pool.hpp
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "lib/mining_pool/mining_pool_interface.hpp"
|
||||||
|
#include <icons/icons.h>
|
||||||
|
|
||||||
|
class BraiinsPool : public MiningPoolInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void setPoolUser(const std::string &user) override { poolUser = user; }
|
||||||
|
void prepareRequest(HTTPClient &http) const override;
|
||||||
|
std::string getApiUrl() const override;
|
||||||
|
PoolStats parseResponse(const JsonDocument &doc) const override;
|
||||||
|
LogoData getLogo() const override;
|
||||||
|
bool supportsDailyEarnings() const override { return true; }
|
||||||
|
std::string getDailyEarningsLabel() const override { return "sats/earned"; }
|
||||||
|
private:
|
||||||
|
static int getHashrateMultiplier(const std::string &unit);
|
||||||
|
};
|
10
src/lib/mining_pool/logo_data.hpp
Normal file
10
src/lib/mining_pool/logo_data.hpp
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
struct LogoData {
|
||||||
|
const uint8_t* data;
|
||||||
|
size_t width;
|
||||||
|
size_t height;
|
||||||
|
};
|
21
src/lib/mining_pool/mining_pool_interface.hpp
Normal file
21
src/lib/mining_pool/mining_pool_interface.hpp
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <HTTPClient.h>
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
#include "pool_stats.hpp"
|
||||||
|
#include "logo_data.hpp"
|
||||||
|
|
||||||
|
class MiningPoolInterface {
|
||||||
|
public:
|
||||||
|
virtual ~MiningPoolInterface() = default;
|
||||||
|
virtual void setPoolUser(const std::string& user) = 0;
|
||||||
|
virtual void prepareRequest(HTTPClient& http) const = 0;
|
||||||
|
virtual std::string getApiUrl() const = 0;
|
||||||
|
virtual PoolStats parseResponse(const JsonDocument& doc) const = 0;
|
||||||
|
virtual LogoData getLogo() const = 0;
|
||||||
|
virtual bool supportsDailyEarnings() const = 0;
|
||||||
|
virtual std::string getDailyEarningsLabel() const = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::string poolUser;
|
||||||
|
};
|
39
src/lib/mining_pool/noderunners/noderunners_pool.cpp
Normal file
39
src/lib/mining_pool/noderunners/noderunners_pool.cpp
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
// src/noderunners/noderunners_pool.cpp
|
||||||
|
#include "noderunners_pool.hpp"
|
||||||
|
|
||||||
|
void NodeRunnersPool::prepareRequest(HTTPClient& http) const {
|
||||||
|
// Empty as NodeRunners doesn't need special headers
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string NodeRunnersPool::getApiUrl() const {
|
||||||
|
return "https://pool.noderunners.network/api/v1/users/" + poolUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
PoolStats NodeRunnersPool::parseResponse(const JsonDocument& doc) const {
|
||||||
|
std::string hashrateStr = doc["hashrate1m"].as<std::string>();
|
||||||
|
char unit = hashrateStr.back();
|
||||||
|
std::string value = hashrateStr.substr(0, hashrateStr.size() - 1);
|
||||||
|
|
||||||
|
int multiplier = getHashrateMultiplier(unit);
|
||||||
|
|
||||||
|
return PoolStats{
|
||||||
|
.hashrate = value + std::string(multiplier, '0'),
|
||||||
|
.dailyEarnings = std::nullopt
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
LogoData NodeRunnersPool::getLogo() const {
|
||||||
|
return LogoData {
|
||||||
|
.data = epd_icons_allArray[6],
|
||||||
|
.width = 122,
|
||||||
|
.height = 122
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
int NodeRunnersPool::getHashrateMultiplier(char unit) {
|
||||||
|
static const std::unordered_map<char, int> multipliers = {
|
||||||
|
{'Z', 21}, {'E', 18}, {'P', 15}, {'T', 12},
|
||||||
|
{'G', 9}, {'M', 6}, {'K', 3}
|
||||||
|
};
|
||||||
|
return multipliers.at(unit);
|
||||||
|
}
|
20
src/lib/mining_pool/noderunners/noderunners_pool.hpp
Normal file
20
src/lib/mining_pool/noderunners/noderunners_pool.hpp
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "lib/mining_pool/mining_pool_interface.hpp"
|
||||||
|
#include <icons/icons.h>
|
||||||
|
|
||||||
|
class NodeRunnersPool : public MiningPoolInterface {
|
||||||
|
public:
|
||||||
|
void setPoolUser(const std::string& user) override { poolUser = user; }
|
||||||
|
|
||||||
|
void prepareRequest(HTTPClient& http) const override;
|
||||||
|
std::string getApiUrl() const override;
|
||||||
|
PoolStats parseResponse(const JsonDocument& doc) const override;
|
||||||
|
LogoData getLogo() const override;
|
||||||
|
bool supportsDailyEarnings() const override { return false; }
|
||||||
|
std::string getDailyEarningsLabel() const override { return ""; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
static int getHashrateMultiplier(char unit);
|
||||||
|
};
|
26
src/lib/mining_pool/ocean/ocean_pool.cpp
Normal file
26
src/lib/mining_pool/ocean/ocean_pool.cpp
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#include "ocean_pool.hpp"
|
||||||
|
|
||||||
|
void OceanPool::prepareRequest(HTTPClient& http) const {
|
||||||
|
// Empty as Ocean doesn't need special headers
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string OceanPool::getApiUrl() const {
|
||||||
|
return "https://api.ocean.xyz/v1/statsnap/" + poolUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
PoolStats OceanPool::parseResponse(const JsonDocument& doc) const {
|
||||||
|
return PoolStats{
|
||||||
|
.hashrate = doc["result"]["hashrate_300s"].as<std::string>(),
|
||||||
|
.dailyEarnings = static_cast<int64_t>(
|
||||||
|
doc["result"]["estimated_earn_next_block"].as<float>() * 100000000
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
LogoData OceanPool::getLogo() const {
|
||||||
|
return LogoData{
|
||||||
|
.data = epd_icons_allArray[4],
|
||||||
|
.width = 122,
|
||||||
|
.height = 122
|
||||||
|
};
|
||||||
|
}
|
15
src/lib/mining_pool/ocean/ocean_pool.hpp
Normal file
15
src/lib/mining_pool/ocean/ocean_pool.hpp
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "lib/mining_pool/mining_pool_interface.hpp"
|
||||||
|
#include <icons/icons.h>
|
||||||
|
|
||||||
|
class OceanPool : public MiningPoolInterface {
|
||||||
|
public:
|
||||||
|
void setPoolUser(const std::string& user) override { poolUser = user; }
|
||||||
|
void prepareRequest(HTTPClient& http) const override;
|
||||||
|
std::string getApiUrl() const override;
|
||||||
|
PoolStats parseResponse(const JsonDocument& doc) const override;
|
||||||
|
LogoData getLogo() const override;
|
||||||
|
bool supportsDailyEarnings() const override { return true; }
|
||||||
|
std::string getDailyEarningsLabel() const override { return "sats/block"; }
|
||||||
|
};
|
20
src/lib/mining_pool/pool_factory.cpp
Normal file
20
src/lib/mining_pool/pool_factory.cpp
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#include "pool_factory.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
const char* PoolFactory::MINING_POOL_NAME_OCEAN = "ocean";
|
||||||
|
const char* PoolFactory::MINING_POOL_NAME_NODERUNNERS = "noderunners";
|
||||||
|
const char* PoolFactory::MINING_POOL_NAME_BRAIINS = "braiins";
|
||||||
|
|
||||||
|
std::unique_ptr<MiningPoolInterface> PoolFactory::createPool(const std::string& poolName) {
|
||||||
|
static const std::unordered_map<std::string, std::function<std::unique_ptr<MiningPoolInterface>()>> poolFactories = {
|
||||||
|
{MINING_POOL_NAME_OCEAN, []() { return std::make_unique<OceanPool>(); }},
|
||||||
|
{MINING_POOL_NAME_NODERUNNERS, []() { return std::make_unique<NodeRunnersPool>(); }},
|
||||||
|
{MINING_POOL_NAME_BRAIINS, []() { return std::make_unique<BraiinsPool>(); }}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto it = poolFactories.find(poolName);
|
||||||
|
if (it == poolFactories.end()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return it->second();
|
||||||
|
}
|
35
src/lib/mining_pool/pool_factory.hpp
Normal file
35
src/lib/mining_pool/pool_factory.hpp
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#pragma once
|
||||||
|
#include "mining_pool_interface.hpp"
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include "noderunners/noderunners_pool.hpp"
|
||||||
|
#include "braiins/brains_pool.hpp"
|
||||||
|
#include "ocean/ocean_pool.hpp"
|
||||||
|
|
||||||
|
class PoolFactory {
|
||||||
|
public:
|
||||||
|
static std::unique_ptr<MiningPoolInterface> createPool(const std::string& poolName);
|
||||||
|
static std::vector<std::string> getAvailablePools() {
|
||||||
|
return {
|
||||||
|
MINING_POOL_NAME_OCEAN,
|
||||||
|
MINING_POOL_NAME_NODERUNNERS,
|
||||||
|
MINING_POOL_NAME_BRAIINS
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string getAvailablePoolsAsString() {
|
||||||
|
const auto pools = getAvailablePools();
|
||||||
|
std::string result;
|
||||||
|
for (size_t i = 0; i < pools.size(); ++i) {
|
||||||
|
result += pools[i];
|
||||||
|
if (i < pools.size() - 1) {
|
||||||
|
result += ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
static const char* MINING_POOL_NAME_OCEAN;
|
||||||
|
static const char* MINING_POOL_NAME_NODERUNNERS;
|
||||||
|
static const char* MINING_POOL_NAME_BRAIINS;
|
||||||
|
};
|
10
src/lib/mining_pool/pool_stats.hpp
Normal file
10
src/lib/mining_pool/pool_stats.hpp
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
struct PoolStats {
|
||||||
|
std::string hashrate;
|
||||||
|
std::optional<int64_t> dailyEarnings;
|
||||||
|
};
|
99
src/lib/mining_pool_stats_fetch.cpp
Normal file
99
src/lib/mining_pool_stats_fetch.cpp
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
#include "mining_pool_stats_fetch.hpp"
|
||||||
|
|
||||||
|
TaskHandle_t miningPoolStatsFetchTaskHandle;
|
||||||
|
|
||||||
|
std::string miningPoolName;
|
||||||
|
std::string miningPoolStatsHashrate;
|
||||||
|
int miningPoolStatsDailyEarnings;
|
||||||
|
|
||||||
|
std::string getMiningPoolStatsHashRate()
|
||||||
|
{
|
||||||
|
return miningPoolStatsHashrate;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getMiningPoolStatsDailyEarnings()
|
||||||
|
{
|
||||||
|
return miningPoolStatsDailyEarnings;
|
||||||
|
}
|
||||||
|
|
||||||
|
void taskMiningPoolStatsFetch(void *pvParameters)
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||||
|
|
||||||
|
HTTPClient http;
|
||||||
|
http.setUserAgent(USER_AGENT);
|
||||||
|
|
||||||
|
std::string poolName = preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str();
|
||||||
|
std::string poolUser = preferences.getString("miningPoolUser", DEFAULT_MINING_POOL_USER).c_str();
|
||||||
|
|
||||||
|
auto poolInterface = PoolFactory::createPool(poolName);
|
||||||
|
if (!poolInterface)
|
||||||
|
{
|
||||||
|
Serial.println("Unknown mining pool: \"" + String(poolName.c_str()) + "\"");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
poolInterface->setPoolUser(poolUser);
|
||||||
|
std::string apiUrl = poolInterface->getApiUrl();
|
||||||
|
http.begin(apiUrl.c_str());
|
||||||
|
poolInterface->prepareRequest(http);
|
||||||
|
int httpCode = http.GET();
|
||||||
|
if (httpCode == 200)
|
||||||
|
{
|
||||||
|
String payload = http.getString();
|
||||||
|
JsonDocument doc;
|
||||||
|
deserializeJson(doc, payload);
|
||||||
|
|
||||||
|
PoolStats stats = poolInterface->parseResponse(doc);
|
||||||
|
miningPoolStatsHashrate = stats.hashrate;
|
||||||
|
|
||||||
|
if (stats.dailyEarnings)
|
||||||
|
{
|
||||||
|
miningPoolStatsDailyEarnings = *stats.dailyEarnings;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
miningPoolStatsDailyEarnings = 0; // or any other default value
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Serial.print(
|
||||||
|
F("Error retrieving mining pool data. HTTP status code: "));
|
||||||
|
Serial.println(httpCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupMiningPoolStatsFetchTask()
|
||||||
|
{
|
||||||
|
xTaskCreate(taskMiningPoolStatsFetch, "miningPoolStatsFetch", (6 * 1024), NULL, tskIDLE_PRIORITY,
|
||||||
|
&miningPoolStatsFetchTaskHandle);
|
||||||
|
|
||||||
|
xTaskNotifyGive(miningPoolStatsFetchTaskHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<MiningPoolInterface>& getMiningPool()
|
||||||
|
{
|
||||||
|
static std::unique_ptr<MiningPoolInterface> currentMiningPool;
|
||||||
|
|
||||||
|
if (!currentMiningPool) {
|
||||||
|
std::string poolName = preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str();
|
||||||
|
currentMiningPool = PoolFactory::createPool(poolName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentMiningPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogoData getMiningPoolLogo()
|
||||||
|
{
|
||||||
|
return getMiningPool()->getLogo();
|
||||||
|
}
|
19
src/lib/mining_pool_stats_fetch.hpp
Normal file
19
src/lib/mining_pool_stats_fetch.hpp
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <HTTPClient.h>
|
||||||
|
#include "mining_pool/pool_factory.hpp"
|
||||||
|
|
||||||
|
#include "lib/config.hpp"
|
||||||
|
#include "lib/shared.hpp"
|
||||||
|
|
||||||
|
extern TaskHandle_t miningPoolStatsFetchTaskHandle;
|
||||||
|
|
||||||
|
void setupMiningPoolStatsFetchTask();
|
||||||
|
void taskMiningPoolStatsFetch(void *pvParameters);
|
||||||
|
|
||||||
|
std::string getMiningPoolStatsHashRate();
|
||||||
|
int getMiningPoolStatsDailyEarnings();
|
||||||
|
|
||||||
|
std::unique_ptr<MiningPoolInterface>& getMiningPool();
|
||||||
|
LogoData getMiningPoolLogo();
|
|
@ -171,14 +171,13 @@ int downloadUpdateHandler(char updateType)
|
||||||
break;
|
break;
|
||||||
case UPDATE_WEBUI:
|
case UPDATE_WEBUI:
|
||||||
{
|
{
|
||||||
latestRelease = getLatestRelease("littlefs.bin");
|
latestRelease = getLatestRelease(getWebUiFilename());
|
||||||
// updateWebUi(latestRelease.fileUrl, U_SPIFFS);
|
// updateWebUi(latestRelease.fileUrl, U_SPIFFS);
|
||||||
// return 0;
|
// return 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// First, download the expected SHA256
|
// First, download the expected SHA256
|
||||||
String expectedSHA256 = downloadSHA256(latestRelease.checksumUrl);
|
String expectedSHA256 = downloadSHA256(latestRelease.checksumUrl);
|
||||||
if (expectedSHA256.isEmpty())
|
if (expectedSHA256.isEmpty())
|
||||||
|
|
|
@ -33,9 +33,19 @@ void workerTask(void *pvParameters) {
|
||||||
parseBitaxeBestDiff(getBitaxeBestDiff());
|
parseBitaxeBestDiff(getBitaxeBestDiff());
|
||||||
}
|
}
|
||||||
setEpdContent(taskEpdContent);
|
setEpdContent(taskEpdContent);
|
||||||
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
case TASK_MINING_POOL_STATS_UPDATE: {
|
||||||
|
if (getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE) {
|
||||||
|
taskEpdContent =
|
||||||
|
parseMiningPoolStatsHashRate(getMiningPoolStatsHashRate());
|
||||||
|
} else if (getCurrentScreen() == SCREEN_MINING_POOL_STATS_EARNINGS) {
|
||||||
|
taskEpdContent =
|
||||||
|
parseMiningPoolStatsDailyEarnings(getMiningPoolStatsDailyEarnings(), getMiningPool()->getDailyEarningsLabel());
|
||||||
|
}
|
||||||
|
setEpdContent(taskEpdContent);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case TASK_PRICE_UPDATE: {
|
case TASK_PRICE_UPDATE: {
|
||||||
uint currency = getCurrentCurrency();
|
uint currency = getCurrentCurrency();
|
||||||
uint price = getPrice(currency);
|
uint price = getPrice(currency);
|
||||||
|
@ -179,6 +189,17 @@ void setCurrentScreen(uint newScreen) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
case SCREEN_MINING_POOL_STATS_HASHRATE:
|
||||||
|
case SCREEN_MINING_POOL_STATS_EARNINGS: {
|
||||||
|
if (preferences.getBool("miningPoolStats", DEFAULT_MINING_POOL_STATS_ENABLED)) {
|
||||||
|
WorkItem miningPoolStatsUpdate = {TASK_MINING_POOL_STATS_UPDATE, 0};
|
||||||
|
xQueueSend(workQueue, &miningPoolStatsUpdate, portMAX_DELAY);
|
||||||
|
} else {
|
||||||
|
setCurrentScreen(SCREEN_BLOCK_HEIGHT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <data_handler.hpp>
|
#include <data_handler.hpp>
|
||||||
#include <bitaxe_handler.hpp>
|
#include <bitaxe_handler.hpp>
|
||||||
|
#include <mining_pool_stats_handler.hpp>
|
||||||
|
|
||||||
#include "lib/epd.hpp"
|
#include "lib/epd.hpp"
|
||||||
#include "lib/shared.hpp"
|
#include "lib/shared.hpp"
|
||||||
|
@ -23,7 +24,8 @@ typedef enum {
|
||||||
TASK_BLOCK_UPDATE,
|
TASK_BLOCK_UPDATE,
|
||||||
TASK_FEE_UPDATE,
|
TASK_FEE_UPDATE,
|
||||||
TASK_TIME_UPDATE,
|
TASK_TIME_UPDATE,
|
||||||
TASK_BITAXE_UPDATE
|
TASK_BITAXE_UPDATE,
|
||||||
|
TASK_MINING_POOL_STATS_UPDATE
|
||||||
} TaskType;
|
} TaskType;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
|
@ -42,24 +42,16 @@ const PROGMEM int SCREEN_BLOCK_FEE_RATE = 6;
|
||||||
const PROGMEM int SCREEN_SATS_PER_CURRENCY = 10;
|
const PROGMEM int SCREEN_SATS_PER_CURRENCY = 10;
|
||||||
|
|
||||||
const PROGMEM int SCREEN_BTC_TICKER = 20;
|
const PROGMEM int SCREEN_BTC_TICKER = 20;
|
||||||
// const PROGMEM int SCREEN_BTC_TICKER_USD = 20;
|
|
||||||
// const PROGMEM int SCREEN_BTC_TICKER_EUR = 21;
|
|
||||||
// const PROGMEM int SCREEN_BTC_TICKER_GBP = 22;
|
|
||||||
// const PROGMEM int SCREEN_BTC_TICKER_JPY = 23;
|
|
||||||
// const PROGMEM int SCREEN_BTC_TICKER_AUD = 24;
|
|
||||||
// const PROGMEM int SCREEN_BTC_TICKER_CAD = 25;
|
|
||||||
|
|
||||||
const PROGMEM int SCREEN_MARKET_CAP = 30;
|
const PROGMEM int SCREEN_MARKET_CAP = 30;
|
||||||
// const PROGMEM int SCREEN_MARKET_CAP_USD = 30;
|
|
||||||
// const PROGMEM int SCREEN_MARKET_CAP_EUR = 31;
|
const PROGMEM int SCREEN_MINING_POOL_STATS_HASHRATE = 70;
|
||||||
// const PROGMEM int SCREEN_MARKET_CAP_GBP = 32;
|
const PROGMEM int SCREEN_MINING_POOL_STATS_EARNINGS = 71;
|
||||||
// const PROGMEM int SCREEN_MARKET_CAP_JPY = 33;
|
|
||||||
// const PROGMEM int SCREEN_MARKET_CAP_AUD = 34;
|
|
||||||
// const PROGMEM int SCREEN_MARKET_CAP_CAD = 35;
|
|
||||||
|
|
||||||
const PROGMEM int SCREEN_BITAXE_HASHRATE = 80;
|
const PROGMEM int SCREEN_BITAXE_HASHRATE = 80;
|
||||||
const PROGMEM int SCREEN_BITAXE_BESTDIFF = 81;
|
const PROGMEM int SCREEN_BITAXE_BESTDIFF = 81;
|
||||||
|
|
||||||
|
|
||||||
const PROGMEM int SCREEN_COUNTDOWN = 98;
|
const PROGMEM int SCREEN_COUNTDOWN = 98;
|
||||||
const PROGMEM int SCREEN_CUSTOM = 99;
|
const PROGMEM int SCREEN_CUSTOM = 99;
|
||||||
const int SCREEN_COUNT = 7;
|
const int SCREEN_COUNT = 7;
|
||||||
|
@ -92,3 +84,14 @@ struct ScreenMapping {
|
||||||
|
|
||||||
String calculateSHA256(uint8_t* data, size_t len);
|
String calculateSHA256(uint8_t* data, size_t len);
|
||||||
String calculateSHA256(WiFiClient *stream, size_t contentLength);
|
String calculateSHA256(WiFiClient *stream, size_t contentLength);
|
||||||
|
|
||||||
|
namespace ArduinoJson {
|
||||||
|
template <typename T>
|
||||||
|
struct Converter<std::vector<T>> {
|
||||||
|
static void toJson(const std::vector<T>& src, JsonVariant dst) {
|
||||||
|
JsonArray array = dst.to<JsonArray>();
|
||||||
|
for (T item : src)
|
||||||
|
array.add(item);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -72,6 +72,10 @@ void IRAM_ATTR minuteTimerISR(void *arg) {
|
||||||
vTaskNotifyGiveFromISR(bitaxeFetchTaskHandle, &xHigherPriorityTaskWoken);
|
vTaskNotifyGiveFromISR(bitaxeFetchTaskHandle, &xHigherPriorityTaskWoken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (miningPoolStatsFetchTaskHandle != NULL) {
|
||||||
|
vTaskNotifyGiveFromISR(miningPoolStatsFetchTaskHandle, &xHigherPriorityTaskWoken);
|
||||||
|
}
|
||||||
|
|
||||||
if (xHigherPriorityTaskWoken == pdTRUE) {
|
if (xHigherPriorityTaskWoken == pdTRUE) {
|
||||||
portYIELD_FROM_ISR();
|
portYIELD_FROM_ISR();
|
||||||
}
|
}
|
||||||
|
|
|
@ -510,7 +510,7 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json)
|
||||||
settings["timePerScreen"].as<uint>() * 60);
|
settings["timePerScreen"].as<uint>() * 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
String strSettings[] = {"hostnamePrefix", "mempoolInstance", "nostrPubKey", "nostrRelay", "bitaxeHostname", "nostrZapPubkey", "httpAuthUser", "httpAuthPass", "gitReleaseUrl"};
|
String strSettings[] = {"hostnamePrefix", "mempoolInstance", "nostrPubKey", "nostrRelay", "bitaxeHostname", "miningPoolName", "miningPoolUser", "nostrZapPubkey", "httpAuthUser", "httpAuthPass", "gitReleaseUrl"};
|
||||||
|
|
||||||
for (String setting : strSettings)
|
for (String setting : strSettings)
|
||||||
{
|
{
|
||||||
|
@ -549,7 +549,7 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json)
|
||||||
"mowMode", "suffixShareDot", "flOffWhenDark",
|
"mowMode", "suffixShareDot", "flOffWhenDark",
|
||||||
"flAlwaysOn", "flDisable", "flFlashOnUpd",
|
"flAlwaysOn", "flDisable", "flFlashOnUpd",
|
||||||
"mempoolSecure", "useNostr", "bitaxeEnabled",
|
"mempoolSecure", "useNostr", "bitaxeEnabled",
|
||||||
"verticalDesc",
|
"miningPoolStats", "verticalDesc",
|
||||||
"nostrZapNotify", "stagingSource", "httpAuthEnabled"};
|
"nostrZapNotify", "stagingSource", "httpAuthEnabled"};
|
||||||
|
|
||||||
for (String setting : boolSettings)
|
for (String setting : boolSettings)
|
||||||
|
@ -714,10 +714,13 @@ void onApiSettingsGet(AsyncWebServerRequest *request)
|
||||||
root["bitaxeEnabled"] = preferences.getBool("bitaxeEnabled", DEFAULT_BITAXE_ENABLED);
|
root["bitaxeEnabled"] = preferences.getBool("bitaxeEnabled", DEFAULT_BITAXE_ENABLED);
|
||||||
root["bitaxeHostname"] = preferences.getString("bitaxeHostname", DEFAULT_BITAXE_HOSTNAME);
|
root["bitaxeHostname"] = preferences.getString("bitaxeHostname", DEFAULT_BITAXE_HOSTNAME);
|
||||||
|
|
||||||
|
root["miningPoolStats"] = preferences.getBool("miningPoolStats", DEFAULT_MINING_POOL_STATS_ENABLED);
|
||||||
|
root["miningPoolName"] = preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME);
|
||||||
|
root["miningPoolUser"] = preferences.getString("miningPoolUser", DEFAULT_MINING_POOL_USER);
|
||||||
|
root["availablePools"] = PoolFactory::getAvailablePools();
|
||||||
root["httpAuthEnabled"] = preferences.getBool("httpAuthEnabled", DEFAULT_HTTP_AUTH_ENABLED);
|
root["httpAuthEnabled"] = preferences.getBool("httpAuthEnabled", DEFAULT_HTTP_AUTH_ENABLED);
|
||||||
root["httpAuthUser"] = preferences.getString("httpAuthUser", DEFAULT_HTTP_AUTH_USERNAME);
|
root["httpAuthUser"] = preferences.getString("httpAuthUser", DEFAULT_HTTP_AUTH_USERNAME);
|
||||||
root["httpAuthPass"] = preferences.getString("httpAuthPass", DEFAULT_HTTP_AUTH_PASSWORD);
|
root["httpAuthPass"] = preferences.getString("httpAuthPass", DEFAULT_HTTP_AUTH_PASSWORD);
|
||||||
|
|
||||||
#ifdef HAS_FRONTLIGHT
|
#ifdef HAS_FRONTLIGHT
|
||||||
root["hasFrontlight"] = true;
|
root["hasFrontlight"] = true;
|
||||||
root["flDisable"] = preferences.getBool("flDisable");
|
root["flDisable"] = preferences.getBool("flDisable");
|
||||||
|
@ -751,17 +754,8 @@ void onApiSettingsGet(AsyncWebServerRequest *request)
|
||||||
#endif
|
#endif
|
||||||
JsonArray screens = root["screens"].to<JsonArray>();
|
JsonArray screens = root["screens"].to<JsonArray>();
|
||||||
|
|
||||||
JsonArray actCurrencies = root["actCurrencies"].to<JsonArray>();
|
root["actCurrencies"] = getActiveCurrencies();
|
||||||
for (const auto &str : getActiveCurrencies())
|
root["availableCurrencies"] = getAvailableCurrencies();
|
||||||
{
|
|
||||||
actCurrencies.add(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
JsonArray availableCurrencies = root["availableCurrencies"].to<JsonArray>();
|
|
||||||
for (const auto &str : getAvailableCurrencies())
|
|
||||||
{
|
|
||||||
availableCurrencies.add(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<ScreenMapping> screenNameMap = getScreenNameMap();
|
std::vector<ScreenMapping> screenNameMap = getScreenNameMap();
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "lib/price_notify.hpp"
|
#include "lib/price_notify.hpp"
|
||||||
#include "lib/screen_handler.hpp"
|
#include "lib/screen_handler.hpp"
|
||||||
#include "webserver/OneParamRewrite.hpp"
|
#include "webserver/OneParamRewrite.hpp"
|
||||||
|
#include "lib/mining_pool/pool_factory.hpp"
|
||||||
|
|
||||||
extern TaskHandle_t eventSourceTaskHandle;
|
extern TaskHandle_t eventSourceTaskHandle;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue