Add sats symbol option, add countdown in blocks, add decimal point for market cap, add hostname to setup screen

This commit is contained in:
Djuri Baars 2024-03-10 12:35:20 +01:00
parent e4a39de5fc
commit c49b8edcb8
15 changed files with 822 additions and 321 deletions

2
data

@ -1 +1 @@
Subproject commit 3f20d67f1abc10b20ddecfb5aa0ff4eb78c4c149 Subproject commit 1b8ab93da64dd7383a2fb34c967b75fdab072718

View File

@ -1,11 +1,11 @@
dependencies: dependencies:
esp_littlefs: esp_littlefs:
component_hash: 0e4812e62ac02a17f2b6a2bb3b6daf9b39e9599a6e319c745ef2a2817c15a073 component_hash: 66d5afe7ad323d0159d04e296c14ffa0e39156502bc15e0520eff2af392d3aa4
source: source:
git: https://github.com/joltwallet/esp_littlefs.git git: https://github.com/joltwallet/esp_littlefs.git
path: . path: .
type: git type: git
version: 5a0a9a0a39549ac55fd51d55bd3f895ffe700a0a version: 41873c20fb5cdbcf28d7d6cc04e4bcb4a1305317
idf: idf:
component_hash: null component_hash: null
source: source:

View File

@ -5,7 +5,7 @@ std::array<std::string, NUM_SCREENS> parsePriceData(std::uint32_t price, char cu
std::array<std::string, NUM_SCREENS> ret; std::array<std::string, NUM_SCREENS> ret;
std::string priceString; std::string priceString;
if (std::to_string(price).length() >= NUM_SCREENS) { if (std::to_string(price).length() >= NUM_SCREENS) {
priceString = formatNumberWithSuffix(price); priceString = formatNumberWithSuffix(price, NUM_SCREENS-2);
} else { } else {
priceString = currencySymbol + std::to_string(price); priceString = currencySymbol + std::to_string(price);
} }
@ -32,15 +32,18 @@ std::array<std::string, NUM_SCREENS> parsePriceData(std::uint32_t price, char cu
return ret; return ret;
} }
std::array<std::string, NUM_SCREENS> parseSatsPerCurrency(std::uint32_t price, char currencySymbol) std::array<std::string, NUM_SCREENS> parseSatsPerCurrency(std::uint32_t price, char currencySymbol, bool withSatsSymbol)
{ {
std::array<std::string, NUM_SCREENS> ret; std::array<std::string, NUM_SCREENS> ret;
std::string priceString = std::to_string(int(round(1 / float(price) * 10e7))); std::string priceString = std::to_string(int(round(1 / float(price) * 10e7)));
std::uint32_t firstIndex = 0; std::uint32_t firstIndex = 0;
uint insertSatSymbol = NUM_SCREENS - priceString.length() - 1;
if (priceString.length() < (NUM_SCREENS)) if (priceString.length() < (NUM_SCREENS))
{ {
priceString.insert(priceString.begin(), NUM_SCREENS - priceString.length(), ' '); priceString.insert(priceString.begin(), NUM_SCREENS - priceString.length(), ' ');
if (currencySymbol == '[') if (currencySymbol == '[')
{ {
ret[0] = "SATS/EUR"; ret[0] = "SATS/EUR";
@ -55,6 +58,10 @@ std::array<std::string, NUM_SCREENS> parseSatsPerCurrency(std::uint32_t price, c
{ {
ret[i] = priceString[i]; ret[i] = priceString[i];
} }
if (withSatsSymbol) {
ret[insertSatSymbol] = "STS";
}
} }
return ret; return ret;
} }
@ -80,24 +87,43 @@ std::array<std::string, NUM_SCREENS> parseBlockHeight(std::uint32_t blockHeight)
return ret; return ret;
} }
std::array<std::string, NUM_SCREENS> parseHalvingCountdown(std::uint32_t blockHeight) std::array<std::string, NUM_SCREENS> parseHalvingCountdown(std::uint32_t blockHeight, bool asBlocks)
{ {
std::array<std::string, NUM_SCREENS> ret; std::array<std::string, NUM_SCREENS> ret;
const std::uint32_t nextHalvingBlock = 210000 - (blockHeight % 210000); const std::uint32_t nextHalvingBlock = 210000 - (blockHeight % 210000);
const std::uint32_t minutesToHalving = nextHalvingBlock * 10; const std::uint32_t minutesToHalving = nextHalvingBlock * 10;
const int years = floor(minutesToHalving / 525600); if (asBlocks) {
const int days = floor((minutesToHalving - (years * 525600)) / (24 * 60)); std::string blockNrString = std::to_string(nextHalvingBlock);
const int hours = floor((minutesToHalving - (years * 525600) - (days * (24 * 60))) / 60); std::uint32_t firstIndex = 0;
const int mins = floor(minutesToHalving - (years * 525600) - (days * (24 * 60)) - (hours * 60));
ret[0] = "BIT/COIN"; if (blockNrString.length() < NUM_SCREENS)
ret[1] = "HALV/ING"; {
ret[(NUM_SCREENS - 5)] = std::to_string(years) + "/YRS"; blockNrString.insert(blockNrString.begin(), NUM_SCREENS - blockNrString.length(), ' ');
ret[(NUM_SCREENS - 4)] = std::to_string(days) + "/DAYS"; ret[0] = "HAL/VING";
ret[(NUM_SCREENS - 3)] = std::to_string(hours) + "/HRS"; firstIndex = 1;
ret[(NUM_SCREENS - 2)] = std::to_string(mins) + "/MINS"; }
ret[(NUM_SCREENS - 1)] = "TO/GO";
for (std::uint32_t i = firstIndex; i < NUM_SCREENS; i++)
{
ret[i] = blockNrString[i];
}
} else {
const int years = floor(minutesToHalving / 525600);
const int days = floor((minutesToHalving - (years * 525600)) / (24 * 60));
const int hours = floor((minutesToHalving - (years * 525600) - (days * (24 * 60))) / 60);
const int mins = floor(minutesToHalving - (years * 525600) - (days * (24 * 60)) - (hours * 60));
ret[0] = "BIT/COIN";
ret[1] = "HAL/VING";
ret[(NUM_SCREENS - 5)] = std::to_string(years) + "/YRS";
ret[(NUM_SCREENS - 4)] = std::to_string(days) + "/DAYS";
ret[(NUM_SCREENS - 3)] = std::to_string(hours) + "/HRS";
ret[(NUM_SCREENS - 2)] = std::to_string(mins) + "/MINS";
ret[(NUM_SCREENS - 1)] = "TO/GO";
}
return ret; return ret;
} }
@ -120,8 +146,9 @@ std::array<std::string, NUM_SCREENS> parseMarketCap(std::uint32_t blockHeight, s
if (bigChars) if (bigChars)
{ {
firstIndex = 1; firstIndex = 1;
// Serial.print("Market cap: ");
std::string priceString = currencySymbol + formatNumberWithSuffix(marketCap); // Serial.println(marketCap);
std::string priceString = currencySymbol + formatNumberWithSuffix(marketCap, (NUM_SCREENS-2));
priceString.insert(priceString.begin(), NUM_SCREENS - priceString.length(), ' '); priceString.insert(priceString.begin(), NUM_SCREENS - priceString.length(), ' ');
for (std::uint32_t i = firstIndex; i < NUM_SCREENS; i++) for (std::uint32_t i = firstIndex; i < NUM_SCREENS; i++)

View File

@ -6,7 +6,7 @@
#include "utils.hpp" #include "utils.hpp"
std::array<std::string, NUM_SCREENS> parsePriceData(std::uint32_t price, char currencySymbol); std::array<std::string, NUM_SCREENS> parsePriceData(std::uint32_t price, char currencySymbol);
std::array<std::string, NUM_SCREENS> parseSatsPerCurrency(std::uint32_t price, char currencySymbol); std::array<std::string, NUM_SCREENS> parseSatsPerCurrency(std::uint32_t price, char currencySymbol, bool withSatsSymbol);
std::array<std::string, NUM_SCREENS> parseBlockHeight(std::uint32_t blockHeight); std::array<std::string, NUM_SCREENS> parseBlockHeight(std::uint32_t blockHeight);
std::array<std::string, NUM_SCREENS> parseHalvingCountdown(std::uint32_t blockHeight); std::array<std::string, NUM_SCREENS> parseHalvingCountdown(std::uint32_t blockHeight, bool asBlocks);
std::array<std::string, NUM_SCREENS> parseMarketCap(std::uint32_t blockHeight, std::uint32_t price, char currencySymbol, bool bigChars); std::array<std::string, NUM_SCREENS> parseMarketCap(std::uint32_t blockHeight, std::uint32_t price, char currencySymbol, bool bigChars);

View File

@ -5,18 +5,21 @@ int modulo(int x, int N)
return (x % N + N) % N; return (x % N + N) % N;
} }
double getSupplyAtBlock(std::uint32_t blockNr) { double getSupplyAtBlock(std::uint32_t blockNr)
if (blockNr >= 33 * 210000) { {
if (blockNr >= 33 * 210000)
{
return 20999999.9769; return 20999999.9769;
} }
const int initialBlockReward = 50; // Initial block reward const int initialBlockReward = 50; // Initial block reward
const int halvingInterval = 210000; // Number of blocks before halving const int halvingInterval = 210000; // Number of blocks before halving
int halvingCount = blockNr / halvingInterval; int halvingCount = blockNr / halvingInterval;
double totalBitcoinInCirculation = 0; double totalBitcoinInCirculation = 0;
for (int i = 0; i < halvingCount; ++i) { for (int i = 0; i < halvingCount; ++i)
{
totalBitcoinInCirculation += halvingInterval * initialBlockReward * std::pow(0.5, i); totalBitcoinInCirculation += halvingInterval * initialBlockReward * std::pow(0.5, i);
} }
@ -25,24 +28,58 @@ double getSupplyAtBlock(std::uint32_t blockNr) {
return totalBitcoinInCirculation; return totalBitcoinInCirculation;
} }
std::string formatNumberWithSuffix(std::uint64_t num) { std::string formatNumberWithSuffix(std::uint64_t num, int numCharacters)
{
static char result[20]; // Adjust size as needed
const long long quadrillion = 1000000000000000LL; const long long quadrillion = 1000000000000000LL;
const long long trillion = 1000000000000LL; const long long trillion = 1000000000000LL;
const long long billion = 1000000000; const long long billion = 1000000000;
const long long million = 1000000; const long long million = 1000000;
const long long thousand = 1000; const long long thousand = 1000;
if (num >= quadrillion) { double numDouble = (double)num;
return std::to_string(num / quadrillion) + "Q"; int numDigits = (int)log10(num) + 1;
} else if (num >= trillion) { char suffix;
return std::to_string(num / trillion) + "T";
} else if (num >= billion) { if (num >= quadrillion || numDigits > 15)
return std::to_string(num / billion) + "B"; {
} else if (num >= million) { numDouble /= quadrillion;
return std::to_string(num / million) + "M"; suffix = 'Q';
} else if (num >= thousand) {
return std::to_string(num / thousand) + "K";
} else {
return std::to_string(num);
} }
} else if (num >= trillion || numDigits > 12)
{
numDouble /= trillion;
suffix = 'T';
}
else if (num >= billion || numDigits > 9)
{
numDouble /= billion;
suffix = 'B';
}
else if (num >= million || numDigits > 6)
{
numDouble /= million;
suffix = 'M';
}
else if (num >= thousand || numDigits > 3)
{
numDouble /= thousand;
suffix = 'K';
}
else
{
sprintf(result, "%llu", (unsigned long long)num);
return result;
}
// Add suffix
int len = snprintf(result, sizeof(result), "%.0f%c", numDouble, suffix);
// If there's room, add decimal places
if (len < numCharacters)
{
snprintf(result, sizeof(result), "%.*f%c", numCharacters - len - 1, numDouble, suffix);
}
return result;
}

View File

@ -3,9 +3,11 @@
#include <string> #include <string>
#include <cmath> #include <cmath>
#include <cstdint> #include <cstdint>
#include <sstream>
#include <iomanip>
int modulo(int x,int N); int modulo(int x,int N);
double getSupplyAtBlock(std::uint32_t blockNr); double getSupplyAtBlock(std::uint32_t blockNr);
std::string formatNumberWithSuffix(std::uint64_t num); std::string formatNumberWithSuffix(std::uint64_t num, int numCharacters = 4);

View File

@ -5046,7 +5046,7 @@ const GFXglyph Antonio_SemiBold90pt7bGlyphs[] PROGMEM = {
{9988, 53, 55, 63, 5, -94}, // 0x2B '+' {9988, 53, 55, 63, 5, -94}, // 0x2B '+'
{10353, 23, 50, 41, 10, -20}, // 0x2C ',' {10353, 23, 50, 41, 10, -20}, // 0x2C ','
{10497, 39, 14, 60, 8, -75}, // 0x2D '-' {10497, 39, 14, 60, 8, -75}, // 0x2D '-'
{10566, 17, 19, 46, 14, -18}, // 0x2E '.' {10566, 17, 19, 46, 14, 106}, // 0x2E '.'
{10607, 55, 152, 66, 6, 105}, // 0x2F '/' {10607, 55, 152, 66, 6, 105}, // 0x2F '/'
{11652, 59, 155, 79, 10, 104}, // 0x30 '0' {11652, 59, 155, 79, 10, 104}, // 0x30 '0'
{12796, 41, 151, 67, 8, 106}, // 0x31 '1' {12796, 41, 151, 67, 8, 106}, // 0x31 '1'

View File

@ -4,6 +4,8 @@
#include "antonio-semibold30.h" #include "antonio-semibold30.h"
#include "antonio-semibold40.h" #include "antonio-semibold40.h"
#include "antonio-semibold90.h" #include "antonio-semibold90.h"
#include "sats-symbol.h"
// #include "oswald-20.h" // #include "oswald-20.h"
// #include "oswald-30.h" // #include "oswald-30.h"
// #include "oswald-90.h" // #include "oswald-90.h"

201
src/fonts/sats-symbol.h Normal file
View File

@ -0,0 +1,201 @@
const uint8_t Satoshi_Symbol90pt7bBitmaps[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F,
0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F,
0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF,
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF,
0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F,
0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF,
0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF,
0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F,
0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00,
0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF,
0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00,
0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F,
0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00,
0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF,
0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xE0 };
const GFXglyph Satoshi_Symbol90pt7bGlyphs[] PROGMEM = {
{ 0, 82, 127, 99, 8, -126 }, { 1302, 71, 109, 93, 0, -117 } }; // 0x53 'S'
const GFXfont Satoshi_Symbol90pt7b PROGMEM = {
(uint8_t *)Satoshi_Symbol90pt7bBitmaps,
(GFXglyph *)Satoshi_Symbol90pt7bGlyphs,
0x53, 0x53, 192 };
// Approx. 2284 bytes

View File

@ -162,8 +162,7 @@ void onWebsocketMessage(esp_websocket_event_data_t *event_data) {
} }
} }
if (getCurrentScreen() == SCREEN_BLOCK_HEIGHT && if (preferences.getBool("ledFlashOnUpd", false)) {
preferences.getBool("ledFlashOnUpd", false)) {
vTaskDelay(pdMS_TO_TICKS(250)); // Wait until screens are updated vTaskDelay(pdMS_TO_TICKS(250)); // Wait until screens are updated
queueLedEffect(LED_FLASH_BLOCK_NOTIFY); queueLedEffect(LED_FLASH_BLOCK_NOTIFY);
} }

View File

@ -10,16 +10,19 @@ Adafruit_MCP23X17 mcp2;
std::vector<std::string> screenNameMap(SCREEN_COUNT); std::vector<std::string> screenNameMap(SCREEN_COUNT);
std::mutex mcpMutex; std::mutex mcpMutex;
void setup() { void setup()
{
setupPreferences(); setupPreferences();
setupHardware(); setupHardware();
setupDisplays(); setupDisplays();
if (preferences.getBool("ledTestOnPower", true)) { if (preferences.getBool("ledTestOnPower", true))
{
queueLedEffect(LED_POWER_TEST); queueLedEffect(LED_POWER_TEST);
} }
{ {
std::lock_guard<std::mutex> lockMcp(mcpMutex); std::lock_guard<std::mutex> lockMcp(mcpMutex);
if (mcp1.digitalRead(3) == LOW) { if (mcp1.digitalRead(3) == LOW)
{
preferences.putBool("wifiConfigured", false); preferences.putBool("wifiConfigured", false);
preferences.remove("txPower"); preferences.remove("txPower");
@ -49,12 +52,25 @@ void setup() {
forceFullRefresh(); forceFullRefresh();
} }
void tryImprovSetup() { void tryImprovSetup()
{
WiFi.onEvent(WiFiEvent); WiFi.onEvent(WiFiEvent);
WiFi.setAutoConnect(true);
WiFi.setAutoReconnect(true);
WiFi.begin();
if (preferences.getInt("txPower", 0))
{
if (WiFi.setTxPower(
static_cast<wifi_power_t>(preferences.getInt("txPower", 0))))
{
Serial.printf("WiFi max tx power set to %d\n",
preferences.getInt("txPower", 0));
}
}
// if (!preferences.getBool("wifiConfigured", false))
{
if (!preferences.getBool("wifiConfigured", false)) {
setFgColor(GxEPD_BLACK);
setBgColor(GxEPD_WHITE);
queueLedEffect(LED_EFFECT_WIFI_WAIT_FOR_CONFIG); queueLedEffect(LED_EFFECT_WIFI_WAIT_FOR_CONFIG);
uint8_t x_buffer[16]; uint8_t x_buffer[16];
@ -84,13 +100,15 @@ void tryImprovSetup() {
wm.setDebugOutput(false); wm.setDebugOutput(false);
wm.setConfigPortalBlocking(true); wm.setConfigPortalBlocking(true);
wm.setAPCallback([&](WiFiManager *wifiManager) { wm.setAPCallback([&](WiFiManager *wifiManager)
{
// Serial.printf("Entered config mode:ip=%s, ssid='%s', pass='%s'\n", // Serial.printf("Entered config mode:ip=%s, ssid='%s', pass='%s'\n",
// WiFi.softAPIP().toString().c_str(), // WiFi.softAPIP().toString().c_str(),
// wifiManager->getConfigPortalSSID().c_str(), // wifiManager->getConfigPortalSSID().c_str(),
// softAP_password.c_str()); // softAP_password.c_str());
// delay(6000); // delay(6000);
setFgColor(GxEPD_BLACK);
setBgColor(GxEPD_WHITE);
const String qrText = "qrWIFI:S:" + wifiManager->getConfigPortalSSID() + const String qrText = "qrWIFI:S:" + wifiManager->getConfigPortalSSID() +
";T:WPA;P:" + softAP_password.c_str() + ";;"; ";T:WPA;P:" + softAP_password.c_str() + ";;";
const String explainText = "*SSID: *\r\n" + const String explainText = "*SSID: *\r\n" +
@ -102,18 +120,17 @@ void tryImprovSetup() {
"To setup\r\nscan QR or\r\nconnect\r\nmanually", "To setup\r\nscan QR or\r\nconnect\r\nmanually",
"Para\r\nconfigurar\r\nescanear QR\r\no conectar\r\nmanualmente", "Para\r\nconfigurar\r\nescanear QR\r\no conectar\r\nmanualmente",
explainText, explainText,
" ", "*Hostname*:\r\n" + getMyHostname(),
qrText}; qrText};
setEpdContent(epdContent); setEpdContent(epdContent); });
});
wm.setSaveConfigCallback([]() { wm.setSaveConfigCallback([]()
{
preferences.putBool("wifiConfigured", true); preferences.putBool("wifiConfigured", true);
delay(1000); delay(1000);
// just restart after succes // just restart after succes
ESP.restart(); ESP.restart(); });
});
bool ac = wm.autoConnect(softAP_SSID.c_str(), softAP_password.c_str()); bool ac = wm.autoConnect(softAP_SSID.c_str(), softAP_password.c_str());
@ -154,31 +171,26 @@ void tryImprovSetup() {
} }
setFgColor(preferences.getUInt("fgColor", DEFAULT_FG_COLOR)); setFgColor(preferences.getUInt("fgColor", DEFAULT_FG_COLOR));
setBgColor(preferences.getUInt("bgColor", DEFAULT_BG_COLOR)); setBgColor(preferences.getUInt("bgColor", DEFAULT_BG_COLOR));
} else {
WiFi.setAutoConnect(true);
WiFi.setAutoReconnect(true);
WiFi.begin();
if (preferences.getInt("txPower", 0)) {
if (WiFi.setTxPower(
static_cast<wifi_power_t>(preferences.getInt("txPower", 0)))) {
Serial.printf("WiFi max tx power set to %d\n",
preferences.getInt("txPower", 0));
}
}
while (WiFi.status() != WL_CONNECTED) {
vTaskDelay(pdMS_TO_TICKS(400));
}
} }
// else
// {
// while (WiFi.status() != WL_CONNECTED)
// {
// vTaskDelay(pdMS_TO_TICKS(400));
// }
// }
// queueLedEffect(LED_EFFECT_WIFI_CONNECT_SUCCESS); // queueLedEffect(LED_EFFECT_WIFI_CONNECT_SUCCESS);
} }
void setupTime() { void setupTime()
{
configTime(preferences.getInt("gmtOffset", TIME_OFFSET_SECONDS), 0, configTime(preferences.getInt("gmtOffset", TIME_OFFSET_SECONDS), 0,
NTP_SERVER); NTP_SERVER);
struct tm timeinfo; struct tm timeinfo;
while (!getLocalTime(&timeinfo)) { while (!getLocalTime(&timeinfo))
{
configTime(preferences.getInt("gmtOffset", TIME_OFFSET_SECONDS), 0, configTime(preferences.getInt("gmtOffset", TIME_OFFSET_SECONDS), 0,
NTP_SERVER); NTP_SERVER);
delay(500); delay(500);
@ -186,7 +198,8 @@ void setupTime() {
} }
} }
void setupPreferences() { void setupPreferences()
{
preferences.begin("btclock", false); preferences.begin("btclock", false);
setFgColor(preferences.getUInt("fgColor", DEFAULT_FG_COLOR)); setFgColor(preferences.getUInt("fgColor", DEFAULT_FG_COLOR));
@ -202,36 +215,46 @@ void setupPreferences() {
screenNameMap[SCREEN_MARKET_CAP] = "Market Cap"; screenNameMap[SCREEN_MARKET_CAP] = "Market Cap";
} }
void setupWebsocketClients(void *pvParameters) { void setupWebsocketClients(void *pvParameters)
{
setupBlockNotify(); setupBlockNotify();
if (preferences.getBool("fetchEurPrice", false)) { if (preferences.getBool("fetchEurPrice", false))
{
setupPriceFetchTask(); setupPriceFetchTask();
} else { }
else
{
setupPriceNotify(); setupPriceNotify();
} }
vTaskDelete(NULL); vTaskDelete(NULL);
} }
void setupTimers() { void setupTimers()
{
xTaskCreate(setupTimeUpdateTimer, "setupTimeUpdateTimer", 2048, NULL, xTaskCreate(setupTimeUpdateTimer, "setupTimeUpdateTimer", 2048, NULL,
tskIDLE_PRIORITY, NULL); tskIDLE_PRIORITY, NULL);
xTaskCreate(setupScreenRotateTimer, "setupScreenRotateTimer", 2048, NULL, xTaskCreate(setupScreenRotateTimer, "setupScreenRotateTimer", 2048, NULL,
tskIDLE_PRIORITY, NULL); tskIDLE_PRIORITY, NULL);
} }
void finishSetup() { void finishSetup()
if (preferences.getBool("ledStatus", false)) { {
if (preferences.getBool("ledStatus", false))
{
restoreLedState(); restoreLedState();
} else { }
else
{
clearLeds(); clearLeds();
} }
} }
std::vector<std::string> getScreenNameMap() { return screenNameMap; } std::vector<std::string> getScreenNameMap() { return screenNameMap; }
void setupMcp() { void setupMcp()
{
#ifdef IS_BTCLOCK_S3 #ifdef IS_BTCLOCK_S3
const int mcp1AddrPins[] = {MCP1_A0_PIN, MCP1_A1_PIN, MCP1_A2_PIN}; const int mcp1AddrPins[] = {MCP1_A0_PIN, MCP1_A1_PIN, MCP1_A2_PIN};
const int mcp1AddrValues[] = {LOW, LOW, LOW}; const int mcp1AddrValues[] = {LOW, LOW, LOW};
@ -242,7 +265,8 @@ void setupMcp() {
pinMode(MCP_RESET_PIN, OUTPUT); pinMode(MCP_RESET_PIN, OUTPUT);
digitalWrite(MCP_RESET_PIN, HIGH); digitalWrite(MCP_RESET_PIN, HIGH);
for (int i = 0; i < 3; ++i) { for (int i = 0; i < 3; ++i)
{
pinMode(mcp1AddrPins[i], OUTPUT); pinMode(mcp1AddrPins[i], OUTPUT);
digitalWrite(mcp1AddrPins[i], mcp1AddrValues[i]); digitalWrite(mcp1AddrPins[i], mcp1AddrValues[i]);
@ -256,19 +280,23 @@ void setupMcp() {
#endif #endif
} }
void setupHardware() { void setupHardware()
if (!LittleFS.begin(true)) { {
if (!LittleFS.begin(true))
{
Serial.println(F("An Error has occurred while mounting LittleFS")); Serial.println(F("An Error has occurred while mounting LittleFS"));
} }
if (!LittleFS.open("/index.html.gz", "r")) { if (!LittleFS.open("/index.html.gz", "r"))
{
Serial.println("Error loading WebUI"); Serial.println("Error loading WebUI");
} }
setupLeds(); setupLeds();
WiFi.setHostname(getMyHostname().c_str()); WiFi.setHostname(getMyHostname().c_str());
if (!psramInit()) { if (!psramInit())
{
Serial.println(F("PSRAM not available")); Serial.println(F("PSRAM not available"));
} }
@ -276,28 +304,34 @@ void setupHardware() {
Wire.begin(I2C_SDA_PIN, I2C_SCK_PIN, 400000); Wire.begin(I2C_SDA_PIN, I2C_SCK_PIN, 400000);
if (!mcp1.begin_I2C(0x20)) { if (!mcp1.begin_I2C(0x20))
{
Serial.println(F("Error MCP23017")); Serial.println(F("Error MCP23017"));
// while (1) // while (1)
// ; // ;
} else { }
else
{
pinMode(MCP_INT_PIN, INPUT_PULLUP); pinMode(MCP_INT_PIN, INPUT_PULLUP);
mcp1.setupInterrupts(false, false, LOW); mcp1.setupInterrupts(false, false, LOW);
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++)
{
mcp1.pinMode(i, INPUT_PULLUP); mcp1.pinMode(i, INPUT_PULLUP);
mcp1.setupInterruptPin(i, LOW); mcp1.setupInterruptPin(i, LOW);
} }
#ifndef IS_BTCLOCK_S3 #ifndef IS_BTCLOCK_S3
for (int i = 8; i <= 14; i++) { for (int i = 8; i <= 14; i++)
{
mcp1.pinMode(i, OUTPUT); mcp1.pinMode(i, OUTPUT);
} }
#endif #endif
} }
#ifdef IS_BTCLOCK_S3 #ifdef IS_BTCLOCK_S3
if (!mcp2.begin_I2C(0x21)) { if (!mcp2.begin_I2C(0x21))
{
Serial.println(F("Error MCP23017")); Serial.println(F("Error MCP23017"));
// while (1) // while (1)
@ -306,10 +340,12 @@ void setupHardware() {
#endif #endif
} }
void improvGetAvailableWifiNetworks() { void improvGetAvailableWifiNetworks()
{
int networkNum = WiFi.scanNetworks(); int networkNum = WiFi.scanNetworks();
for (int id = 0; id < networkNum; ++id) { for (int id = 0; id < networkNum; ++id)
{
std::vector<uint8_t> data = improv::build_rpc_response( std::vector<uint8_t> data = improv::build_rpc_response(
improv::GET_WIFI_NETWORKS, improv::GET_WIFI_NETWORKS,
{WiFi.SSID(id), String(WiFi.RSSI(id)), {WiFi.SSID(id), String(WiFi.RSSI(id)),
@ -323,15 +359,18 @@ void improvGetAvailableWifiNetworks() {
improv_send_response(data); improv_send_response(data);
} }
bool improv_connectWifi(std::string ssid, std::string password) { bool improv_connectWifi(std::string ssid, std::string password)
{
uint8_t count = 0; uint8_t count = 0;
WiFi.begin(ssid.c_str(), password.c_str()); WiFi.begin(ssid.c_str(), password.c_str());
while (WiFi.status() != WL_CONNECTED) { while (WiFi.status() != WL_CONNECTED)
{
blinkDelay(500, 2); blinkDelay(500, 2);
if (count > MAX_ATTEMPTS_WIFI_CONNECTION) { if (count > MAX_ATTEMPTS_WIFI_CONNECTION)
{
WiFi.disconnect(); WiFi.disconnect();
return false; return false;
} }
@ -341,7 +380,8 @@ bool improv_connectWifi(std::string ssid, std::string password) {
return true; return true;
} }
void onImprovErrorCallback(improv::Error err) { void onImprovErrorCallback(improv::Error err)
{
blinkDelayColor(100, 1, 255, 0, 0); blinkDelayColor(100, 1, 255, 0, 0);
// pixels.setPixelColor(0, pixels.Color(255, 0, 0)); // pixels.setPixelColor(0, pixels.Color(255, 0, 0));
// pixels.setPixelColor(1, pixels.Color(255, 0, 0)); // pixels.setPixelColor(1, pixels.Color(255, 0, 0));
@ -355,94 +395,110 @@ void onImprovErrorCallback(improv::Error err) {
// vTaskDelay(pdMS_TO_TICKS(100)); // vTaskDelay(pdMS_TO_TICKS(100));
} }
std::vector<std::string> getLocalUrl() { std::vector<std::string> getLocalUrl()
{
return {// URL where user can finish onboarding or use device return {// URL where user can finish onboarding or use device
// Recommended to use website hosted by device // Recommended to use website hosted by device
String("http://" + WiFi.localIP().toString()).c_str()}; String("http://" + WiFi.localIP().toString()).c_str()};
} }
bool onImprovCommandCallback(improv::ImprovCommand cmd) { bool onImprovCommandCallback(improv::ImprovCommand cmd)
switch (cmd.command) { {
case improv::Command::GET_CURRENT_STATE: { switch (cmd.command)
if ((WiFi.status() == WL_CONNECTED)) { {
improv_set_state(improv::State::STATE_PROVISIONED); case improv::Command::GET_CURRENT_STATE:
std::vector<uint8_t> data = improv::build_rpc_response( {
improv::GET_CURRENT_STATE, getLocalUrl(), false); if ((WiFi.status() == WL_CONNECTED))
improv_send_response(data); {
} else { improv_set_state(improv::State::STATE_PROVISIONED);
improv_set_state(improv::State::STATE_AUTHORIZED); std::vector<uint8_t> data = improv::build_rpc_response(
} improv::GET_CURRENT_STATE, getLocalUrl(), false);
break;
}
case improv::Command::WIFI_SETTINGS: {
if (cmd.ssid.length() == 0) {
improv_set_error(improv::Error::ERROR_INVALID_RPC);
break;
}
improv_set_state(improv::STATE_PROVISIONING);
queueLedEffect(LED_EFFECT_WIFI_CONNECTING);
if (improv_connectWifi(cmd.ssid, cmd.password)) {
queueLedEffect(LED_EFFECT_WIFI_CONNECT_SUCCESS);
// std::array<String, NUM_SCREENS> epdContent = {"S", "U", "C", "C",
// "E", "S", "S"}; setEpdContent(epdContent);
preferences.putBool("wifiConfigured", true);
improv_set_state(improv::STATE_PROVISIONED);
std::vector<uint8_t> data = improv::build_rpc_response(
improv::WIFI_SETTINGS, getLocalUrl(), false);
improv_send_response(data);
delay(2500);
ESP.restart();
setupWebserver();
} else {
queueLedEffect(LED_EFFECT_WIFI_CONNECT_ERROR);
improv_set_state(improv::STATE_STOPPED);
improv_set_error(improv::Error::ERROR_UNABLE_TO_CONNECT);
}
break;
}
case improv::Command::GET_DEVICE_INFO: {
std::vector<std::string> infos = {// Firmware name
"BTClock",
// Firmware version
"1.0.0",
// Hardware chip/variant
"ESP32S3",
// Device name
"BTClock"};
std::vector<uint8_t> data =
improv::build_rpc_response(improv::GET_DEVICE_INFO, infos, false);
improv_send_response(data); improv_send_response(data);
}
else
{
improv_set_state(improv::State::STATE_AUTHORIZED);
}
break;
}
case improv::Command::WIFI_SETTINGS:
{
if (cmd.ssid.length() == 0)
{
improv_set_error(improv::Error::ERROR_INVALID_RPC);
break; break;
} }
case improv::Command::GET_WIFI_NETWORKS: { improv_set_state(improv::STATE_PROVISIONING);
improvGetAvailableWifiNetworks(); queueLedEffect(LED_EFFECT_WIFI_CONNECTING);
// std::array<String, NUM_SCREENS> epdContent = {"W", "E", "B", "W", "I",
// "F", "I"}; setEpdContent(epdContent); if (improv_connectWifi(cmd.ssid, cmd.password))
break; {
queueLedEffect(LED_EFFECT_WIFI_CONNECT_SUCCESS);
// std::array<String, NUM_SCREENS> epdContent = {"S", "U", "C", "C",
// "E", "S", "S"}; setEpdContent(epdContent);
preferences.putBool("wifiConfigured", true);
improv_set_state(improv::STATE_PROVISIONED);
std::vector<uint8_t> data = improv::build_rpc_response(
improv::WIFI_SETTINGS, getLocalUrl(), false);
improv_send_response(data);
delay(2500);
ESP.restart();
setupWebserver();
}
else
{
queueLedEffect(LED_EFFECT_WIFI_CONNECT_ERROR);
improv_set_state(improv::STATE_STOPPED);
improv_set_error(improv::Error::ERROR_UNABLE_TO_CONNECT);
} }
default: { break;
improv_set_error(improv::ERROR_UNKNOWN_RPC); }
return false;
} case improv::Command::GET_DEVICE_INFO:
{
std::vector<std::string> infos = {// Firmware name
"BTClock",
// Firmware version
"1.0.0",
// Hardware chip/variant
"ESP32S3",
// Device name
"BTClock"};
std::vector<uint8_t> data =
improv::build_rpc_response(improv::GET_DEVICE_INFO, infos, false);
improv_send_response(data);
break;
}
case improv::Command::GET_WIFI_NETWORKS:
{
improvGetAvailableWifiNetworks();
// std::array<String, NUM_SCREENS> epdContent = {"W", "E", "B", "W", "I",
// "F", "I"}; setEpdContent(epdContent);
break;
}
default:
{
improv_set_error(improv::ERROR_UNKNOWN_RPC);
return false;
}
} }
return true; return true;
} }
void improv_set_state(improv::State state) { void improv_set_state(improv::State state)
{
std::vector<uint8_t> data = {'I', 'M', 'P', 'R', 'O', 'V'}; std::vector<uint8_t> data = {'I', 'M', 'P', 'R', 'O', 'V'};
data.resize(11); data.resize(11);
data[6] = improv::IMPROV_SERIAL_VERSION; data[6] = improv::IMPROV_SERIAL_VERSION;
@ -451,13 +507,15 @@ void improv_set_state(improv::State state) {
data[9] = state; data[9] = state;
uint8_t checksum = 0x00; uint8_t checksum = 0x00;
for (uint8_t d : data) checksum += d; for (uint8_t d : data)
checksum += d;
data[10] = checksum; data[10] = checksum;
Serial.write(data.data(), data.size()); Serial.write(data.data(), data.size());
} }
void improv_send_response(std::vector<uint8_t> &response) { void improv_send_response(std::vector<uint8_t> &response)
{
std::vector<uint8_t> data = {'I', 'M', 'P', 'R', 'O', 'V'}; std::vector<uint8_t> data = {'I', 'M', 'P', 'R', 'O', 'V'};
data.resize(9); data.resize(9);
data[6] = improv::IMPROV_SERIAL_VERSION; data[6] = improv::IMPROV_SERIAL_VERSION;
@ -466,13 +524,15 @@ void improv_send_response(std::vector<uint8_t> &response) {
data.insert(data.end(), response.begin(), response.end()); data.insert(data.end(), response.begin(), response.end());
uint8_t checksum = 0x00; uint8_t checksum = 0x00;
for (uint8_t d : data) checksum += d; for (uint8_t d : data)
checksum += d;
data.push_back(checksum); data.push_back(checksum);
Serial.write(data.data(), data.size()); Serial.write(data.data(), data.size());
} }
void improv_set_error(improv::Error error) { void improv_set_error(improv::Error error)
{
std::vector<uint8_t> data = {'I', 'M', 'P', 'R', 'O', 'V'}; std::vector<uint8_t> data = {'I', 'M', 'P', 'R', 'O', 'V'};
data.resize(11); data.resize(11);
data[6] = improv::IMPROV_SERIAL_VERSION; data[6] = improv::IMPROV_SERIAL_VERSION;
@ -481,89 +541,97 @@ void improv_set_error(improv::Error error) {
data[9] = error; data[9] = error;
uint8_t checksum = 0x00; uint8_t checksum = 0x00;
for (uint8_t d : data) checksum += d; for (uint8_t d : data)
checksum += d;
data[10] = checksum; data[10] = checksum;
Serial.write(data.data(), data.size()); Serial.write(data.data(), data.size());
} }
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) { void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info)
{
static bool first_connect = true; static bool first_connect = true;
Serial.printf("[WiFi-event] event: %d\n", event); Serial.printf("[WiFi-event] event: %d\n", event);
switch (event) { switch (event)
case ARDUINO_EVENT_WIFI_READY: {
Serial.println("WiFi interface ready"); case ARDUINO_EVENT_WIFI_READY:
break; Serial.println("WiFi interface ready");
case ARDUINO_EVENT_WIFI_SCAN_DONE: break;
Serial.println("Completed scan for access points"); case ARDUINO_EVENT_WIFI_SCAN_DONE:
break; Serial.println("Completed scan for access points");
case ARDUINO_EVENT_WIFI_STA_START: break;
Serial.println("WiFi client started"); case ARDUINO_EVENT_WIFI_STA_START:
break; Serial.println("WiFi client started");
case ARDUINO_EVENT_WIFI_STA_STOP: break;
Serial.println("WiFi clients stopped"); case ARDUINO_EVENT_WIFI_STA_STOP:
break; Serial.println("WiFi clients stopped");
case ARDUINO_EVENT_WIFI_STA_CONNECTED: break;
Serial.println("Connected to access point"); case ARDUINO_EVENT_WIFI_STA_CONNECTED:
break; Serial.println("Connected to access point");
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: { break;
if (!first_connect) { case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
Serial.println("Disconnected from WiFi access point"); {
queueLedEffect(LED_EFFECT_WIFI_CONNECT_ERROR); if (!first_connect)
uint8_t reason = info.wifi_sta_disconnected.reason; {
if (reason) Serial.println("Disconnected from WiFi access point");
Serial.printf("Disconnect reason: %s, ",
WiFi.disconnectReasonName((wifi_err_reason_t)reason));
}
break;
}
case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE:
Serial.println("Authentication mode of access point has changed");
break;
case ARDUINO_EVENT_WIFI_STA_GOT_IP: {
Serial.print("Obtained IP address: ");
Serial.println(WiFi.localIP());
if (!first_connect) queueLedEffect(LED_EFFECT_WIFI_CONNECT_SUCCESS);
first_connect = false;
break;
}
case ARDUINO_EVENT_WIFI_STA_LOST_IP:
Serial.println("Lost IP address and IP address is reset to 0");
queueLedEffect(LED_EFFECT_WIFI_CONNECT_ERROR); queueLedEffect(LED_EFFECT_WIFI_CONNECT_ERROR);
WiFi.reconnect(); uint8_t reason = info.wifi_sta_disconnected.reason;
break; if (reason)
case ARDUINO_EVENT_WIFI_AP_START: Serial.printf("Disconnect reason: %s, ",
Serial.println("WiFi access point started"); WiFi.disconnectReasonName((wifi_err_reason_t)reason));
break; }
case ARDUINO_EVENT_WIFI_AP_STOP: break;
Serial.println("WiFi access point stopped"); }
break; case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE:
case ARDUINO_EVENT_WIFI_AP_STACONNECTED: Serial.println("Authentication mode of access point has changed");
Serial.println("Client connected"); break;
break; case ARDUINO_EVENT_WIFI_STA_GOT_IP:
case ARDUINO_EVENT_WIFI_AP_STADISCONNECTED: {
Serial.println("Client disconnected"); Serial.print("Obtained IP address: ");
break; Serial.println(WiFi.localIP());
case ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED: if (!first_connect)
Serial.println("Assigned IP address to client"); queueLedEffect(LED_EFFECT_WIFI_CONNECT_SUCCESS);
break; first_connect = false;
case ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED: break;
Serial.println("Received probe request"); }
break; case ARDUINO_EVENT_WIFI_STA_LOST_IP:
case ARDUINO_EVENT_WIFI_AP_GOT_IP6: Serial.println("Lost IP address and IP address is reset to 0");
Serial.println("AP IPv6 is preferred"); queueLedEffect(LED_EFFECT_WIFI_CONNECT_ERROR);
break; WiFi.reconnect();
case ARDUINO_EVENT_WIFI_STA_GOT_IP6: break;
Serial.println("STA IPv6 is preferred"); case ARDUINO_EVENT_WIFI_AP_START:
break; Serial.println("WiFi access point started");
default: break;
break; case ARDUINO_EVENT_WIFI_AP_STOP:
Serial.println("WiFi access point stopped");
break;
case ARDUINO_EVENT_WIFI_AP_STACONNECTED:
Serial.println("Client connected");
break;
case ARDUINO_EVENT_WIFI_AP_STADISCONNECTED:
Serial.println("Client disconnected");
break;
case ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED:
Serial.println("Assigned IP address to client");
break;
case ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED:
Serial.println("Received probe request");
break;
case ARDUINO_EVENT_WIFI_AP_GOT_IP6:
Serial.println("AP IPv6 is preferred");
break;
case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
Serial.println("STA IPv6 is preferred");
break;
default:
break;
} }
} }
String getMyHostname() { String getMyHostname()
{
uint8_t mac[6]; uint8_t mac[6];
// WiFi.macAddress(mac); // WiFi.macAddress(mac);
esp_efuse_mac_get_default(mac); esp_efuse_mac_get_default(mac);

View File

@ -16,12 +16,21 @@ Native_Pin EPD_CS[NUM_SCREENS] = {
#endif #endif
}; };
Native_Pin EPD_BUSY[NUM_SCREENS] = { Native_Pin EPD_BUSY[NUM_SCREENS] = {
Native_Pin(3), Native_Pin(5), Native_Pin(7), Native_Pin(9), Native_Pin(3),
Native_Pin(37), Native_Pin(18), Native_Pin(16), Native_Pin(5),
Native_Pin(7),
Native_Pin(9),
Native_Pin(37),
Native_Pin(18),
Native_Pin(16),
}; };
MCP23X17_Pin EPD_RESET_MPD[NUM_SCREENS] = { MCP23X17_Pin EPD_RESET_MPD[NUM_SCREENS] = {
MCP23X17_Pin(mcp1, 8), MCP23X17_Pin(mcp1, 9), MCP23X17_Pin(mcp1, 10), MCP23X17_Pin(mcp1, 8),
MCP23X17_Pin(mcp1, 11), MCP23X17_Pin(mcp1, 12), MCP23X17_Pin(mcp1, 13), MCP23X17_Pin(mcp1, 9),
MCP23X17_Pin(mcp1, 10),
MCP23X17_Pin(mcp1, 11),
MCP23X17_Pin(mcp1, 12),
MCP23X17_Pin(mcp1, 13),
MCP23X17_Pin(mcp1, 14), MCP23X17_Pin(mcp1, 14),
}; };
@ -30,20 +39,30 @@ Native_Pin EPD_DC = Native_Pin(14);
Native_Pin EPD_DC = Native_Pin(38); Native_Pin EPD_DC = Native_Pin(38);
MCP23X17_Pin EPD_BUSY[NUM_SCREENS] = { MCP23X17_Pin EPD_BUSY[NUM_SCREENS] = {
MCP23X17_Pin(mcp1, 8), MCP23X17_Pin(mcp1, 9), MCP23X17_Pin(mcp1, 10), MCP23X17_Pin(mcp1, 8),
MCP23X17_Pin(mcp1, 11), MCP23X17_Pin(mcp1, 12), MCP23X17_Pin(mcp1, 13), MCP23X17_Pin(mcp1, 9),
MCP23X17_Pin(mcp1, 14), MCP23X17_Pin(mcp1, 4), MCP23X17_Pin(mcp1, 10),
MCP23X17_Pin(mcp1, 11),
MCP23X17_Pin(mcp1, 12),
MCP23X17_Pin(mcp1, 13),
MCP23X17_Pin(mcp1, 14),
MCP23X17_Pin(mcp1, 4),
}; };
MCP23X17_Pin EPD_CS[NUM_SCREENS] = { MCP23X17_Pin EPD_CS[NUM_SCREENS] = {
MCP23X17_Pin(mcp2, 8), MCP23X17_Pin(mcp2, 10), MCP23X17_Pin(mcp2, 12), MCP23X17_Pin(mcp2, 8), MCP23X17_Pin(mcp2, 10), MCP23X17_Pin(mcp2, 12),
MCP23X17_Pin(mcp2, 14), MCP23X17_Pin(mcp2, 0), MCP23X17_Pin(mcp2, 2), MCP23X17_Pin(mcp2, 14), MCP23X17_Pin(mcp2, 0), MCP23X17_Pin(mcp2, 2),
MCP23X17_Pin(mcp2, 4), MCP23X17_Pin(mcp2, 6)}; MCP23X17_Pin(mcp2, 4), MCP23X17_Pin(mcp2, 6)};
MCP23X17_Pin EPD_RESET_MPD[NUM_SCREENS] = { MCP23X17_Pin EPD_RESET_MPD[NUM_SCREENS] = {
MCP23X17_Pin(mcp2, 9), MCP23X17_Pin(mcp2, 11), MCP23X17_Pin(mcp2, 13), MCP23X17_Pin(mcp2, 9),
MCP23X17_Pin(mcp2, 15), MCP23X17_Pin(mcp2, 1), MCP23X17_Pin(mcp2, 3), MCP23X17_Pin(mcp2, 11),
MCP23X17_Pin(mcp2, 5), MCP23X17_Pin(mcp2, 7), MCP23X17_Pin(mcp2, 13),
MCP23X17_Pin(mcp2, 15),
MCP23X17_Pin(mcp2, 1),
MCP23X17_Pin(mcp2, 3),
MCP23X17_Pin(mcp2, 5),
MCP23X17_Pin(mcp2, 7),
}; };
#endif #endif
@ -78,24 +97,30 @@ int bgColor = GxEPD_BLACK;
#define FONT_SMALL Antonio_SemiBold20pt7b #define FONT_SMALL Antonio_SemiBold20pt7b
#define FONT_BIG Antonio_SemiBold90pt7b #define FONT_BIG Antonio_SemiBold90pt7b
#define FONT_MEDIUM Antonio_SemiBold40pt7b #define FONT_MEDIUM Antonio_SemiBold40pt7b
#define FONT_SATSYMBOL Satoshi_Symbol90pt7b
std::mutex epdUpdateMutex; std::mutex epdUpdateMutex;
std::mutex epdMutex[NUM_SCREENS]; std::mutex epdMutex[NUM_SCREENS];
uint8_t qrcode[800]; uint8_t qrcode[800];
void forceFullRefresh() { void forceFullRefresh()
for (uint i = 0; i < NUM_SCREENS; i++) { {
for (uint i = 0; i < NUM_SCREENS; i++)
{
lastFullRefresh[i] = NULL; lastFullRefresh[i] = NULL;
} }
} }
void refreshFromMemory() { void refreshFromMemory()
for (uint i = 0; i < NUM_SCREENS; i++) { {
for (uint i = 0; i < NUM_SCREENS; i++)
{
int *taskParam = new int; int *taskParam = new int;
*taskParam = i; *taskParam = i;
xTaskCreate( xTaskCreate(
[](void *pvParameters) { [](void *pvParameters)
{
const int epdIndex = *(int *)pvParameters; const int epdIndex = *(int *)pvParameters;
delete (int *)pvParameters; delete (int *)pvParameters;
displays[epdIndex].refresh(false); displays[epdIndex].refresh(false);
@ -105,10 +130,12 @@ void refreshFromMemory() {
} }
} }
void setupDisplays() { void setupDisplays()
{
std::lock_guard<std::mutex> lockMcp(mcpMutex); std::lock_guard<std::mutex> lockMcp(mcpMutex);
for (uint i = 0; i < NUM_SCREENS; i++) { for (uint i = 0; i < NUM_SCREENS; i++)
{
displays[i].init(0, true, 30); displays[i].init(0, true, 30);
} }
@ -116,7 +143,8 @@ void setupDisplays() {
xTaskCreate(prepareDisplayUpdateTask, "PrepareUpd", 4096, NULL, 11, NULL); xTaskCreate(prepareDisplayUpdateTask, "PrepareUpd", 4096, NULL, 11, NULL);
for (uint i = 0; i < NUM_SCREENS; i++) { for (uint i = 0; i < NUM_SCREENS; i++)
{
// epdUpdateSemaphore[i] = xSemaphoreCreateBinary(); // epdUpdateSemaphore[i] = xSemaphoreCreateBinary();
// xSemaphoreGive(epdUpdateSemaphore[i]); // xSemaphoreGive(epdUpdateSemaphore[i]);
@ -124,7 +152,7 @@ void setupDisplays() {
*taskParam = i; *taskParam = i;
xTaskCreate(updateDisplay, ("EpdUpd" + String(i)).c_str(), 2048, taskParam, xTaskCreate(updateDisplay, ("EpdUpd" + String(i)).c_str(), 2048, taskParam,
11, &tasks[i]); // create task 11, &tasks[i]); // create task
} }
epdContent = {"B", "T", "C", "L", "O", "C", "K"}; epdContent = {"B", "T", "C", "L", "O", "C", "K"};
@ -132,14 +160,17 @@ void setupDisplays() {
setEpdContent(epdContent); setEpdContent(epdContent);
} }
void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent) { void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent)
{
setEpdContent(newEpdContent, false); setEpdContent(newEpdContent, false);
} }
void setEpdContent(std::array<std::string, NUM_SCREENS> newEpdContent) { void setEpdContent(std::array<std::string, NUM_SCREENS> newEpdContent)
{
std::array<String, NUM_SCREENS> conv; std::array<String, NUM_SCREENS> conv;
for (size_t i = 0; i < newEpdContent.size(); ++i) { for (size_t i = 0; i < newEpdContent.size(); ++i)
{
conv[i] = String(newEpdContent[i].c_str()); conv[i] = String(newEpdContent[i].c_str());
} }
@ -147,13 +178,16 @@ void setEpdContent(std::array<std::string, NUM_SCREENS> newEpdContent) {
} }
void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent, void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent,
bool forceUpdate) { bool forceUpdate)
{
std::lock_guard<std::mutex> lock(epdUpdateMutex); std::lock_guard<std::mutex> lock(epdUpdateMutex);
waitUntilNoneBusy(); waitUntilNoneBusy();
for (uint i = 0; i < NUM_SCREENS; i++) { for (uint i = 0; i < NUM_SCREENS; i++)
if (newEpdContent[i].compareTo(currentEpdContent[i]) != 0 || forceUpdate) { {
if (newEpdContent[i].compareTo(currentEpdContent[i]) != 0 || forceUpdate)
{
epdContent[i] = newEpdContent[i]; epdContent[i] = newEpdContent[i];
UpdateDisplayTaskItem dispUpdate = {i}; UpdateDisplayTaskItem dispUpdate = {i};
xQueueSend(updateQueue, &dispUpdate, portMAX_DELAY); xQueueSend(updateQueue, &dispUpdate, portMAX_DELAY);
@ -161,12 +195,15 @@ void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent,
} }
} }
void prepareDisplayUpdateTask(void *pvParameters) { void prepareDisplayUpdateTask(void *pvParameters)
{
UpdateDisplayTaskItem receivedItem; UpdateDisplayTaskItem receivedItem;
while (1) { while (1)
{
// Wait for a work item to be available in the queue // Wait for a work item to be available in the queue
if (xQueueReceive(updateQueue, &receivedItem, portMAX_DELAY)) { if (xQueueReceive(updateQueue, &receivedItem, portMAX_DELAY))
{
uint epdIndex = receivedItem.dispNum; uint epdIndex = receivedItem.dispNum;
std::lock_guard<std::mutex> lock(epdMutex[epdIndex]); std::lock_guard<std::mutex> lock(epdMutex[epdIndex]);
// displays[epdIndex].init(0, false); // Little longer reset duration // displays[epdIndex].init(0, false); // Little longer reset duration
@ -174,23 +211,43 @@ void prepareDisplayUpdateTask(void *pvParameters) {
bool updatePartial = true; bool updatePartial = true;
if (strstr(epdContent[epdIndex].c_str(), "/") != NULL) { if (strstr(epdContent[epdIndex].c_str(), "/") != NULL)
{
String top = epdContent[epdIndex].substring( String top = epdContent[epdIndex].substring(
0, epdContent[epdIndex].indexOf("/")); 0, epdContent[epdIndex].indexOf("/"));
String bottom = epdContent[epdIndex].substring( String bottom = epdContent[epdIndex].substring(
epdContent[epdIndex].indexOf("/") + 1); epdContent[epdIndex].indexOf("/") + 1);
splitText(epdIndex, top, bottom, updatePartial); splitText(epdIndex, top, bottom, updatePartial);
} else if (epdContent[epdIndex].startsWith(F("qr"))) { }
else if (epdContent[epdIndex].startsWith(F("qr")))
{
renderQr(epdIndex, epdContent[epdIndex], updatePartial); renderQr(epdIndex, epdContent[epdIndex], updatePartial);
} else if (epdContent[epdIndex].length() > 5) { }
else if (epdContent[epdIndex].length() > 5)
{
renderText(epdIndex, epdContent[epdIndex], updatePartial); renderText(epdIndex, epdContent[epdIndex], updatePartial);
} else { }
if (epdContent[epdIndex].length() > 1) { else
showChars(epdIndex, epdContent[epdIndex], updatePartial, {
&FONT_MEDIUM); if (epdContent[epdIndex].length() > 1 && epdContent[epdIndex].indexOf(".") == -1)
} else { {
if (epdContent[epdIndex].equals("STS"))
{
showDigit(epdIndex, 'S', updatePartial,
&FONT_SATSYMBOL);
}
else
{
showChars(epdIndex, epdContent[epdIndex], updatePartial,
&FONT_MEDIUM);
}
}
else
{
showDigit(epdIndex, epdContent[epdIndex].c_str()[0], updatePartial, showDigit(epdIndex, epdContent[epdIndex].c_str()[0], updatePartial,
&FONT_BIG); &FONT_BIG);
} }
} }
@ -199,11 +256,13 @@ void prepareDisplayUpdateTask(void *pvParameters) {
} }
} }
extern "C" void updateDisplay(void *pvParameters) noexcept { extern "C" void updateDisplay(void *pvParameters) noexcept
{
const int epdIndex = *(int *)pvParameters; const int epdIndex = *(int *)pvParameters;
delete (int *)pvParameters; delete (int *)pvParameters;
for (;;) { for (;;)
{
// Wait for the task notification // Wait for the task notification
ulTaskNotifyTake(pdTRUE, portMAX_DELAY); ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
@ -215,7 +274,8 @@ extern "C" void updateDisplay(void *pvParameters) noexcept {
displays[epdIndex].init(0, false, 40); displays[epdIndex].init(0, false, 40);
} }
uint count = 0; uint count = 0;
while (EPD_BUSY[epdIndex].digitalRead() == HIGH || count < 10) { while (EPD_BUSY[epdIndex].digitalRead() == HIGH || count < 10)
{
vTaskDelay(pdMS_TO_TICKS(100)); vTaskDelay(pdMS_TO_TICKS(100));
count++; count++;
} }
@ -227,16 +287,20 @@ extern "C" void updateDisplay(void *pvParameters) noexcept {
(millis() - lastFullRefresh[epdIndex]) > (millis() - lastFullRefresh[epdIndex]) >
(preferences.getUInt("fullRefreshMin", (preferences.getUInt("fullRefreshMin",
DEFAULT_MINUTES_FULL_REFRESH) * DEFAULT_MINUTES_FULL_REFRESH) *
60 * 1000)) { 60 * 1000))
{
updatePartial = false; updatePartial = false;
} }
char tries = 0; char tries = 0;
while (tries < 3) { while (tries < 3)
if (displays[epdIndex].displayWithReturn(updatePartial)) { {
if (displays[epdIndex].displayWithReturn(updatePartial))
{
displays[epdIndex].powerOff(); displays[epdIndex].powerOff();
currentEpdContent[epdIndex] = epdContent[epdIndex]; currentEpdContent[epdIndex] = epdContent[epdIndex];
if (!updatePartial) lastFullRefresh[epdIndex] = millis(); if (!updatePartial)
lastFullRefresh[epdIndex] = millis();
if (eventSourceTaskHandle != NULL) if (eventSourceTaskHandle != NULL)
xTaskNotifyGive(eventSourceTaskHandle); xTaskNotifyGive(eventSourceTaskHandle);
@ -251,7 +315,8 @@ extern "C" void updateDisplay(void *pvParameters) noexcept {
} }
void splitText(const uint dispNum, const String &top, const String &bottom, void splitText(const uint dispNum, const String &top, const String &bottom,
bool partial) { bool partial)
{
displays[dispNum].setRotation(2); displays[dispNum].setRotation(2);
displays[dispNum].setFont(&FONT_SMALL); displays[dispNum].setFont(&FONT_SMALL);
displays[dispNum].setTextColor(getFgColor()); displays[dispNum].setTextColor(getFgColor());
@ -290,24 +355,67 @@ void splitText(const uint dispNum, const String &top, const String &bottom,
} }
void showDigit(const uint dispNum, char chr, bool partial, void showDigit(const uint dispNum, char chr, bool partial,
const GFXfont *font) { const GFXfont *font)
{
String str(chr); String str(chr);
if (chr == '.')
{
str = "!";
}
displays[dispNum].setRotation(2); displays[dispNum].setRotation(2);
displays[dispNum].setFont(font); displays[dispNum].setFont(font);
displays[dispNum].setTextColor(getFgColor()); displays[dispNum].setTextColor(getFgColor());
int16_t tbx, tby; int16_t tbx, tby;
uint16_t tbw, tbh; uint16_t tbw, tbh;
displays[dispNum].getTextBounds(str, 0, 0, &tbx, &tby, &tbw, &tbh); displays[dispNum].getTextBounds(str, 0, 0, &tbx, &tby, &tbw, &tbh);
// center the bounding box by transposition of the origin: // center the bounding box by transposition of the origin:
uint16_t x = ((displays[dispNum].width() - tbw) / 2) - tbx; uint16_t x = ((displays[dispNum].width() - tbw) / 2) - tbx;
uint16_t y = ((displays[dispNum].height() - tbh) / 2) - tby; uint16_t y = ((displays[dispNum].height() - tbh) / 2) - tby;
// if (str.equals("."))
// {
// // int16_t yAdvance = font->yAdvance;
// // uint8_t charIndex = 46 - font->first;
// // GFXglyph *glyph = (&font->glyph)[charIndex];
// int16_t tbx2, tby2;
// uint16_t tbw2, tbh2;
// displays[dispNum].getTextBounds(".!", 0, 0, &tbx2, &tby2, &tbw2, &tbh2);
// y = ((displays[dispNum].height() - tbh2) / 2) - tby2;
// // Serial.print("yAdvance");
// // Serial.println(yAdvance);
// // if (glyph != nullptr) {
// // Serial.print("height");
// // Serial.println(glyph->height);
// // Serial.print("yOffset");
// // Serial.println(glyph->yOffset);
// // }
// // y = 250-99+18+19;
// }
displays[dispNum].fillScreen(getBgColor()); displays[dispNum].fillScreen(getBgColor());
displays[dispNum].setCursor(x, y); displays[dispNum].setCursor(x, y);
displays[dispNum].print(str); displays[dispNum].print(str);
if (chr == '.')
{
displays[dispNum].fillRect(x,y,displays[dispNum].width(),round(displays[dispNum].height() * 0.9), getBgColor());
}
// displays[dispNum].setCursor(10, 3);
// displays[dispNum].setFont(&FONT_SMALL);
// displays[dispNum].setTextColor(getFgColor());
// displays[dispNum].println("Y = " + y);
} }
void showChars(const uint dispNum, const String &chars, bool partial, void showChars(const uint dispNum, const String &chars, bool partial,
const GFXfont *font) { const GFXfont *font)
{
displays[dispNum].setRotation(2); displays[dispNum].setRotation(2);
displays[dispNum].setFont(font); displays[dispNum].setFont(font);
displays[dispNum].setTextColor(getFgColor()); displays[dispNum].setTextColor(getFgColor());
@ -330,10 +438,12 @@ void setBgColor(int color) { bgColor = color; }
void setFgColor(int color) { fgColor = color; } void setFgColor(int color) { fgColor = color; }
std::array<String, NUM_SCREENS> getCurrentEpdContent() { std::array<String, NUM_SCREENS> getCurrentEpdContent()
{
return currentEpdContent; return currentEpdContent;
} }
void renderText(const uint dispNum, const String &text, bool partial) { void renderText(const uint dispNum, const String &text, bool partial)
{
displays[dispNum].setRotation(2); displays[dispNum].setRotation(2);
displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(), displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(),
displays[dispNum].height()); displays[dispNum].height());
@ -346,20 +456,25 @@ void renderText(const uint dispNum, const String &text, bool partial) {
std::string line; std::string line;
while (std::getline(ss, line, '\n')) { while (std::getline(ss, line, '\n'))
if (line.rfind("*", 0) == 0) { {
if (line.rfind("*", 0) == 0)
{
line.erase(std::remove(line.begin(), line.end(), '*'), line.end()); line.erase(std::remove(line.begin(), line.end(), '*'), line.end());
displays[dispNum].setFont(&FreeSansBold9pt7b); displays[dispNum].setFont(&FreeSansBold9pt7b);
displays[dispNum].println(line.c_str()); displays[dispNum].println(line.c_str());
} else { }
else
{
displays[dispNum].setFont(&FreeSans9pt7b); displays[dispNum].setFont(&FreeSans9pt7b);
displays[dispNum].println(line.c_str()); displays[dispNum].println(line.c_str());
} }
} }
} }
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
uint8_t tempBuffer[800]; uint8_t tempBuffer[800];
@ -379,8 +494,10 @@ void renderQr(const uint dispNum, const String &text, bool partial) {
displays[dispNum].fillScreen(GxEPD_WHITE); displays[dispNum].fillScreen(GxEPD_WHITE);
const int border = 0; const int border = 0;
for (int y = -border; y < size * 4 + border; y++) { for (int y = -border; y < size * 4 + border; y++)
for (int x = -border; x < size * 4 + border; x++) { {
for (int x = -border; x < size * 4 + border; x++)
{
displays[dispNum].drawPixel( displays[dispNum].drawPixel(
padding + x, paddingY + y, padding + x, paddingY + y,
qrcodegen_getModule(qrcode, floor(float(x) / 4), floor(float(y) / 4)) qrcodegen_getModule(qrcode, floor(float(x) / 4), floor(float(y) / 4))
@ -391,16 +508,22 @@ void renderQr(const uint dispNum, const String &text, bool partial) {
#endif #endif
} }
void waitUntilNoneBusy() { void waitUntilNoneBusy()
for (int i = 0; i < NUM_SCREENS; i++) { {
for (int i = 0; i < NUM_SCREENS; i++)
{
uint count = 0; uint count = 0;
while (EPD_BUSY[i].digitalRead()) { while (EPD_BUSY[i].digitalRead())
{
count++; count++;
vTaskDelay(10); vTaskDelay(10);
if (count == 200) { if (count == 200)
{
// displays[i].init(0, false); // displays[i].init(0, false);
vTaskDelay(100); vTaskDelay(100);
} else if (count > 205) { }
else if (count > 205)
{
Serial.printf("Busy timeout %d", i); Serial.printf("Busy timeout %d", i);
break; break;
} }

View File

@ -36,7 +36,7 @@ void workerTask(void *pvParameters) {
if (getCurrentScreen() == SCREEN_BTC_TICKER) { if (getCurrentScreen() == SCREEN_BTC_TICKER) {
taskEpdContent = parsePriceData(price, priceSymbol); taskEpdContent = parsePriceData(price, priceSymbol);
} else if (getCurrentScreen() == SCREEN_MSCW_TIME) { } else if (getCurrentScreen() == SCREEN_MSCW_TIME) {
taskEpdContent = parseSatsPerCurrency(price, priceSymbol); taskEpdContent = parseSatsPerCurrency(price, priceSymbol, preferences.getBool("useSatsSymbol", false));
} else { } else {
taskEpdContent = taskEpdContent =
parseMarketCap(getBlockHeight(), price, priceSymbol, parseMarketCap(getBlockHeight(), price, priceSymbol,
@ -50,7 +50,7 @@ void workerTask(void *pvParameters) {
if (getCurrentScreen() != SCREEN_HALVING_COUNTDOWN) { if (getCurrentScreen() != SCREEN_HALVING_COUNTDOWN) {
taskEpdContent = parseBlockHeight(getBlockHeight()); taskEpdContent = parseBlockHeight(getBlockHeight());
} else { } else {
taskEpdContent = parseHalvingCountdown(getBlockHeight()); taskEpdContent = parseHalvingCountdown(getBlockHeight(), preferences.getBool("useBlkCountdown", false));
} }
if (getCurrentScreen() == SCREEN_HALVING_COUNTDOWN || if (getCurrentScreen() == SCREEN_HALVING_COUNTDOWN ||

View File

@ -11,7 +11,7 @@ void setupWebserver() {
server.addHandler(&events); server.addHandler(&events);
// server.serveStatic("/css", LittleFS, "/css/"); // server.serveStatic("/css", LittleFS, "/css/");
// server.serveStatic("/js", LittleFS, "/js/"); server.serveStatic("/fonts", LittleFS, "/fonts/");
server.serveStatic("/build", LittleFS, "/build"); server.serveStatic("/build", LittleFS, "/build");
server.serveStatic("/swagger.json", LittleFS, "/swagger.json"); server.serveStatic("/swagger.json", LittleFS, "/swagger.json");
server.serveStatic("/api.html", LittleFS, "/api.html"); server.serveStatic("/api.html", LittleFS, "/api.html");
@ -320,7 +320,7 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) {
String boolSettings[] = {"fetchEurPrice", "ledTestOnPower", "ledFlashOnUpd", String boolSettings[] = {"fetchEurPrice", "ledTestOnPower", "ledFlashOnUpd",
"mdnsEnabled", "otaEnabled", "stealFocus", "mdnsEnabled", "otaEnabled", "stealFocus",
"mcapBigChar"}; "mcapBigChar", "useSatsSymbol", "useBlkCountdown"};
for (String setting : boolSettings) { for (String setting : boolSettings) {
if (settings.containsKey(setting)) { if (settings.containsKey(setting)) {
@ -402,11 +402,14 @@ void onApiSettingsGet(AsyncWebServerRequest *request) {
root["ledTestOnPower"] = preferences.getBool("ledTestOnPower", true); root["ledTestOnPower"] = preferences.getBool("ledTestOnPower", true);
root["ledFlashOnUpd"] = preferences.getBool("ledFlashOnUpd", false); root["ledFlashOnUpd"] = preferences.getBool("ledFlashOnUpd", false);
root["ledBrightness"] = preferences.getUInt("ledBrightness", 128); root["ledBrightness"] = preferences.getUInt("ledBrightness", 128);
root["stealFocus"] = preferences.getBool("stealFocus", true); root["stealFocus"] = preferences.getBool("stealFocus", false);
root["mcapBigChar"] = preferences.getBool("mcapBigChar", true); root["mcapBigChar"] = preferences.getBool("mcapBigChar", true);
root["mdnsEnabled"] = preferences.getBool("mdnsEnabled", true); root["mdnsEnabled"] = preferences.getBool("mdnsEnabled", true);
root["otaEnabled"] = preferences.getBool("otaEnabled", true); root["otaEnabled"] = preferences.getBool("otaEnabled", true);
root["fetchEurPrice"] = preferences.getBool("fetchEurPrice", false); root["fetchEurPrice"] = preferences.getBool("fetchEurPrice", false);
root["useSatsSymbol"] = preferences.getBool("useSatsSymbol", false);
root["useBlkCountdown"] = preferences.getBool("useBlkCountdown", false);
root["hostnamePrefix"] = preferences.getString("hostnamePrefix", "btclock"); root["hostnamePrefix"] = preferences.getString("hostnamePrefix", "btclock");
root["hostname"] = getMyHostname(); root["hostname"] = getMyHostname();
root["ip"] = WiFi.localIP(); root["ip"] = WiFi.localIP();

View File

@ -10,7 +10,7 @@ void tearDown(void) {
} }
void test_CorrectSatsPerDollarConversion(void) { void test_CorrectSatsPerDollarConversion(void) {
std::array<std::string, NUM_SCREENS> output = parseSatsPerCurrency(37253, '$'); std::array<std::string, NUM_SCREENS> output = parseSatsPerCurrency(37253, '$', false);
TEST_ASSERT_EQUAL_STRING("MSCW/TIME", output[0].c_str()); TEST_ASSERT_EQUAL_STRING("MSCW/TIME", output[0].c_str());
TEST_ASSERT_EQUAL_STRING("2", output[NUM_SCREENS-4].c_str()); TEST_ASSERT_EQUAL_STRING("2", output[NUM_SCREENS-4].c_str());
TEST_ASSERT_EQUAL_STRING("6", output[NUM_SCREENS-3].c_str()); TEST_ASSERT_EQUAL_STRING("6", output[NUM_SCREENS-3].c_str());
@ -40,13 +40,49 @@ void test_PriceOf100kusd(void) {
void test_PriceOf1MillionUsd(void) { void test_PriceOf1MillionUsd(void) {
std::array<std::string, NUM_SCREENS> output = parsePriceData(1000000, '$'); std::array<std::string, NUM_SCREENS> output = parsePriceData(1000000, '$');
TEST_ASSERT_EQUAL_STRING("BTC/USD", output[0].c_str()); TEST_ASSERT_EQUAL_STRING("BTC/USD", output[0].c_str());
for (int i = 1; i <= NUM_SCREENS-3; i++) {
TEST_ASSERT_EQUAL_STRING(" ", output[i].c_str()); TEST_ASSERT_EQUAL_STRING("1", output[NUM_SCREENS-5].c_str());
} TEST_ASSERT_EQUAL_STRING(".", output[NUM_SCREENS-4].c_str());
TEST_ASSERT_EQUAL_STRING("1", output[NUM_SCREENS-2].c_str()); TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS-3].c_str());
TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS-2].c_str());
TEST_ASSERT_EQUAL_STRING("M", output[NUM_SCREENS-1].c_str()); TEST_ASSERT_EQUAL_STRING("M", output[NUM_SCREENS-1].c_str());
} }
void test_McapLowerUsd(void) {
std::array<std::string, NUM_SCREENS> output = parseMarketCap(810000, 26000, '$', true);
TEST_ASSERT_EQUAL_STRING("USD/MCAP", output[0].c_str());
// TEST_ASSERT_EQUAL_STRING("$", output[NUM_SCREENS-6].c_str());
TEST_ASSERT_EQUAL_STRING("$", output[NUM_SCREENS-5].c_str());
TEST_ASSERT_EQUAL_STRING("5", output[NUM_SCREENS-4].c_str());
TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS-3].c_str());
TEST_ASSERT_EQUAL_STRING("7", output[NUM_SCREENS-2].c_str());
TEST_ASSERT_EQUAL_STRING("B", output[NUM_SCREENS-1].c_str());
}
void test_Mcap1TrillionUsd(void) {
std::array<std::string, NUM_SCREENS> output = parseMarketCap(831000, 52000, '$', true);
TEST_ASSERT_EQUAL_STRING("USD/MCAP", output[0].c_str());
TEST_ASSERT_EQUAL_STRING("$", output[NUM_SCREENS-6].c_str());
TEST_ASSERT_EQUAL_STRING("1", output[NUM_SCREENS-5].c_str());
TEST_ASSERT_EQUAL_STRING(".", output[NUM_SCREENS-4].c_str());
TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS-3].c_str());
TEST_ASSERT_EQUAL_STRING("2", output[NUM_SCREENS-2].c_str());
TEST_ASSERT_EQUAL_STRING("T", output[NUM_SCREENS-1].c_str());
}
void test_Mcap1TrillionEur(void) {
std::array<std::string, NUM_SCREENS> output = parseMarketCap(831000, 52000, '[', true);
TEST_ASSERT_EQUAL_STRING("EUR/MCAP", output[0].c_str());
TEST_ASSERT_EQUAL_STRING("[", output[NUM_SCREENS-6].c_str());
TEST_ASSERT_EQUAL_STRING("1", output[NUM_SCREENS-5].c_str());
TEST_ASSERT_EQUAL_STRING(".", output[NUM_SCREENS-4].c_str());
TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS-3].c_str());
TEST_ASSERT_EQUAL_STRING("2", output[NUM_SCREENS-2].c_str());
TEST_ASSERT_EQUAL_STRING("T", output[NUM_SCREENS-1].c_str());
}
// not needed when using generate_test_runner.rb // not needed when using generate_test_runner.rb
int runUnityTests(void) { int runUnityTests(void) {
UNITY_BEGIN(); UNITY_BEGIN();
@ -54,7 +90,10 @@ int runUnityTests(void) {
RUN_TEST(test_SixCharacterBlockHeight); RUN_TEST(test_SixCharacterBlockHeight);
RUN_TEST(test_SevenCharacterBlockHeight); RUN_TEST(test_SevenCharacterBlockHeight);
RUN_TEST(test_PriceOf100kusd); RUN_TEST(test_PriceOf100kusd);
RUN_TEST(test_PriceOf1MillionUsd); RUN_TEST(test_McapLowerUsd);
RUN_TEST(test_Mcap1TrillionUsd);
RUN_TEST(test_Mcap1TrillionEur);
//RUN_TEST(test_Mcap1MillionEur);
return UNITY_END(); return UNITY_END();
} }