forked from btclock/btclock_v3
WebUI: Add German translation, switch to own price source
This commit is contained in:
parent
a2fa0a12a8
commit
efaab00fb4
6 changed files with 117 additions and 48 deletions
2
data
2
data
|
@ -1 +1 @@
|
||||||
Subproject commit dcdf98964a42ccd83b2d2501bbed46a640bbc300
|
Subproject commit e47fc066b0608132c44a35f7041be80b263adcff
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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(×tamp);
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
|
@ -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
|
|
@ -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,12 +63,14 @@ 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:
|
case WEBSOCKET_EVENT_CONNECTED:
|
||||||
Serial.println(F("Connected to CoinCap.io WebSocket"));
|
Serial.println("Connected to " + String(config.uri) + " WebSocket");
|
||||||
priceNotifyInit = true;
|
priceNotifyInit = true;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -75,19 +86,23 @@ void onWebsocketPriceEvent(void *handler_args, esp_event_base_t base,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
10
src/lib/shared.cpp
Normal 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
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue