Initial commit: Claude Usage Tracker for Panlee SC01 Plus
Physical desk monitor that displays Claude Code usage limits (5-hour session and 7-day weekly utilization) on an ESP32-S3 touchscreen via USB serial. Firmware: LVGL 9 dashboard with LovyanGFX on SC01 Plus, Anthropic brand colors and custom fonts (Tiempos, Styrene B, DejaVu Sans Mono), Claude spinner animation with rotating status words. Daemon: Pure bash script that reads the Claude Code OAuth token, makes a minimal Haiku API call, extracts usage from rate-limit response headers, and sends JSON to the ESP32 over serial. Uses inotifywait for instant USB plug/unplug detection. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
commit
2611c70881
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include <Arduino.h>
|
||||
|
||||
struct UsageData {
|
||||
float session_pct; // 5-hour window utilization (0-100)
|
||||
int session_reset_mins; // minutes until session resets
|
||||
float weekly_pct; // 7-day window utilization (0-100)
|
||||
int weekly_reset_mins; // minutes until weekly resets
|
||||
char status[16]; // "allowed" or "limited"
|
||||
bool ok; // data parse succeeded
|
||||
bool valid; // false until first successful parse
|
||||
};
|
||||
@@ -0,0 +1,93 @@
|
||||
#pragma once
|
||||
|
||||
#define LGFX_USE_V1
|
||||
#include <LovyanGFX.hpp>
|
||||
|
||||
class LGFX : public lgfx::LGFX_Device {
|
||||
// 8-bit parallel bus for ST7796 display
|
||||
lgfx::Bus_Parallel8 _bus_instance;
|
||||
// ST7796 display panel
|
||||
lgfx::Panel_ST7796 _panel_instance;
|
||||
// PWM backlight
|
||||
lgfx::Light_PWM _light_instance;
|
||||
// FT6336U capacitive touch (FT5x06 compatible)
|
||||
lgfx::Touch_FT5x06 _touch_instance;
|
||||
|
||||
public:
|
||||
LGFX(void) {
|
||||
// ---- Bus configuration ----
|
||||
{
|
||||
auto cfg = _bus_instance.config();
|
||||
cfg.port = 0;
|
||||
cfg.freq_write = 40000000; // 40 MHz
|
||||
cfg.pin_wr = 47;
|
||||
cfg.pin_rd = -1; // not connected
|
||||
cfg.pin_rs = 0; // DC (data/command)
|
||||
cfg.pin_d0 = 9;
|
||||
cfg.pin_d1 = 46;
|
||||
cfg.pin_d2 = 3;
|
||||
cfg.pin_d3 = 8;
|
||||
cfg.pin_d4 = 18;
|
||||
cfg.pin_d5 = 17;
|
||||
cfg.pin_d6 = 16;
|
||||
cfg.pin_d7 = 15;
|
||||
_bus_instance.config(cfg);
|
||||
_panel_instance.setBus(&_bus_instance);
|
||||
}
|
||||
|
||||
// ---- Panel configuration ----
|
||||
{
|
||||
auto cfg = _panel_instance.config();
|
||||
cfg.pin_cs = -1; // directly driven
|
||||
cfg.pin_rst = 4;
|
||||
cfg.pin_busy = -1;
|
||||
cfg.memory_width = 320;
|
||||
cfg.memory_height = 480;
|
||||
cfg.panel_width = 320;
|
||||
cfg.panel_height = 480;
|
||||
cfg.offset_x = 0;
|
||||
cfg.offset_y = 0;
|
||||
cfg.offset_rotation = 0;
|
||||
cfg.dummy_read_pixel = 8;
|
||||
cfg.dummy_read_bits = 1;
|
||||
cfg.readable = false;
|
||||
cfg.invert = true;
|
||||
cfg.rgb_order = false;
|
||||
cfg.dlen_16bit = false;
|
||||
cfg.bus_shared = true;
|
||||
_panel_instance.config(cfg);
|
||||
}
|
||||
|
||||
// ---- Backlight configuration ----
|
||||
{
|
||||
auto cfg = _light_instance.config();
|
||||
cfg.pin_bl = 45;
|
||||
cfg.invert = false;
|
||||
cfg.freq = 44100;
|
||||
cfg.pwm_channel = 7;
|
||||
_light_instance.config(cfg);
|
||||
_panel_instance.setLight(&_light_instance);
|
||||
}
|
||||
|
||||
// ---- Touch configuration ----
|
||||
{
|
||||
auto cfg = _touch_instance.config();
|
||||
cfg.x_min = 0;
|
||||
cfg.x_max = 319;
|
||||
cfg.y_min = 0;
|
||||
cfg.y_max = 479;
|
||||
cfg.pin_int = 7;
|
||||
cfg.bus_shared = false;
|
||||
cfg.offset_rotation = 0;
|
||||
cfg.i2c_port = 1;
|
||||
cfg.i2c_addr = 0x38;
|
||||
cfg.pin_sda = 6;
|
||||
cfg.pin_scl = 5;
|
||||
cfg.freq = 400000;
|
||||
_touch_instance.config(cfg);
|
||||
_panel_instance.setTouch(&_touch_instance);
|
||||
}
|
||||
|
||||
setPanel(&_panel_instance);
|
||||
}
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,152 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#define LOGO_WIDTH 48
|
||||
#define LOGO_HEIGHT 48
|
||||
|
||||
static const uint16_t logo_data[2304] = {
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0xDBAA,
|
||||
0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA,
|
||||
0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0xDBAA, 0xDBAA, 0xDBAA, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2,
|
||||
};
|
||||
@@ -0,0 +1,126 @@
|
||||
#include <Arduino.h>
|
||||
#include <lvgl.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include "display_cfg.h"
|
||||
#include "data.h"
|
||||
#include "ui.h"
|
||||
|
||||
static LGFX lcd;
|
||||
static UsageData usage = {};
|
||||
|
||||
// LVGL draw buffers
|
||||
#define BUF_LINES 40
|
||||
static uint16_t buf1[480 * BUF_LINES];
|
||||
static uint16_t buf2[480 * BUF_LINES];
|
||||
|
||||
// Serial line buffer
|
||||
#define SERIAL_BUF_SIZE 512
|
||||
static char serial_buf[SERIAL_BUF_SIZE];
|
||||
static int serial_pos = 0;
|
||||
|
||||
// LVGL tick callback
|
||||
static uint32_t my_tick(void) {
|
||||
return millis();
|
||||
}
|
||||
|
||||
// LVGL flush callback
|
||||
static void my_flush_cb(lv_display_t* disp, const lv_area_t* area, uint8_t* px_map) {
|
||||
uint32_t w = (area->x2 - area->x1 + 1);
|
||||
uint32_t h = (area->y2 - area->y1 + 1);
|
||||
lcd.startWrite();
|
||||
lcd.setAddrWindow(area->x1, area->y1, w, h);
|
||||
lcd.writePixels((uint16_t*)px_map, w * h, true);
|
||||
lcd.endWrite();
|
||||
lv_display_flush_ready(disp);
|
||||
}
|
||||
|
||||
// LVGL touch callback
|
||||
static void my_touch_cb(lv_indev_t* indev, lv_indev_data_t* data) {
|
||||
uint16_t x, y;
|
||||
if (lcd.getTouch(&x, &y)) {
|
||||
data->point.x = x;
|
||||
data->point.y = y;
|
||||
data->state = LV_INDEV_STATE_PRESSED;
|
||||
} else {
|
||||
data->state = LV_INDEV_STATE_RELEASED;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse a JSON line into UsageData
|
||||
static bool parse_json(const char* json, UsageData* out) {
|
||||
JsonDocument doc;
|
||||
DeserializationError err = deserializeJson(doc, json);
|
||||
if (err) {
|
||||
Serial.printf("JSON parse error: %s\n", err.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
out->session_pct = doc["s"] | 0.0f;
|
||||
out->session_reset_mins = doc["sr"] | -1;
|
||||
out->weekly_pct = doc["w"] | 0.0f;
|
||||
out->weekly_reset_mins = doc["wr"] | -1;
|
||||
strlcpy(out->status, doc["st"] | "unknown", sizeof(out->status));
|
||||
out->ok = doc["ok"] | false;
|
||||
out->valid = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Read serial data, returns true when a complete line is ready
|
||||
static bool read_serial_line() {
|
||||
while (Serial.available()) {
|
||||
char c = Serial.read();
|
||||
if (c == '\n') {
|
||||
serial_buf[serial_pos] = '\0';
|
||||
serial_pos = 0;
|
||||
return true;
|
||||
}
|
||||
if (serial_pos < SERIAL_BUF_SIZE - 1) {
|
||||
serial_buf[serial_pos++] = c;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(300);
|
||||
Serial.println("{\"ready\":true}");
|
||||
|
||||
// Init display
|
||||
lcd.init();
|
||||
lcd.setRotation(1);
|
||||
lcd.setBrightness(200);
|
||||
lcd.fillScreen(TFT_BLACK);
|
||||
|
||||
// Init LVGL
|
||||
lv_init();
|
||||
lv_tick_set_cb(my_tick);
|
||||
|
||||
lv_display_t* disp = lv_display_create(480, 320);
|
||||
lv_display_set_color_format(disp, LV_COLOR_FORMAT_RGB565);
|
||||
lv_display_set_flush_cb(disp, my_flush_cb);
|
||||
lv_display_set_buffers(disp, buf1, buf2, sizeof(buf1), LV_DISPLAY_RENDER_MODE_PARTIAL);
|
||||
|
||||
lv_indev_t* indev = lv_indev_create();
|
||||
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
|
||||
lv_indev_set_read_cb(indev, my_touch_cb);
|
||||
|
||||
// Build dashboard
|
||||
ui_init();
|
||||
|
||||
Serial.println("Dashboard ready, waiting for data on serial...");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
lv_timer_handler();
|
||||
ui_tick_anim();
|
||||
|
||||
if (read_serial_line()) {
|
||||
if (parse_json(serial_buf, &usage)) {
|
||||
ui_update(&usage);
|
||||
Serial.println("{\"ack\":true}");
|
||||
}
|
||||
}
|
||||
|
||||
delay(5);
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
#include "ui.h"
|
||||
#include <lvgl.h>
|
||||
#include "logo.h"
|
||||
|
||||
// Custom fonts
|
||||
LV_FONT_DECLARE(font_tiempos_34);
|
||||
LV_FONT_DECLARE(font_styrene_28);
|
||||
LV_FONT_DECLARE(font_styrene_16);
|
||||
LV_FONT_DECLARE(font_styrene_14);
|
||||
LV_FONT_DECLARE(font_styrene_12);
|
||||
LV_FONT_DECLARE(font_mono_18);
|
||||
|
||||
// Anthropic brand palette
|
||||
#define COL_BG lv_color_hex(0x141413)
|
||||
#define COL_PANEL lv_color_hex(0x1f1f1e)
|
||||
#define COL_TEXT lv_color_hex(0xfaf9f5)
|
||||
#define COL_DIM lv_color_hex(0xb0aea5)
|
||||
#define COL_ACCENT lv_color_hex(0xd97757)
|
||||
#define COL_GREEN lv_color_hex(0x788c5d)
|
||||
#define COL_AMBER lv_color_hex(0xd97757)
|
||||
#define COL_RED lv_color_hex(0xc0392b)
|
||||
#define COL_BAR_BG lv_color_hex(0x2a2a28)
|
||||
|
||||
// Widget handles
|
||||
static lv_obj_t* lbl_title;
|
||||
|
||||
static lv_obj_t* bar_session;
|
||||
static lv_obj_t* lbl_session_pct;
|
||||
static lv_obj_t* lbl_session_label;
|
||||
static lv_obj_t* lbl_session_reset;
|
||||
|
||||
static lv_obj_t* bar_weekly;
|
||||
static lv_obj_t* lbl_weekly_pct;
|
||||
static lv_obj_t* lbl_weekly_label;
|
||||
static lv_obj_t* lbl_weekly_reset;
|
||||
|
||||
static lv_obj_t* lbl_anim;
|
||||
|
||||
// Logo image descriptor for LVGL
|
||||
static lv_image_dsc_t logo_dsc;
|
||||
|
||||
// Animation state
|
||||
static uint32_t anim_last_ms = 0;
|
||||
static uint8_t anim_spinner_idx = 0;
|
||||
static uint8_t anim_msg_idx = 0;
|
||||
static uint32_t anim_msg_start = 0;
|
||||
#define ANIM_SPIN_MS 120 // spinner frame speed
|
||||
#define ANIM_MSG_MS 4000 // how long each message stays
|
||||
|
||||
// Claude's spinner characters: · ✻ ✽ ✶ ✳ ✢
|
||||
// UTF-8 encoded
|
||||
static const char* const spinner_frames[] = {
|
||||
"\xC2\xB7", // · (U+00B7)
|
||||
"\xE2\x9C\xBB", // ✻ (U+273B)
|
||||
"\xE2\x9C\xBD", // ✽ (U+273D)
|
||||
"\xE2\x9C\xB6", // ✶ (U+2736)
|
||||
"\xE2\x9C\xB3", // ✳ (U+2733)
|
||||
"\xE2\x9C\xA2", // ✢ (U+2722)
|
||||
};
|
||||
#define SPINNER_COUNT 6
|
||||
|
||||
static const char* const anim_messages[] = {
|
||||
"Accomplishing", "Elucidating", "Perusing",
|
||||
"Actioning", "Enchanting", "Philosophising",
|
||||
"Actualizing", "Envisioning", "Pondering",
|
||||
"Baking", "Finagling", "Pontificating",
|
||||
"Booping", "Flibbertigibbeting", "Processing",
|
||||
"Brewing", "Forging", "Puttering",
|
||||
"Calculating", "Forming", "Puzzling",
|
||||
"Cerebrating", "Frolicking", "Reticulating",
|
||||
"Channelling", "Generating", "Ruminating",
|
||||
"Churning", "Germinating", "Scheming",
|
||||
"Clauding", "Hatching", "Schlepping",
|
||||
"Coalescing", "Herding", "Shimmying",
|
||||
"Cogitating", "Honking", "Shucking",
|
||||
"Combobulating", "Hustling", "Simmering",
|
||||
"Computing", "Ideating", "Smooshing",
|
||||
"Concocting", "Imagining", "Spelunking",
|
||||
"Conjuring", "Incubating", "Spinning",
|
||||
"Considering", "Inferring", "Stewing",
|
||||
"Contemplating", "Jiving", "Sussing",
|
||||
"Cooking", "Manifesting", "Synthesizing",
|
||||
"Crafting", "Marinating", "Thinking",
|
||||
"Creating", "Meandering", "Tinkering",
|
||||
"Crunching", "Moseying", "Transmuting",
|
||||
"Deciphering", "Mulling", "Unfurling",
|
||||
"Deliberating", "Mustering", "Unravelling",
|
||||
"Determining", "Musing", "Vibing",
|
||||
"Discombobulating", "Noodling", "Wandering",
|
||||
"Divining", "Percolating", "Whirring",
|
||||
"Doing", "Wibbling",
|
||||
"Effecting", "Wizarding",
|
||||
"Working", "Wrangling",
|
||||
};
|
||||
#define ANIM_MSG_COUNT (sizeof(anim_messages) / sizeof(anim_messages[0]))
|
||||
|
||||
static lv_color_t pct_color(float pct) {
|
||||
if (pct >= 80.0f) return COL_RED;
|
||||
if (pct >= 50.0f) return COL_AMBER;
|
||||
return COL_GREEN;
|
||||
}
|
||||
|
||||
static void format_reset_time(int mins, char* buf, size_t len) {
|
||||
if (mins < 0) {
|
||||
snprintf(buf, len, "---");
|
||||
} else if (mins < 60) {
|
||||
snprintf(buf, len, "Resets in %dm", mins);
|
||||
} else if (mins < 1440) {
|
||||
snprintf(buf, len, "Resets in %dh %dm", mins / 60, mins % 60);
|
||||
} else {
|
||||
snprintf(buf, len, "Resets in %dd %dh", mins / 1440, (mins % 1440) / 60);
|
||||
}
|
||||
}
|
||||
|
||||
static lv_obj_t* make_panel(lv_obj_t* parent, int x, int y, int w, int h) {
|
||||
lv_obj_t* panel = lv_obj_create(parent);
|
||||
lv_obj_set_pos(panel, x, y);
|
||||
lv_obj_set_size(panel, w, h);
|
||||
lv_obj_set_style_bg_color(panel, COL_PANEL, 0);
|
||||
lv_obj_set_style_bg_opa(panel, LV_OPA_COVER, 0);
|
||||
lv_obj_set_style_radius(panel, 8, 0);
|
||||
lv_obj_set_style_border_width(panel, 0, 0);
|
||||
lv_obj_set_style_pad_left(panel, 12, 0);
|
||||
lv_obj_set_style_pad_right(panel, 12, 0);
|
||||
lv_obj_set_style_pad_top(panel, 10, 0);
|
||||
lv_obj_set_style_pad_bottom(panel, 16, 0);
|
||||
lv_obj_clear_flag(panel, LV_OBJ_FLAG_SCROLLABLE);
|
||||
return panel;
|
||||
}
|
||||
|
||||
static lv_obj_t* make_bar(lv_obj_t* parent, int x, int y, int w, int h) {
|
||||
lv_obj_t* bar = lv_bar_create(parent);
|
||||
lv_obj_set_pos(bar, x, y);
|
||||
lv_obj_set_size(bar, w, h);
|
||||
lv_bar_set_range(bar, 0, 100);
|
||||
lv_bar_set_value(bar, 0, LV_ANIM_OFF);
|
||||
lv_obj_set_style_bg_color(bar, COL_BAR_BG, LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_opa(bar, LV_OPA_COVER, LV_PART_MAIN);
|
||||
lv_obj_set_style_radius(bar, 6, LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_color(bar, COL_GREEN, LV_PART_INDICATOR);
|
||||
lv_obj_set_style_bg_opa(bar, LV_OPA_COVER, LV_PART_INDICATOR);
|
||||
lv_obj_set_style_radius(bar, 6, LV_PART_INDICATOR);
|
||||
return bar;
|
||||
}
|
||||
|
||||
void ui_init(void) {
|
||||
lv_obj_t* scr = lv_screen_active();
|
||||
lv_obj_set_style_bg_color(scr, COL_BG, 0);
|
||||
lv_obj_set_style_bg_opa(scr, LV_OPA_COVER, 0);
|
||||
|
||||
// ---- Logo image ----
|
||||
logo_dsc.header.w = LOGO_WIDTH;
|
||||
logo_dsc.header.h = LOGO_HEIGHT;
|
||||
logo_dsc.header.cf = LV_COLOR_FORMAT_RGB565;
|
||||
logo_dsc.header.stride = LOGO_WIDTH * 2;
|
||||
logo_dsc.data = (const uint8_t*)logo_data;
|
||||
logo_dsc.data_size = LOGO_WIDTH * LOGO_HEIGHT * 2;
|
||||
|
||||
lv_obj_t* img = lv_image_create(scr);
|
||||
lv_image_set_src(img, &logo_dsc);
|
||||
lv_obj_set_pos(img, 10, 4);
|
||||
|
||||
// ---- Title (vertically centered to 48px logo) ----
|
||||
lbl_title = lv_label_create(scr);
|
||||
lv_label_set_text(lbl_title, "Claude Usage Tracker");
|
||||
lv_obj_set_style_text_font(lbl_title, &font_tiempos_34, 0);
|
||||
lv_obj_set_style_text_color(lbl_title, COL_TEXT, 0);
|
||||
lv_obj_set_pos(lbl_title, 66, 12);
|
||||
|
||||
// ---- Session panel ----
|
||||
// Layout: percentage -> bar -> "5-Hour Session ... Resets in ..." below
|
||||
lv_obj_t* p_session = make_panel(scr, 8, 56, 464, 100);
|
||||
|
||||
lbl_session_pct = lv_label_create(p_session);
|
||||
lv_label_set_text(lbl_session_pct, "---%");
|
||||
lv_obj_set_style_text_font(lbl_session_pct, &font_styrene_28, 0);
|
||||
lv_obj_set_style_text_color(lbl_session_pct, COL_TEXT, 0);
|
||||
lv_obj_set_pos(lbl_session_pct, 0, 0);
|
||||
|
||||
bar_session = make_bar(p_session, 0, 36, 440, 20);
|
||||
|
||||
lbl_session_label = lv_label_create(p_session);
|
||||
lv_label_set_text(lbl_session_label, "Current Session");
|
||||
lv_obj_set_style_text_font(lbl_session_label, &font_styrene_16, 0);
|
||||
lv_obj_set_style_text_color(lbl_session_label, COL_DIM, 0);
|
||||
lv_obj_set_pos(lbl_session_label, 0, 62);
|
||||
|
||||
lbl_session_reset = lv_label_create(p_session);
|
||||
lv_label_set_text(lbl_session_reset, "---");
|
||||
lv_obj_set_style_text_font(lbl_session_reset, &font_styrene_16, 0);
|
||||
lv_obj_set_style_text_color(lbl_session_reset, COL_DIM, 0);
|
||||
lv_obj_set_pos(lbl_session_reset, 440, 62);
|
||||
lv_obj_set_style_text_align(lbl_session_reset, LV_TEXT_ALIGN_RIGHT, 0);
|
||||
lv_obj_align(lbl_session_reset, LV_ALIGN_TOP_RIGHT, 0, 62);
|
||||
|
||||
// ---- Weekly panel ----
|
||||
lv_obj_t* p_weekly = make_panel(scr, 8, 166, 464, 100);
|
||||
|
||||
lbl_weekly_pct = lv_label_create(p_weekly);
|
||||
lv_label_set_text(lbl_weekly_pct, "---%");
|
||||
lv_obj_set_style_text_font(lbl_weekly_pct, &font_styrene_28, 0);
|
||||
lv_obj_set_style_text_color(lbl_weekly_pct, COL_TEXT, 0);
|
||||
lv_obj_set_pos(lbl_weekly_pct, 0, 0);
|
||||
|
||||
bar_weekly = make_bar(p_weekly, 0, 36, 440, 20);
|
||||
|
||||
lbl_weekly_label = lv_label_create(p_weekly);
|
||||
lv_label_set_text(lbl_weekly_label, "Current Week");
|
||||
lv_obj_set_style_text_font(lbl_weekly_label, &font_styrene_16, 0);
|
||||
lv_obj_set_style_text_color(lbl_weekly_label, COL_DIM, 0);
|
||||
lv_obj_set_pos(lbl_weekly_label, 0, 62);
|
||||
|
||||
lbl_weekly_reset = lv_label_create(p_weekly);
|
||||
lv_label_set_text(lbl_weekly_reset, "---");
|
||||
lv_obj_set_style_text_font(lbl_weekly_reset, &font_styrene_16, 0);
|
||||
lv_obj_set_style_text_color(lbl_weekly_reset, COL_DIM, 0);
|
||||
lv_obj_align(lbl_weekly_reset, LV_ALIGN_TOP_RIGHT, 0, 62);
|
||||
|
||||
// ---- Animation at bottom ----
|
||||
lbl_anim = lv_label_create(scr);
|
||||
lv_label_set_text(lbl_anim, "");
|
||||
lv_obj_set_style_text_font(lbl_anim, &font_mono_18, 0);
|
||||
lv_obj_set_style_text_color(lbl_anim, COL_ACCENT, 0);
|
||||
lv_obj_align(lbl_anim, LV_ALIGN_BOTTOM_MID, 0, -16);
|
||||
}
|
||||
|
||||
void ui_update(const UsageData* data) {
|
||||
if (!data->valid) return;
|
||||
|
||||
int s_pct = (int)(data->session_pct + 0.5f);
|
||||
lv_label_set_text_fmt(lbl_session_pct, "%d%%", s_pct);
|
||||
lv_bar_set_value(bar_session, s_pct, LV_ANIM_ON);
|
||||
lv_obj_set_style_bg_color(bar_session, pct_color(data->session_pct), LV_PART_INDICATOR);
|
||||
|
||||
char buf[48];
|
||||
format_reset_time(data->session_reset_mins, buf, sizeof(buf));
|
||||
lv_label_set_text(lbl_session_reset, buf);
|
||||
|
||||
int w_pct = (int)(data->weekly_pct + 0.5f);
|
||||
lv_label_set_text_fmt(lbl_weekly_pct, "%d%%", w_pct);
|
||||
lv_bar_set_value(bar_weekly, w_pct, LV_ANIM_ON);
|
||||
lv_obj_set_style_bg_color(bar_weekly, pct_color(data->weekly_pct), LV_PART_INDICATOR);
|
||||
|
||||
format_reset_time(data->weekly_reset_mins, buf, sizeof(buf));
|
||||
lv_label_set_text(lbl_weekly_reset, buf);
|
||||
}
|
||||
|
||||
void ui_tick_anim(void) {
|
||||
uint32_t now = lv_tick_get();
|
||||
|
||||
// Switch to next message
|
||||
if (now - anim_msg_start >= ANIM_MSG_MS) {
|
||||
anim_msg_idx = (anim_msg_idx + 1) % ANIM_MSG_COUNT;
|
||||
anim_msg_start = now;
|
||||
}
|
||||
|
||||
// Spin the spinner
|
||||
if (now - anim_last_ms >= ANIM_SPIN_MS) {
|
||||
anim_last_ms = now;
|
||||
anim_spinner_idx = (anim_spinner_idx + 1) % SPINNER_COUNT;
|
||||
|
||||
static char buf[80];
|
||||
snprintf(buf, sizeof(buf), "%s %s\xE2\x80\xA6",
|
||||
spinner_frames[anim_spinner_idx],
|
||||
anim_messages[anim_msg_idx]);
|
||||
lv_label_set_text(lbl_anim, buf);
|
||||
}
|
||||
}
|
||||
|
||||
void ui_set_status(const char* text) {
|
||||
(void)text;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
#include "data.h"
|
||||
|
||||
void ui_init(void);
|
||||
void ui_update(const UsageData* data);
|
||||
void ui_tick_anim(void);
|
||||
void ui_set_status(const char* text);
|
||||
Reference in New Issue
Block a user