Add missing settings, webUI as submodule

This commit is contained in:
Djuri Baars 2024-03-17 18:47:26 +01:00
parent 6c3796c776
commit 585b50d0ba
12 changed files with 209 additions and 45 deletions

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "data"]
path = data
url = https://github.com/btclock/oc-webui.git

1
data Submodule

@ -0,0 +1 @@
Subproject commit 9df3329847f3939dc1242136e19746613fb83c4b

View file

View file

@ -9,7 +9,7 @@
; https://docs.platformio.org/page/projectconf.html ; https://docs.platformio.org/page/projectconf.html
[platformio] [platformio]
data_dir = data/build data_dir = data/build_gz
default_envs = lolin_s2_mini_213epd, lolin_s2_mini_29epd, lolin_s3_mini_213epd, lolin_s3_mini_29epd default_envs = lolin_s2_mini_213epd, lolin_s2_mini_29epd, lolin_s3_mini_213epd, lolin_s3_mini_29epd
[btclock_base] [btclock_base]
@ -19,6 +19,7 @@ monitor_speed = 115200
monitor_filters = esp32_exception_decoder, colorize monitor_filters = esp32_exception_decoder, colorize
board_build.filesystem = littlefs board_build.filesystem = littlefs
board_build.partitions = partition.csv board_build.partitions = partition.csv
extra_scripts = post:scripts/extra_script.py
build_flags = build_flags =
!python scripts/git_rev.py !python scripts/git_rev.py
-DLAST_BUILD_TIME=$UNIX_TIME -DLAST_BUILD_TIME=$UNIX_TIME

38
scripts/extra_script.py Normal file
View file

@ -0,0 +1,38 @@
Import("env")
import os
import gzip
from shutil import copyfileobj, rmtree
from pathlib import Path
def gzip_file(input_file, output_file):
with open(input_file, 'rb') as f_in:
with gzip.open(output_file, 'wb') as f_out:
copyfileobj(f_in, f_out)
def process_directory(input_dir, output_dir):
if os.path.exists(output_dir):
rmtree(output_dir)
for root, dirs, files in os.walk(input_dir):
relative_path = os.path.relpath(root, input_dir)
output_root = os.path.join(output_dir, relative_path)
Path(output_root).mkdir(parents=True, exist_ok=True)
for file in files:
# if file.endswith(('.html', '.css', '.js')):
input_file_path = os.path.join(root, file)
output_file_path = os.path.join(output_root, file + '.gz')
gzip_file(input_file_path, output_file_path)
print(f'Compressed: {input_file_path} -> {output_file_path}')
# Build web interface before building FS
def before_buildfs(source, target, env):
env.Execute("cd data && yarn && yarn postinstall && yarn build")
input_directory = 'data/dist'
output_directory = 'data/build_gz'
process_directory(input_directory, output_directory)
os.environ["PUBLIC_BASE_URL"] = ""
env.AddPreAction("$BUILD_DIR/littlefs.bin", before_buildfs)

View file

@ -3,7 +3,7 @@
Preferences preferences; Preferences preferences;
const char *ntpServer = "pool.ntp.org"; const char *ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 0; // const long gmtOffset_sec = 0;
const int daylightOffset_sec = 3600; const int daylightOffset_sec = 3600;
TaskHandle_t OTAHandle = NULL; TaskHandle_t OTAHandle = NULL;
@ -14,7 +14,7 @@ bool isUpdating = false;
void setupTime() void setupTime()
{ {
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer); configTime(preferences.getInt(SETTING_TIME_OFFSET_MIN), daylightOffset_sec, ntpServer);
} }
void setupPreferences() void setupPreferences()
@ -48,10 +48,44 @@ void setupPreferences()
{ {
preferences.putString(SETTING_MEMPOOL_INSTANCE, "https://mempool.space"); preferences.putString(SETTING_MEMPOOL_INSTANCE, "https://mempool.space");
} }
if (!preferences.isKey(SETTING_TIME_FORMAT))
{
preferences.putString(SETTING_TIME_FORMAT, "%H:%M:%S");
}
if (!preferences.isKey(SETTING_DATE_FORMAT))
{
preferences.putString(SETTING_DATE_FORMAT, "%d-%m-%Y");
}
if (!preferences.isKey(SETTING_DECIMAL_SEPARATOR))
{
preferences.putChar(SETTING_DECIMAL_SEPARATOR, '.');
}
if (!preferences.isKey(SETTING_POWER_SAVE_MODE))
{
preferences.putBool(SETTING_POWER_SAVE_MODE, false);
}
if (!preferences.isKey(SETTING_TIME_OFFSET_MIN))
{
preferences.putInt(SETTING_TIME_OFFSET_MIN, 0);
}
} }
void setupWifi() void setupWifi()
{ {
uint8_t mac[6];
WiFi.macAddress(mac);
unsigned long seed = 0;
for (int i = 0; i < 6; i++)
{
seed += (unsigned long)mac[i] << ((i & 1) * 8);
}
randomSeed(seed);
// WiFi.begin(, "); // WiFi.begin(, ");
WiFi.setAutoConnect(true); WiFi.setAutoConnect(true);
WiFi.setAutoReconnect(true); WiFi.setAutoReconnect(true);
@ -75,15 +109,10 @@ void setupWifi()
} }
} }
byte mac[6];
WiFi.macAddress(mac);
String softAP_SSID = String softAP_SSID =
String("OrangeBTClock"); String("OrangeBTClock");
WiFi.setHostname(softAP_SSID.c_str()); WiFi.setHostname(softAP_SSID.c_str());
String softAP_password = String softAP_password = getAPPassword();
base64::encode(String(mac[2], 16) + String(mac[4], 16) +
String(mac[5], 16) + String(mac[1], 16))
.substring(2, 10);
// wm.setConfigPortalTimeout(preferences.getUInt("wpTimeout", 600)); // wm.setConfigPortalTimeout(preferences.getUInt("wpTimeout", 600));
wm.setWiFiAutoReconnect(false); wm.setWiFiAutoReconnect(false);
@ -214,31 +243,36 @@ void setupOTA()
ArduinoOTA.begin(); ArduinoOTA.begin();
xTaskCreatePinnedToCore( xTaskCreatePinnedToCore(
OTAUpdateTask, // Task function OTAUpdateTask, // Task function
"OTAUpdateTask", // Task name "OTAUpdateTask", // Task name
4096, // Stack size 4096, // Stack size
NULL, // Task parameters NULL, // Task parameters
1, // Priority (higher value means higher priority) 1, // Priority (higher value means higher priority)
&OTAHandle, // Task handle &OTAHandle, // Task handle
0 // Core to run the task (0 or 1) 0 // Core to run the task (0 or 1)
); );
} }
void OTAUpdateTask(void *pvParameters)
void OTAUpdateTask(void *pvParameters) { {
for (;;) { for (;;)
ArduinoOTA.handle(); // Handle OTA updates {
ArduinoOTA.handle(); // Handle OTA updates
vTaskDelay(1000 / portTICK_PERIOD_MS); // Delay to avoid high CPU usage vTaskDelay(1000 / portTICK_PERIOD_MS); // Delay to avoid high CPU usage
} }
} }
char getCurrencyIcon() { char getCurrencyIcon()
{
char ret; char ret;
const char* currency = preferences.getString(SETTING_CURRENCY).c_str(); const char *currency = preferences.getString(SETTING_CURRENCY).c_str();
if (strcmp(currency, CURRENCY_USD) == 0) { if (strcmp(currency, CURRENCY_USD) == 0)
ret = ICON_DOLLAR; {
} else if(strcmp(currency, CURRENCY_EUR) == 0) { ret = ICON_DOLLAR;
ret = ICON_EURO; }
else if (strcmp(currency, CURRENCY_EUR) == 0)
{
ret = ICON_EURO;
} }
// break; // break;
// case CURRENCY_GBP: // case CURRENCY_GBP:

View file

@ -59,6 +59,7 @@ void loop()
{ {
if (isUpdating) if (isUpdating)
{ {
delay(1000);
return; return;
} }
@ -135,22 +136,22 @@ void loop()
{ {
icon = getCurrencyIcon(); icon = getCurrencyIcon();
int64_t marketCap = static_cast<std::int64_t>(getSupplyAtBlock(getBlock()) * double(getPrice())); int64_t marketCap = static_cast<std::int64_t>(getSupplyAtBlock(getBlock()) * double(getPrice()));
rowContent = String(formatNumberWithSuffix(marketCap, 4)); rowContent = String(formatNumberWithSuffix(marketCap, 8));
break; break;
} }
case LINE_TIME: case LINE_TIME:
{ {
icon = ICON_GLOBE; icon = ICON_GLOBE;
char dateString[10]; char dateString[16];
strftime(dateString, 10, "%H:%M:%S", &timeinfo); strftime(dateString, sizeof(dateString), preferences.getString(SETTING_TIME_FORMAT).c_str(), &timeinfo);
rowContent = dateString; rowContent = dateString;
break; break;
} }
case LINE_DATE: case LINE_DATE:
{ {
icon = ICON_GLOBE; icon = ICON_GLOBE;
char dateString[10]; char dateString[16];
strftime(dateString, 10, "%x", &timeinfo); strftime(dateString, sizeof(dateString), preferences.getString(SETTING_DATE_FORMAT).c_str(), &timeinfo);
rowContent = dateString; rowContent = dateString;
break; break;
} }

View file

@ -1,13 +1,2 @@
#include "shared.hpp" #include "shared.hpp"
String getMyHostname()
{
uint8_t mac[6];
// WiFi.macAddress(mac);
esp_efuse_mac_get_default(mac);
char hostname[15];
String hostnamePrefix = preferences.getString(SETTING_HOSTNAME_PREFIX);
snprintf(hostname, sizeof(hostname), "%s-%02x%02x%02x", hostnamePrefix,
mac[3], mac[4], mac[5]);
return hostname;
}

View file

@ -5,6 +5,7 @@
#include <Preferences.h> #include <Preferences.h>
#include <GxEPD2.h> #include <GxEPD2.h>
#include <GxEPD2_BW.h> #include <GxEPD2_BW.h>
#include "utils.hpp"
#include "fonts/fonts.hpp" #include "fonts/fonts.hpp"
#ifdef VERSION_EPD_2_13 #ifdef VERSION_EPD_2_13
@ -62,6 +63,12 @@
#define SETTING_CURRENCY "currency" #define SETTING_CURRENCY "currency"
#define SETTING_HOSTNAME_PREFIX "hostnamePrefix" #define SETTING_HOSTNAME_PREFIX "hostnamePrefix"
#define SETTING_MEMPOOL_INSTANCE "mempoolInstance" #define SETTING_MEMPOOL_INSTANCE "mempoolInstance"
#define SETTING_POWER_SAVE_MODE "powerSaveMode"
#define SETTING_TIME_OFFSET_MIN "timeOffsetMin"
#define SETTING_DECIMAL_SEPARATOR "decSeparator"
#define SETTING_TIME_FORMAT "timeFormat"
#define SETTING_DATE_FORMAT "dateFormat"
const int LINE_BLOCKHEIGHT = 0; const int LINE_BLOCKHEIGHT = 0;
const int LINE_MEMPOOL_FEES = 1; const int LINE_MEMPOOL_FEES = 1;
@ -94,4 +101,3 @@ extern char currentIcon1;
extern char currentIcon2; extern char currentIcon2;
extern char currentIcon3; extern char currentIcon3;
String getMyHostname();

32
src/utils.cpp Normal file
View file

@ -0,0 +1,32 @@
#include "utils.hpp"
String getAPPassword()
{
byte mac[6];
WiFi.macAddress(mac);
const char charset[] = "abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ23456789";
char password[9]; // 8 characters + null terminator
snprintf(password, sizeof(password), "%c%c%c%c%c%c%c%c",
charset[mac[0] % (sizeof(charset) - 1)],
charset[mac[1] % (sizeof(charset) - 1)],
charset[mac[2] % (sizeof(charset) - 1)],
charset[mac[3] % (sizeof(charset) - 1)],
charset[mac[4] % (sizeof(charset) - 1)],
charset[mac[5] % (sizeof(charset) - 1)],
charset[(mac[0] + mac[1] + mac[2] + mac[3] + mac[4] + mac[5]) % (sizeof(charset) - 1)],
charset[(mac[0] * mac[1] * mac[2] * mac[3] * mac[4] * mac[5]) % (sizeof(charset) - 1)]);
return password;
}
String getMyHostname()
{
uint8_t mac[6];
// WiFi.macAddress(mac);
esp_efuse_mac_get_default(mac);
char hostname[15];
String hostnamePrefix = preferences.getString(SETTING_HOSTNAME_PREFIX);
snprintf(hostname, sizeof(hostname), "%s-%02x%02x%02x", hostnamePrefix,
mac[3], mac[4], mac[5]);
return hostname;
}

27
src/utils.hpp Normal file
View file

@ -0,0 +1,27 @@
#pragma once
#include <WiFi.h>
#include <Arduino.h>
#include <ArduinoJson.hpp>
#include "shared.hpp"
namespace ArduinoJson {
template <>
struct Converter<char> {
static void toJson(char c, JsonVariant var) {
var.set(static_cast<signed char>(c));
}
static char fromJson(JsonVariantConst src) {
return static_cast<char>(src.as<signed char>());
}
static bool checkJson(JsonVariantConst src) {
return src.is<signed char>();
}
};
}
String getAPPassword();
String getMyHostname();

View file

@ -3,8 +3,10 @@
AsyncWebServer server(80); AsyncWebServer server(80);
const String uintSettings[] = {SETTING_ROW1_CONTENT, SETTING_ROW2_CONTENT, SETTING_ROW3_CONTENT}; const String uintSettings[] = {SETTING_ROW1_CONTENT, SETTING_ROW2_CONTENT, SETTING_ROW3_CONTENT};
const String stringSettings[] = {SETTING_CURRENCY,SETTING_MEMPOOL_INSTANCE}; const String intSettings[] = {SETTING_TIME_OFFSET_MIN};
const String boolSettings[] = {}; const String stringSettings[] = {SETTING_CURRENCY, SETTING_MEMPOOL_INSTANCE, SETTING_TIME_FORMAT, SETTING_DATE_FORMAT};
const String charSettings[] = {SETTING_DECIMAL_SEPARATOR};
const String boolSettings[] = {SETTING_POWER_SAVE_MODE};
void setupWebserver() void setupWebserver()
{ {
@ -68,11 +70,21 @@ void onApiSettingsGet(AsyncWebServerRequest *request)
root[setting] = preferences.getUInt(setting.c_str()); root[setting] = preferences.getUInt(setting.c_str());
} }
for (String setting : intSettings)
{
root[setting] = preferences.getInt(setting.c_str());
}
for (String setting : stringSettings) for (String setting : stringSettings)
{ {
root[setting] = preferences.getString(setting.c_str()); root[setting] = preferences.getString(setting.c_str());
} }
for (String setting : charSettings)
{
root[setting] = preferences.getChar(setting.c_str());
}
for (String setting : boolSettings) for (String setting : boolSettings)
{ {
root[setting] = preferences.getBool(setting.c_str()); root[setting] = preferences.getBool(setting.c_str());
@ -110,6 +122,16 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json)
} }
} }
for (String setting : intSettings)
{
if (settings.containsKey(setting))
{
preferences.putInt(setting.c_str(), settings[setting].as<int>());
Serial.printf("Setting %s to %d\r\n", setting.c_str(),
settings[setting].as<uint>());
}
}
for (String setting : stringSettings) for (String setting : stringSettings)
{ {
if (settings.containsKey(setting)) if (settings.containsKey(setting))
@ -120,6 +142,16 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json)
} }
} }
for (String setting : charSettings)
{
if (settings.containsKey(setting))
{
preferences.putChar(setting.c_str(), settings[setting].as<char>());
Serial.printf("Setting %s to %s\r\n", setting.c_str(),
settings[setting].as<String>());
}
}
for (String setting : boolSettings) for (String setting : boolSettings)
{ {
if (settings.containsKey(setting)) if (settings.containsKey(setting))