Initial import

This commit is contained in:
Chad Mercer 2026-05-30 20:26:01 -05:00
commit 6e5975dd4b
9 changed files with 3127 additions and 0 deletions

125
docs/README.md Normal file
View file

@ -0,0 +1,125 @@
# Bitcoin Dashboard for Elecrow 7-inch HMI Display
A real-time financial dashboard displaying cryptocurrency, precious metals, stocks, and market indices on the Elecrow 7.0-inch ESP32 HMI Display.
## Hardware
- **Display**: Elecrow 7.0-inch ESP32 HMI Display (Advance series)
- **Resolution**: 800x480 RGB parallel interface
- **Touch**: GT911 capacitive touch controller
- **MCU**: ESP32-S3 with N4R8 module (4MB Flash, 8MB PSRAM)
## Features
- Real-time price data from Yahoo Finance API
- Auto-refresh every 5 minutes
- Touch to manual refresh
- WiFi credentials stored in persistent memory
- Antialiased fonts (DejaVu family)
## Displayed Assets
| Column | Assets |
|--------|--------|
| Hard Money | Bitcoin (BTC/USD), Gold, Silver |
| Stocks | MSTR, STRC |
| Indices | NASDAQ, DOW, S&P 500 |
## Color Scheme
| Asset | Color | Hex |
|-------|-------|-----|
| Bitcoin | Orange | `#F7931A` |
| Gold | Gold | `#FFD700` |
| Silver | Silver | `#C0C0C0` |
| Stocks/Indices | Dollar Green | `#00A86B` |
| Status Bar | Bitcoin Orange | `#F7931A` |
## Software Stack
- **Framework**: Arduino (PlatformIO)
- **Display Library**: LovyanGFX v1.2.19
- **Fonts**: DejaVu (antialiased)
## Building
```bash
cd /home/chad/Documents/PlatformIO/Projects/bitcoin_dashboard
pio run -t upload
```
## PlatformIO Configuration
- **Platform**: espressif32@6.8.1
- **Board**: esp32-s3-devkitc-1
- **Partition**: huge_app.csv (3MB app, no OTA)
- **Flash Mode**: QIO @ 80MHz
- **PSRAM**: OPI (8MB)
## Data Source
Yahoo Finance API:
```
https://query1.finance.yahoo.com/v8/finance/chart/{SYMBOL}?interval=1d&range=1d
```
### Symbol Mapping
| Display | Yahoo Symbol |
|---------|--------------|
| Bitcoin | BTC-USD |
| Gold | GC=F |
| Silver | SI=F |
| MSTR | MSTR |
| STRC | STRC |
| NASDAQ | ^IXIC |
| DOW | ^DJI |
| S&P 500 | ^GSPC |
## Pin Configuration
### RGB Display Interface
| Signal | GPIO |
|--------|------|
| D0-D15 | 15, 7, 6, 5, 4, 9, 46, 3, 8, 16, 1, 14, 21, 47, 48, 45 |
| HSYNC | GPIO 39 |
| VSYNC | GPIO 40 |
| DE | GPIO 41 |
| PCLK | GPIO 0 |
| Backlight | GPIO 2 |
### Touch Controller (GT911)
| Signal | GPIO |
|--------|------|
| SDA | GPIO 19 |
| SCL | GPIO 20 |
| I2C Address | 0x14 |
## WiFi Setup
WiFi credentials are stored in ESP32 preferences (persistent storage):
```cpp
preferences.begin("wifi", true);
preferences.putString("ssid", "your_ssid");
preferences.putString("password", "your_password");
preferences.end();
```
## Project Structure
```
bitcoin_dashboard/
├── src/
│ └── main.cpp # Main application
├── docs/
│ └── README.md # This file
├── platformio.ini # PlatformIO configuration
└── .gitignore
```
## License
MIT

108
include/lgfx_config.hpp Normal file
View file

@ -0,0 +1,108 @@
/**
* LGFX Display Configuration for Elecrow 7-inch HMI Display
* Based on working Arduino example
*/
#ifndef LGFX_CONFIG_HPP
#define LGFX_CONFIG_HPP
#define LGFX_USE_V1
#include <LovyanGFX.hpp>
#include <lgfx/v1/platforms/esp32s3/Panel_RGB.hpp>
#include <lgfx/v1/platforms/esp32s3/Bus_RGB.hpp>
#include <driver/i2c.h>
class LGFX : public lgfx::LGFX_Device {
public:
lgfx::Bus_RGB _bus_instance;
lgfx::Panel_RGB _panel_instance;
lgfx::Light_PWM _light_instance;
lgfx::Touch_GT911 _touch_instance;
LGFX(void) {
{
auto cfg = _panel_instance.config();
cfg.memory_width = 800;
cfg.memory_height = 480;
cfg.panel_width = 800;
cfg.panel_height = 480;
cfg.offset_x = 0;
cfg.offset_y = 0;
_panel_instance.config(cfg);
}
{
auto cfg = _bus_instance.config();
cfg.panel = &_panel_instance;
cfg.pin_d0 = GPIO_NUM_15;
cfg.pin_d1 = GPIO_NUM_7;
cfg.pin_d2 = GPIO_NUM_6;
cfg.pin_d3 = GPIO_NUM_5;
cfg.pin_d4 = GPIO_NUM_4;
cfg.pin_d5 = GPIO_NUM_9;
cfg.pin_d6 = GPIO_NUM_46;
cfg.pin_d7 = GPIO_NUM_3;
cfg.pin_d8 = GPIO_NUM_8;
cfg.pin_d9 = GPIO_NUM_16;
cfg.pin_d10 = GPIO_NUM_1;
cfg.pin_d11 = GPIO_NUM_14;
cfg.pin_d12 = GPIO_NUM_21;
cfg.pin_d13 = GPIO_NUM_47;
cfg.pin_d14 = GPIO_NUM_48;
cfg.pin_d15 = GPIO_NUM_45;
cfg.pin_henable = GPIO_NUM_41;
cfg.pin_vsync = GPIO_NUM_40;
cfg.pin_hsync = GPIO_NUM_39;
cfg.pin_pclk = GPIO_NUM_0;
cfg.freq_write = 12000000;
cfg.hsync_polarity = 0;
cfg.hsync_front_porch = 40;
cfg.hsync_pulse_width = 48;
cfg.hsync_back_porch = 40;
cfg.vsync_polarity = 0;
cfg.vsync_front_porch = 1;
cfg.vsync_pulse_width = 31;
cfg.vsync_back_porch = 13;
cfg.pclk_active_neg = 1;
cfg.de_idle_high = 0;
cfg.pclk_idle_high = 0;
_bus_instance.config(cfg);
}
_panel_instance.setBus(&_bus_instance);
{
auto cfg = _light_instance.config();
cfg.pin_bl = GPIO_NUM_2;
_light_instance.config(cfg);
}
_panel_instance.light(&_light_instance);
{
auto cfg = _touch_instance.config();
cfg.x_min = 0;
cfg.x_max = 799;
cfg.y_min = 0;
cfg.y_max = 479;
cfg.pin_int = -1;
cfg.pin_rst = -1;
cfg.bus_shared = false;
cfg.offset_rotation = 0;
cfg.i2c_port = I2C_NUM_1;
cfg.pin_sda = GPIO_NUM_19;
cfg.pin_scl = GPIO_NUM_20;
cfg.freq = 400000;
cfg.i2c_addr = 0x14;
_touch_instance.config(cfg);
_panel_instance.setTouch(&_touch_instance);
}
setPanel(&_panel_instance);
}
};
#endif // LGFX_CONFIG_HPP

145
include/lv_conf.h Normal file
View file

@ -0,0 +1,145 @@
/**
* LVGL Configuration for Bitcoin Dashboard
* Target: Elecrow 7-inch HMI Display (800x480)
*/
#ifndef LV_CONF_H
#define LV_CONF_H
#include <stdint.h>
#define LV_COLOR_DEPTH 16
#define LV_COLOR_16_SWAP 0
#define LV_HOR_RES_MAX 800
#define LV_VER_RES_MAX 480
#define LV_DPI_DEF 100
#define LV_DISP_DEF_REFR_PERIOD 16
#define LV_TICK_CUSTOM 1
#define LV_TICK_CUSTOM_INCLUDE "Arduino.h"
#define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis())
#define LV_MEM_CUSTOM 1
#define LV_MEM_CUSTOM_INCLUDE "Arduino.h"
#define LV_MEM_CUSTOM_ALLOC malloc
#define LV_MEM_CUSTOM_FREE free
#define LV_MEM_SIZE (64 * 1024U)
#define LV_MEM_ADR 0
#define LV_DRAW_CPU_ARM_ALIGN 4
#define LV_USE_DRAW_MASKS 1
#define LV_USE_DRAW_SW 1
#define LV_DRAW_SW_DRAW_UNIT_CNT 2
#define LV_USE_DRAW_SW_COMPLEX_GRADIENTS 1
#define LV_USE_DRAW_SW_SHADOW 1
#define LV_USE_DRAW_SW_BLUR 1
#define LV_USE_DRAW_SW_ARGB_TO_RGB565 1
#define LV_USE_ASSERT_NULL 1
#define LV_USE_ASSERT_MALLOC 1
#define LV_USE_MSG 1
#define LV_USE_FS_STDIO 0
#define LV_USE_FS_FATFS 0
#define LV_USE_FS_LITTLEFS 0
#define LV_USE_LODEPNG 0
#define LV_USE_LIBPNG 0
#define LV_USE_BMP 0
#define LV_USE_RLE 0
#define LV_USE_QRCODE 0
#define LV_USE_BARCODE 0
#define LV_USE_TJPGD 0
#define LV_USE_GIF 0
#define LV_USE_FLEX 1
#define LV_USE_GRID 1
#define LV_USE_SNAPSHOT 1
#define LV_USE_SYSMON 0
#define LV_USE_PERF_MONITOR 0
#define LV_USE_MEM_MONITOR 0
#define LV_THEME_DEFAULT_DARK 0
#define LV_THEME_DEFAULT_GROW 1
#define LV_USE_THEME_DEFAULT 1
#define LV_USE_THEME_BASIC 1
#define LV_USE_THEME_MONO 1
#define LV_USE_ARC 1
#define LV_USE_BAR 1
#define LV_USE_BTN 1
#define LV_USE_BTNMATRIX 1
#define LV_USE_CALENDAR 1
#define LV_USE_CANVAS 1
#define LV_USE_CHART 1
#define LV_USE_CHECKBOX 1
#define LV_USE_DROPDOWN 1
#define LV_USE_IMG 1
#define LV_USE_IMGBTN 1
#define LV_USE_KEYBOARD 1
#define LV_USE_LABEL 1
#define LV_LABEL_TEXT_SELECTION 1
#define LV_LABEL_LONG_TXT_HINT 1
#define LV_USE_LED 1
#define LV_USE_LINE 1
#define LV_USE_LIST 1
#define LV_USE_MENU 1
#define LV_USE_METER 1
#define LV_USE_MSGBOX 1
#define LV_USE_ROLLER 1
#define LV_USE_SCALE 1
#define LV_USE_SLIDER 1
#define LV_USE_SPAN 1
#define LV_USE_SPINBOX 1
#define LV_USE_SPINNER 1
#define LV_USE_SWITCH 1
#define LV_USE_TABVIEW 1
#define LV_USE_TABLE 1
#define LV_USE_TEXTAREA 1
#define LV_USE_TILEVIEW 1
#define LV_USE_WIN 1
#define LV_FONT_MONTSERRAT_12 1
#define LV_FONT_MONTSERRAT_14 1
#define LV_FONT_MONTSERRAT_16 1
#define LV_FONT_MONTSERRAT_18 1
#define LV_FONT_MONTSERRAT_20 1
#define LV_FONT_MONTSERRAT_22 1
#define LV_FONT_MONTSERRAT_24 1
#define LV_FONT_MONTSERRAT_26 1
#define LV_FONT_MONTSERRAT_28 1
#define LV_FONT_MONTSERRAT_30 1
#define LV_FONT_MONTSERRAT_32 1
#define LV_FONT_MONTSERRAT_34 1
#define LV_FONT_MONTSERRAT_36 1
#define LV_FONT_FMT_TXT_LARGE 1
#define LV_USE_FONT_COMPRESSED 1
#define LV_FONT_DEFAULT &lv_font_montserrat_14
#define LV_TXT_ENC_UTF8 1
#define LV_TXT_BREAK_CHARS " ,.;:-_)]}"
#define LV_TXT_LINE_BREAK_LONG_LEN 12
#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3
#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 3
#define LV_TXT_COLOR_CMD "#"
#define LV_USE_INDEV_SCROLLBAR 1
#define LV_USE_INDEV_BUTTON 1
#define LV_USE_INDEV_KEYPAD 1
#define LV_USE_INDEV_ENCODER 1
#define LV_USE_GROUP 1
#define LV_USE_ANIM 1
#define LV_ANIM_HOLD_COUNT 1
#define LV_GRADIENT_MAX_STOPS 2
#endif // LV_CONF_H

145
lv_conf.h Normal file
View file

@ -0,0 +1,145 @@
/**
* LVGL Configuration for Bitcoin Dashboard
* Target: Elecrow 7-inch HMI Display (800x480)
*/
#ifndef LV_CONF_H
#define LV_CONF_H
#include <stdint.h>
#define LV_COLOR_DEPTH 16
#define LV_COLOR_16_SWAP 0
#define LV_HOR_RES_MAX 800
#define LV_VER_RES_MAX 480
#define LV_DPI_DEF 100
#define LV_DISP_DEF_REFR_PERIOD 16
#define LV_TICK_CUSTOM 1
#define LV_TICK_CUSTOM_INCLUDE "Arduino.h"
#define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis())
#define LV_MEM_CUSTOM 1
#define LV_MEM_CUSTOM_INCLUDE "Arduino.h"
#define LV_MEM_CUSTOM_ALLOC malloc
#define LV_MEM_CUSTOM_FREE free
#define LV_MEM_SIZE (64 * 1024U)
#define LV_MEM_ADR 0
#define LV_DRAW_CPU_ARM_ALIGN 4
#define LV_USE_DRAW_MASKS 1
#define LV_USE_DRAW_SW 1
#define LV_DRAW_SW_DRAW_UNIT_CNT 2
#define LV_USE_DRAW_SW_COMPLEX_GRADIENTS 1
#define LV_USE_DRAW_SW_SHADOW 1
#define LV_USE_DRAW_SW_BLUR 1
#define LV_USE_DRAW_SW_ARGB_TO_RGB565 1
#define LV_USE_ASSERT_NULL 1
#define LV_USE_ASSERT_MALLOC 1
#define LV_USE_MSG 1
#define LV_USE_FS_STDIO 0
#define LV_USE_FS_FATFS 0
#define LV_USE_FS_LITTLEFS 0
#define LV_USE_LODEPNG 0
#define LV_USE_LIBPNG 0
#define LV_USE_BMP 0
#define LV_USE_RLE 0
#define LV_USE_QRCODE 0
#define LV_USE_BARCODE 0
#define LV_USE_TJPGD 0
#define LV_USE_GIF 0
#define LV_USE_FLEX 1
#define LV_USE_GRID 1
#define LV_USE_SNAPSHOT 1
#define LV_USE_SYSMON 0
#define LV_USE_PERF_MONITOR 0
#define LV_USE_MEM_MONITOR 0
#define LV_THEME_DEFAULT_DARK 0
#define LV_THEME_DEFAULT_GROW 1
#define LV_USE_THEME_DEFAULT 1
#define LV_USE_THEME_BASIC 1
#define LV_USE_THEME_MONO 1
#define LV_USE_ARC 1
#define LV_USE_BAR 1
#define LV_USE_BTN 1
#define LV_USE_BTNMATRIX 1
#define LV_USE_CALENDAR 1
#define LV_USE_CANVAS 1
#define LV_USE_CHART 1
#define LV_USE_CHECKBOX 1
#define LV_USE_DROPDOWN 1
#define LV_USE_IMG 1
#define LV_USE_IMGBTN 1
#define LV_USE_KEYBOARD 1
#define LV_USE_LABEL 1
#define LV_LABEL_TEXT_SELECTION 1
#define LV_LABEL_LONG_TXT_HINT 1
#define LV_USE_LED 1
#define LV_USE_LINE 1
#define LV_USE_LIST 1
#define LV_USE_MENU 1
#define LV_USE_METER 1
#define LV_USE_MSGBOX 1
#define LV_USE_ROLLER 1
#define LV_USE_SCALE 1
#define LV_USE_SLIDER 1
#define LV_USE_SPAN 1
#define LV_USE_SPINBOX 1
#define LV_USE_SPINNER 1
#define LV_USE_SWITCH 1
#define LV_USE_TABVIEW 1
#define LV_USE_TABLE 1
#define LV_USE_TEXTAREA 1
#define LV_USE_TILEVIEW 1
#define LV_USE_WIN 1
#define LV_FONT_MONTSERRAT_12 1
#define LV_FONT_MONTSERRAT_14 1
#define LV_FONT_MONTSERRAT_16 1
#define LV_FONT_MONTSERRAT_18 1
#define LV_FONT_MONTSERRAT_20 1
#define LV_FONT_MONTSERRAT_22 1
#define LV_FONT_MONTSERRAT_24 1
#define LV_FONT_MONTSERRAT_26 1
#define LV_FONT_MONTSERRAT_28 1
#define LV_FONT_MONTSERRAT_30 1
#define LV_FONT_MONTSERRAT_32 1
#define LV_FONT_MONTSERRAT_34 1
#define LV_FONT_MONTSERRAT_36 1
#define LV_FONT_FMT_TXT_LARGE 1
#define LV_USE_FONT_COMPRESSED 1
#define LV_FONT_DEFAULT &lv_font_montserrat_14
#define LV_TXT_ENC_UTF8 1
#define LV_TXT_BREAK_CHARS " ,.;:-_)]}"
#define LV_TXT_LINE_BREAK_LONG_LEN 12
#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3
#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 3
#define LV_TXT_COLOR_CMD "#"
#define LV_USE_INDEV_SCROLLBAR 1
#define LV_USE_INDEV_BUTTON 1
#define LV_USE_INDEV_KEYPAD 1
#define LV_USE_INDEV_ENCODER 1
#define LV_USE_GROUP 1
#define LV_USE_ANIM 1
#define LV_ANIM_HOLD_COUNT 1
#define LV_GRADIENT_MAX_STOPS 2
#endif // LV_CONF_H

30
platformio.ini Normal file
View file

@ -0,0 +1,30 @@
; PlatformIO Project Configuration File
; Bitcoin Dashboard for Elecrow 7-inch HMI Display
; Based on working Arduino example
[env:elecrow_7inch_hmi]
platform = espressif32@6.8.1
board = esp32-s3-devkitc-1
framework = arduino
; Libraries
lib_deps =
lovyan03/LovyanGFX@^1.1.8
monitor_speed = 115200
; Critical settings for the N4R8 module (from working example)
board_upload.flash_size = 4MB
board_build.arduino.memory_type = qio_opi
board_build.f_flash = 80000000L
board_build.flash_mode = qio
; Use Huge APP partition (3MB No OTA/1MB SPIFFS)
board_build.partitions = huge_app.csv
; Required build flags for S3 display stability
build_flags =
-DARDUINO_USB_MODE=1
-DARDUINO_USB_CDC_ON_BOOT=1
-DBOARD_HAS_PSRAM
-mfix-esp32-psram-cache-issue

145
src/lv_conf.h Normal file
View file

@ -0,0 +1,145 @@
/**
* LVGL Configuration for Bitcoin Dashboard
* Target: Elecrow 7-inch HMI Display (800x480)
*/
#ifndef LV_CONF_H
#define LV_CONF_H
#include <stdint.h>
#define LV_COLOR_DEPTH 16
#define LV_COLOR_16_SWAP 0
#define LV_HOR_RES_MAX 800
#define LV_VER_RES_MAX 480
#define LV_DPI_DEF 100
#define LV_DISP_DEF_REFR_PERIOD 16
#define LV_TICK_CUSTOM 1
#define LV_TICK_CUSTOM_INCLUDE "Arduino.h"
#define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis())
#define LV_MEM_CUSTOM 1
#define LV_MEM_CUSTOM_INCLUDE "Arduino.h"
#define LV_MEM_CUSTOM_ALLOC malloc
#define LV_MEM_CUSTOM_FREE free
#define LV_MEM_SIZE (64 * 1024U)
#define LV_MEM_ADR 0
#define LV_DRAW_CPU_ARM_ALIGN 4
#define LV_USE_DRAW_MASKS 1
#define LV_USE_DRAW_SW 1
#define LV_DRAW_SW_DRAW_UNIT_CNT 2
#define LV_USE_DRAW_SW_COMPLEX_GRADIENTS 1
#define LV_USE_DRAW_SW_SHADOW 1
#define LV_USE_DRAW_SW_BLUR 1
#define LV_USE_DRAW_SW_ARGB_TO_RGB565 1
#define LV_USE_ASSERT_NULL 1
#define LV_USE_ASSERT_MALLOC 1
#define LV_USE_MSG 1
#define LV_USE_FS_STDIO 0
#define LV_USE_FS_FATFS 0
#define LV_USE_FS_LITTLEFS 0
#define LV_USE_LODEPNG 0
#define LV_USE_LIBPNG 0
#define LV_USE_BMP 0
#define LV_USE_RLE 0
#define LV_USE_QRCODE 0
#define LV_USE_BARCODE 0
#define LV_USE_TJPGD 0
#define LV_USE_GIF 0
#define LV_USE_FLEX 1
#define LV_USE_GRID 1
#define LV_USE_SNAPSHOT 1
#define LV_USE_SYSMON 0
#define LV_USE_PERF_MONITOR 0
#define LV_USE_MEM_MONITOR 0
#define LV_THEME_DEFAULT_DARK 0
#define LV_THEME_DEFAULT_GROW 1
#define LV_USE_THEME_DEFAULT 1
#define LV_USE_THEME_BASIC 1
#define LV_USE_THEME_MONO 1
#define LV_USE_ARC 1
#define LV_USE_BAR 1
#define LV_USE_BTN 1
#define LV_USE_BTNMATRIX 1
#define LV_USE_CALENDAR 1
#define LV_USE_CANVAS 1
#define LV_USE_CHART 1
#define LV_USE_CHECKBOX 1
#define LV_USE_DROPDOWN 1
#define LV_USE_IMG 1
#define LV_USE_IMGBTN 1
#define LV_USE_KEYBOARD 1
#define LV_USE_LABEL 1
#define LV_LABEL_TEXT_SELECTION 1
#define LV_LABEL_LONG_TXT_HINT 1
#define LV_USE_LED 1
#define LV_USE_LINE 1
#define LV_USE_LIST 1
#define LV_USE_MENU 1
#define LV_USE_METER 1
#define LV_USE_MSGBOX 1
#define LV_USE_ROLLER 1
#define LV_USE_SCALE 1
#define LV_USE_SLIDER 1
#define LV_USE_SPAN 1
#define LV_USE_SPINBOX 1
#define LV_USE_SPINNER 1
#define LV_USE_SWITCH 1
#define LV_USE_TABVIEW 1
#define LV_USE_TABLE 1
#define LV_USE_TEXTAREA 1
#define LV_USE_TILEVIEW 1
#define LV_USE_WIN 1
#define LV_FONT_MONTSERRAT_12 1
#define LV_FONT_MONTSERRAT_14 1
#define LV_FONT_MONTSERRAT_16 1
#define LV_FONT_MONTSERRAT_18 1
#define LV_FONT_MONTSERRAT_20 1
#define LV_FONT_MONTSERRAT_22 1
#define LV_FONT_MONTSERRAT_24 1
#define LV_FONT_MONTSERRAT_26 1
#define LV_FONT_MONTSERRAT_28 1
#define LV_FONT_MONTSERRAT_30 1
#define LV_FONT_MONTSERRAT_32 1
#define LV_FONT_MONTSERRAT_34 1
#define LV_FONT_MONTSERRAT_36 1
#define LV_FONT_FMT_TXT_LARGE 1
#define LV_USE_FONT_COMPRESSED 1
#define LV_FONT_DEFAULT &lv_font_montserrat_14
#define LV_TXT_ENC_UTF8 1
#define LV_TXT_BREAK_CHARS " ,.;:-_)]}"
#define LV_TXT_LINE_BREAK_LONG_LEN 12
#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3
#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 3
#define LV_TXT_COLOR_CMD "#"
#define LV_USE_INDEV_SCROLLBAR 1
#define LV_USE_INDEV_BUTTON 1
#define LV_USE_INDEV_KEYPAD 1
#define LV_USE_INDEV_ENCODER 1
#define LV_USE_GROUP 1
#define LV_USE_ANIM 1
#define LV_ANIM_HOLD_COUNT 1
#define LV_GRADIENT_MAX_STOPS 2
#endif // LV_CONF_H

2251
src/main.cpp Normal file

File diff suppressed because it is too large Load diff

132
src/mqtt_module.cpp Normal file
View file

@ -0,0 +1,132 @@
/**
* MQTT Module Implementation
* Handles connection to MQTT broker and price updates
*/
#include "mqtt_module.h"
MQTTModule::MQTTModule()
: _port(1883), _lastReconnectAttempt(0), _initialized(false) {
}
void MQTTModule::begin(const char* server, int port, const char* user, const char* pass) {
_server = String(server);
_port = port;
_user = String(user);
_pass = String(pass);
_wifiClient.setInsecure();
_mqttClient.setClient(_wifiClient);
_mqttClient.setBufferSize(MQTT_MAX_PACKET_SIZE);
_mqttClient.setCallback([this](char* t, byte* p, unsigned int l) {
this->_callback(t, p, l);
});
_mqttClient.setServer(_server.c_str(), _port);
_initialized = true;
Serial.printf("[MQTT] Configured for %s:%d\n", _server.c_str(), _port);
}
void MQTTModule::setTopic(const char* topic) {
_topic = String(topic);
Serial.printf("[MQTT] Topic set to: %s\n", _topic.c_str());
}
void MQTTModule::_callback(char* topic, byte* payload, unsigned int length) {
char buffer[MQTT_MAX_PACKET_SIZE];
if (length >= MQTT_MAX_PACKET_SIZE) {
length = MQTT_MAX_PACKET_SIZE - 1;
}
memcpy(buffer, payload, length);
buffer[length] = '\0';
Serial.printf("[MQTT] Received: %s\n", buffer);
_parsePriceData(buffer);
}
void MQTTModule::_parsePriceData(const char* json) {
JsonDocument doc;
DeserializationError error = deserializeJson(doc, json);
if (error) {
Serial.printf("[MQTT] JSON parse error: %s\n", error.c_str());
return;
}
bool updated = false;
if (doc.containsKey("btc")) {
btcPrice = doc["btc"].as<double>();
Serial.printf("[MQTT] BTC: $%.2f\n", btcPrice);
updated = true;
}
if (doc.containsKey("gold")) {
goldPrice = doc["gold"].as<double>();
Serial.printf("[MQTT] Gold: $%.2f\n", goldPrice);
updated = true;
}
if (doc.containsKey("silver")) {
silverPrice = doc["silver"].as<double>();
Serial.printf("[MQTT] Silver: $%.2f\n", silverPrice);
updated = true;
}
if (updated) {
needsRefresh = true;
Serial.println("[MQTT] Triggering screen refresh");
}
}
void MQTTModule::update() {
if (!_initialized) return;
if (!_mqttClient.connected()) {
unsigned long now = millis();
if (now - _lastReconnectAttempt > 5000) {
_lastReconnectAttempt = now;
reconnect();
}
} else {
_mqttClient.loop();
}
}
bool MQTTModule::isConnected() {
return _mqttClient.connected();
}
void MQTTModule::reconnect() {
if (WiFi.status() != WL_CONNECTED) {
Serial.println("[MQTT] WiFi not connected, skipping reconnect");
return;
}
Serial.print("[MQTT] Connecting...");
String clientId = "esp32-financial-" + String((uint32_t)ESP.getEfuseMac(), HEX);
if (_mqttClient.connect(clientId.c_str(), _user.c_str(), _pass.c_str())) {
Serial.println(" connected!");
if (_topic.length() > 0) {
if (_mqttClient.subscribe(_topic.c_str())) {
Serial.printf("[MQTT] Subscribed to: %s\n", _topic.c_str());
} else {
Serial.println("[MQTT] Subscribe failed");
}
}
} else {
Serial.printf(" failed (rc=%d)\n", _mqttClient.state());
}
}
void MQTTModule::disconnect() {
if (_mqttClient.connected()) {
_mqttClient.disconnect();
Serial.println("[MQTT] Disconnected");
}
}

46
src/mqtt_module.h Normal file
View file

@ -0,0 +1,46 @@
/**
* MQTT Module for Financial Dashboard
* Handles connection to MQTT broker and price updates
* Additive to existing firmware - uses needsRefresh flag
*/
#ifndef MQTT_MODULE_H
#define MQTT_MODULE_H
#include <Arduino.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <WiFiClientSecure.h>
#include <ArduinoJson.h>
#define MQTT_MAX_PACKET_SIZE 2048
extern bool needsRefresh;
extern double btcPrice, goldPrice, silverPrice;
class MQTTModule {
public:
MQTTModule();
void begin(const char* server, int port, const char* user, const char* pass);
void setTopic(const char* topic);
void update();
bool isConnected();
void reconnect();
void disconnect();
private:
WiFiClientSecure _wifiClient;
PubSubClient _mqttClient;
String _server;
int _port;
String _user;
String _pass;
String _topic;
unsigned long _lastReconnectAttempt;
bool _initialized;
void _callback(char* topic, byte* payload, unsigned int length);
void _parsePriceData(const char* json);
};
#endif