WebUI: Add German translation, switch to own price source

This commit is contained in:
Djuri Baars 2024-05-08 23:54:17 +02:00
parent a2fa0a12a8
commit efaab00fb4
6 changed files with 117 additions and 48 deletions

2
data

@ -1 +1 @@
Subproject commit dcdf98964a42ccd83b2d2501bbed46a640bbc300 Subproject commit e47fc066b0608132c44a35f7041be80b263adcff

View file

@ -41,7 +41,8 @@ void setup()
if (mcp1.digitalRead(0) == LOW) if (mcp1.digitalRead(0) == LOW)
{ {
// Then loop forever to prevent anything else from writing to the screen // Then loop forever to prevent anything else from writing to the screen
while (true) { while (true)
{
delay(1000); delay(1000);
} }
} }
@ -84,7 +85,7 @@ void tryImprovSetup()
} }
} }
// if (!preferences.getBool("wifiConfigured", false)) // if (!preferences.getBool("wifiConfigured", false))
{ {
queueLedEffect(LED_EFFECT_WIFI_WAIT_FOR_CONFIG); queueLedEffect(LED_EFFECT_WIFI_WAIT_FOR_CONFIG);
@ -130,13 +131,23 @@ void tryImprovSetup()
const String explainText = "*SSID: *\r\n" + const String explainText = "*SSID: *\r\n" +
wifiManager->getConfigPortalSSID() + wifiManager->getConfigPortalSSID() +
"\r\n\r\n*Password:*\r\n" + softAP_password; "\r\n\r\n*Password:*\r\n" + softAP_password;
// Set the UNIX timestamp
time_t timestamp = LAST_BUILD_TIME; // Example timestamp: March 7, 2021 00:00:00 UTC
// Convert the timestamp to a struct tm in UTC
struct tm *timeinfo = gmtime(&timestamp);
// Format the date
char formattedDate[20];
strftime(formattedDate, sizeof(formattedDate), "%y-%m-%d\r\n%H:%M:%S", timeinfo);
std::array<String, NUM_SCREENS> epdContent = { std::array<String, NUM_SCREENS> epdContent = {
"Welcome!", "Welcome!",
"Bienvenidos!", "Bienvenidos!",
"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(), "*Hostname*:\r\n" + getMyHostname() + "\r\n\r\n" + "*FW build date:*\r\n" + formattedDate,
qrText}; qrText};
setEpdContent(epdContent); }); setEpdContent(epdContent); });
@ -311,6 +322,17 @@ void setupHardware()
Serial.println(F("Error loading WebUI")); Serial.println(F("Error loading WebUI"));
} }
// if (!LittleFS.exists("/qr.txt"))
// {
// File f = LittleFS.open("/qr.txt", "w");
// if(f) {
// } else {
// Serial.println(F("Can't write QR to FS"));
// }
// }
setupLeds(); setupLeds();
WiFi.setHostname(getMyHostname().c_str()); WiFi.setHostname(getMyHostname().c_str());
@ -665,17 +687,27 @@ String getMyHostname()
return hostname; return hostname;
} }
uint getLastTimeSync() { uint getLastTimeSync()
{
return lastTimeSync; return lastTimeSync;
} }
#ifdef HAS_FRONTLIGHT #ifdef HAS_FRONTLIGHT
void setupFrontlight() { void setupFrontlight()
flArray.begin(); {
if (!flArray.begin(PCA9685_MODE1_AUTOINCR, PCA9685_MODE2_INVERT))
{
Serial.println(F("FL driver error"));
return;
}
Serial.println(F("FL driver active"));
flArray.setFrequency(1000); flArray.setFrequency(1000);
flArray.setOutputEnablePin(PCA_OE_PIN); flArray.setOutputEnablePin(PCA_OE_PIN);
flArray.setOutputEnable(true);
if (!preferences.isKey("flMaxBrightness")) { delay(1000);
flArray.setOutputEnable(false);
if (!preferences.isKey("flMaxBrightness"))
{
preferences.putUInt("flMaxBrightness", 4095); preferences.putUInt("flMaxBrightness", 4095);
} }
// Initialize all LEDs to off // Initialize all LEDs to off

View file

@ -339,7 +339,7 @@ void frontlightFadeInAll() {
for (int ledPin = 0; ledPin < NUM_SCREENS; ledPin++) { for (int ledPin = 0; ledPin < NUM_SCREENS; ledPin++) {
flArray.setPWM(ledPin, 0, dutyCycle); flArray.setPWM(ledPin, 0, dutyCycle);
} }
delay(flDelayTime); vTaskDelay(pdMS_TO_TICKS(flDelayTime));
} }
} }
@ -348,21 +348,21 @@ void frontlightFadeOutAll() {
for (int ledPin = 0; ledPin < NUM_SCREENS; ledPin++) { for (int ledPin = 0; ledPin < NUM_SCREENS; ledPin++) {
flArray.setPWM(ledPin, 0, dutyCycle); flArray.setPWM(ledPin, 0, dutyCycle);
} }
delay(flDelayTime); vTaskDelay(pdMS_TO_TICKS(flDelayTime));
} }
} }
void frontlightFadeIn(uint num) { void frontlightFadeIn(uint num) {
for (int dutyCycle = 0; dutyCycle <= preferences.getUInt("flMaxBrightness"); dutyCycle += 5) { for (int dutyCycle = 0; dutyCycle <= preferences.getUInt("flMaxBrightness"); dutyCycle += 5) {
flArray.setPWM(num, 0, dutyCycle); flArray.setPWM(num, 0, dutyCycle);
delay(flDelayTime); vTaskDelay(pdMS_TO_TICKS(flDelayTime));
} }
} }
void frontlightFadeOut(uint num) { void frontlightFadeOut(uint num) {
for (int dutyCycle = preferences.getUInt("flMaxBrightness"); dutyCycle >= 0; dutyCycle -= 5) { for (int dutyCycle = preferences.getUInt("flMaxBrightness"); dutyCycle >= 0; dutyCycle -= 5) {
flArray.setPWM(num, 0, dutyCycle); flArray.setPWM(num, 0, dutyCycle);
delay(flDelayTime); vTaskDelay(pdMS_TO_TICKS(flDelayTime));
} }
} }
#endif #endif

View file

@ -1,5 +1,6 @@
#include "price_notify.hpp" #include "price_notify.hpp"
const char *wsOwnServerPrice = "wss://ws.btclock.store/ws?assets=bitcoin";
const char *wsServerPrice = "wss://ws.coincap.io/prices?assets=bitcoin"; const char *wsServerPrice = "wss://ws.coincap.io/prices?assets=bitcoin";
// const char* coinCapWsCert = R"(-----BEGIN CERTIFICATE----- // const char* coinCapWsCert = R"(-----BEGIN CERTIFICATE-----
@ -35,17 +36,25 @@ const char *wsServerPrice = "wss://ws.coincap.io/prices?assets=bitcoin";
// WebsocketsClient client; // WebsocketsClient client;
esp_websocket_client_handle_t clientPrice = NULL; esp_websocket_client_handle_t clientPrice = NULL;
uint currentPrice = 30000; esp_websocket_client_config_t config;
uint currentPrice = 50000;
unsigned long int lastPriceUpdate; unsigned long int lastPriceUpdate;
bool priceNotifyInit = false; bool priceNotifyInit = false;
void setupPriceNotify() { void setupPriceNotify()
{
// currentPrice = preferences.get("lastPrice", 30000); // currentPrice = preferences.get("lastPrice", 30000);
esp_websocket_client_config_t config = {.uri = wsServerPrice, if (preferences.getBool("ownPriceSource", true))
// .task_stack = (7*1024), {
// .cert_pem = coinCapWsCert, config = {.uri = wsOwnServerPrice,
.user_agent = USER_AGENT}; .user_agent = USER_AGENT};
}
else
{
config = {.uri = wsServerPrice,
.user_agent = USER_AGENT};
}
clientPrice = esp_websocket_client_init(&config); clientPrice = esp_websocket_client_init(&config);
esp_websocket_register_events(clientPrice, WEBSOCKET_EVENT_ANY, esp_websocket_register_events(clientPrice, WEBSOCKET_EVENT_ANY,
@ -54,40 +63,46 @@ void setupPriceNotify() {
} }
void onWebsocketPriceEvent(void *handler_args, esp_event_base_t base, void onWebsocketPriceEvent(void *handler_args, esp_event_base_t base,
int32_t event_id, void *event_data) { int32_t event_id, void *event_data)
{
esp_websocket_event_data_t *data = (esp_websocket_event_data_t *)event_data; esp_websocket_event_data_t *data = (esp_websocket_event_data_t *)event_data;
switch (event_id) { switch (event_id)
case WEBSOCKET_EVENT_CONNECTED: {
Serial.println(F("Connected to CoinCap.io WebSocket")); case WEBSOCKET_EVENT_CONNECTED:
priceNotifyInit = true; Serial.println("Connected to " + String(config.uri) + " WebSocket");
priceNotifyInit = true;
break; break;
case WEBSOCKET_EVENT_DATA: case WEBSOCKET_EVENT_DATA:
onWebsocketPriceMessage(data); onWebsocketPriceMessage(data);
break; break;
case WEBSOCKET_EVENT_ERROR: case WEBSOCKET_EVENT_ERROR:
Serial.println(F("Price WS Connnection error")); Serial.println(F("Price WS Connnection error"));
break; break;
case WEBSOCKET_EVENT_DISCONNECTED: case WEBSOCKET_EVENT_DISCONNECTED:
Serial.println(F("Price WS Connnection Closed")); Serial.println(F("Price WS Connnection Closed"));
break; break;
} }
} }
void onWebsocketPriceMessage(esp_websocket_event_data_t *event_data) { void onWebsocketPriceMessage(esp_websocket_event_data_t *event_data)
{
JsonDocument doc; JsonDocument doc;
deserializeJson(doc, (char *)event_data->data_ptr); deserializeJson(doc, (char *)event_data->data_ptr);
if (doc.containsKey("bitcoin")) { if (doc.containsKey("bitcoin"))
if (currentPrice != doc["bitcoin"].as<long>()) { {
if (currentPrice != doc["bitcoin"].as<long>())
{
uint minSecPriceUpd = preferences.getUInt( uint minSecPriceUpd = preferences.getUInt(
"minSecPriceUpd", DEFAULT_SECONDS_BETWEEN_PRICE_UPDATE); "minSecPriceUpd", DEFAULT_SECONDS_BETWEEN_PRICE_UPDATE);
uint currentTime = esp_timer_get_time() / 1000000; uint currentTime = esp_timer_get_time() / 1000000;
if (lastPriceUpdate == 0 || if (lastPriceUpdate == 0 ||
(currentTime - lastPriceUpdate) > minSecPriceUpd) { (currentTime - lastPriceUpdate) > minSecPriceUpd)
{
// const unsigned long oldPrice = currentPrice; // const unsigned long oldPrice = currentPrice;
currentPrice = doc["bitcoin"].as<uint>(); currentPrice = doc["bitcoin"].as<uint>();
preferences.putUInt("lastPrice", currentPrice); preferences.putUInt("lastPrice", currentPrice);
@ -95,7 +110,8 @@ void onWebsocketPriceMessage(esp_websocket_event_data_t *event_data) {
// if (abs((int)(oldPrice-currentPrice)) > round(0.0015*oldPrice)) { // if (abs((int)(oldPrice-currentPrice)) > round(0.0015*oldPrice)) {
if (workQueue != nullptr && (getCurrentScreen() == SCREEN_BTC_TICKER || if (workQueue != nullptr && (getCurrentScreen() == SCREEN_BTC_TICKER ||
getCurrentScreen() == SCREEN_MSCW_TIME || getCurrentScreen() == SCREEN_MSCW_TIME ||
getCurrentScreen() == SCREEN_MARKET_CAP)) { getCurrentScreen() == SCREEN_MARKET_CAP))
{
WorkItem priceUpdate = {TASK_PRICE_UPDATE, 0}; WorkItem priceUpdate = {TASK_PRICE_UPDATE, 0};
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY); xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
} }
@ -105,7 +121,8 @@ void onWebsocketPriceMessage(esp_websocket_event_data_t *event_data) {
} }
} }
uint getLastPriceUpdate() { uint getLastPriceUpdate()
{
return lastPriceUpdate; return lastPriceUpdate;
} }
@ -113,17 +130,22 @@ uint getPrice() { return currentPrice; }
void setPrice(uint newPrice) { currentPrice = newPrice; } void setPrice(uint newPrice) { currentPrice = newPrice; }
bool isPriceNotifyConnected() { bool isPriceNotifyConnected()
if (clientPrice == NULL) return false; {
if (clientPrice == NULL)
return false;
return esp_websocket_client_is_connected(clientPrice); return esp_websocket_client_is_connected(clientPrice);
} }
bool getPriceNotifyInit() { bool getPriceNotifyInit()
{
return priceNotifyInit; return priceNotifyInit;
} }
void stopPriceNotify() { void stopPriceNotify()
if (clientPrice == NULL) return; {
if (clientPrice == NULL)
return;
esp_websocket_client_close(clientPrice, pdMS_TO_TICKS(5000)); esp_websocket_client_close(clientPrice, pdMS_TO_TICKS(5000));
esp_websocket_client_stop(clientPrice); esp_websocket_client_stop(clientPrice);
esp_websocket_client_destroy(clientPrice); esp_websocket_client_destroy(clientPrice);
@ -131,9 +153,11 @@ void stopPriceNotify() {
clientPrice = NULL; clientPrice = NULL;
} }
void restartPriceNotify() { void restartPriceNotify()
{
stopPriceNotify(); stopPriceNotify();
if (clientPrice == NULL) { if (clientPrice == NULL)
{
setupPriceNotify(); setupPriceNotify();
return; return;
} }

10
src/lib/shared.cpp Normal file
View file

@ -0,0 +1,10 @@
#include "shared.hpp"
#ifdef TEST_SCREENS
uint8_t input_buffer[3 * input_buffer_pixels]; // up to depth 24
uint8_t output_row_mono_buffer[max_row_width / 8]; // buffer for at least one row of b/w bits
uint8_t output_row_color_buffer[max_row_width / 8]; // buffer for at least one row of color bits
uint8_t mono_palette_buffer[max_palette_pixels / 8]; // palette buffer for depth <= 8 b/w
uint8_t color_palette_buffer[max_palette_pixels / 8]; // palette buffer for depth <= 8 c/w
uint16_t rgb_palette_buffer[max_palette_pixels]; // palette buffer for depth <= 8 for buffered graphics, needed for 7-color display
#endif

View file

@ -329,7 +329,7 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) {
String boolSettings[] = {"fetchEurPrice", "ledTestOnPower", "ledFlashOnUpd", String boolSettings[] = {"fetchEurPrice", "ledTestOnPower", "ledFlashOnUpd",
"mdnsEnabled", "otaEnabled", "stealFocus", "mdnsEnabled", "otaEnabled", "stealFocus",
"mcapBigChar", "useSatsSymbol", "useBlkCountdown", "mcapBigChar", "useSatsSymbol", "useBlkCountdown",
"suffixPrice", "disableLeds"}; "suffixPrice", "disableLeds", "ownPriceSource", "flAlwaysOn"};
for (String setting : boolSettings) { for (String setting : boolSettings) {
if (settings.containsKey(setting)) { if (settings.containsKey(setting)) {
@ -425,10 +425,13 @@ void onApiSettingsGet(AsyncWebServerRequest *request) {
root["hostname"] = getMyHostname(); root["hostname"] = getMyHostname();
root["ip"] = WiFi.localIP(); root["ip"] = WiFi.localIP();
root["txPower"] = WiFi.getTxPower(); root["txPower"] = WiFi.getTxPower();
root["ownPriceSource"] = preferences.getBool("ownPriceSource", true);
#ifdef HAS_FRONTLIGHT #ifdef HAS_FRONTLIGHT
root["hasFrontlight"] = true; root["hasFrontlight"] = true;
root["flMaxBrightness"] = preferences.getUInt("flMaxBrightness", 4095); root["flMaxBrightness"] = preferences.getUInt("flMaxBrightness", 4095);
root["flAlwaysOn"] = preferences.getBool("flAlwaysOn", false);
#else #else
root["hasFrontlight"] = false; root["hasFrontlight"] = false;
#endif #endif