Skip to content

Repository files navigation

YD-ESP32-S3 Sub2API usage display

Sub2API Usage Display

Sub2API Usage Display demo

Purpose

This firmware runs on a YD-ESP32-S3 and shows the Sub2API account's server-defined today_actual_cost, today_tokens, and tpm on a 128x32 SSD1306 OLED. Network, authentication, SNTP, and polling work runs in a FreeRTOS worker so the display loop remains responsive.

Wiring

Use a 3.3 V SSD1306 I2C OLED at address 0x3C.

OLED YD-ESP32-S3
VCC 3V3
GND GND
SDA GPIO5
SCL GPIO6

The I2C bus runs at 100 kHz. At startup, and every two seconds while the OLED is absent, Serial reports the I2C addresses found by the scan or I2C display missing.

Configuration

Create the ignored local configuration from config.example.yaml:

wifi:
  ssid: "replace-with-wifi-ssid"
  password: "replace-with-wifi-password"

service:
  login_endpoint: "https://sub2api.example.com/api/v1/auth/login"
  refresh_endpoint: "https://sub2api.example.com/api/v1/auth/refresh"
  usage_endpoint: "https://sub2api.example.com/api/v1/usage/dashboard/stats"
  username: "replace-with-login-email"
  password: "replace-with-login-password"

polling:
  interval_seconds: 60
  request_timeout_ms: 10000

Replace the sub2api.example.com placeholder with your Sub2API host and save the file as config.local.yaml. All endpoints must be absolute HTTPS URLs, the usage endpoint must have the exact path shown above with no query string, the polling interval must be at least 2 seconds, and the timeout must be from 1,000 through 60,000 milliseconds. service.username is sent in the login request's email field.

YAML is validated only during the build. The firmware contains no runtime YAML parser, and a missing or invalid field stops the build without printing secret values.

Security

The Wi-Fi and service credentials are compiled into the firmware. Rotating access and refresh tokens are stored together in ESP32 NVS. The generated build artifacts and a board in another person's possession can therefore expose credentials or tokens unless ESP32 flash encryption is separately configured and enabled. Keep config.local.yaml, .pio/, firmware images, and physical boards protected.

HTTPS uses hostname and certificate-chain verification with the committed DigiCert Global Root G2 certificate. The transport does not use insecure TLS. If the service changes to a chain outside that root, update the trust anchor and firmware.

Build And Upload

Install the pinned tools and run the automated checks with the nonsecret example configuration:

rtk uv sync
APP_CONFIG_FILE=config.example.yaml rtk uv run pytest -q
APP_CONFIG_FILE=config.example.yaml rtk uv run pio test -e native

Build and upload with the ignored real configuration, then open Serial at 115200 baud:

make build
make upload
make monitor

The Makefile defaults to config.local.yaml, the yd_esp32s3 environment, /dev/cu.usbmodem21201, and 115200 baud. Override any value on the command line when needed:

make upload PORT=/dev/cu.usbmodemXXXX CONFIG=config.other.yaml

The YD-ESP32-S3 native USB JTAG/Serial interface is built with USB CDC enabled, so the same port is used for upload and monitor. Replace the example port if the host assigns a different device name. DTR and RTS are held inactive while monitoring so opening the terminal does not repeatedly reset the native USB interface.

Serial output is deliberately limited to boot/I2C status and a nonsecret worker-start failure category. It does not print configuration, endpoint URLs, request bodies, authorization headers, credentials, or tokens.

Display And Recovery

After a successful fetch, the OLED shows the cost in a large font on the left. The right side shows daily tokens on the first row and TPM on the second, both right-aligned in the small font and without labels. Daily tokens use truncated integer K, M, or B notation. TPM uses truncated integer K or M notation. A one-pixel vertical line is centered in the unused pixels between the cost and right column; no space characters are used for layout.

If the large cost and right column do not fit together, only the cost is shown. The stale marker is drawn independently and does not change usage content coordinates.

Before the first reading, the OLED shows the active WIFI, TIME, AUTH, or FETCH phase. A failure is reduced to a nonsecret category:

Display Meaning
WIFI ERR Wi-Fi connection was lost
TIME ERR wall-clock synchronization failed
AUTH ERR the service rejected authentication
TLS ERR certificate or TLS setup failed
NET ERR DNS, timeout, or other network transport failure
PARSE ERR the response could not be parsed
API ERR the API returned an unsuccessful response envelope
SIZE ERR the response exceeded the bounded buffer
HTTP nnn HTTP or rate-limit response with status nnn
HTTP ERR HTTP failure without a usable status

After the first successful fetch, the display always retains the last cost and token reading; a 2x2-pixel white dot in the upper-right marks it stale until another fetch succeeds. Wi-Fi reconnect, authentication, HTTP, TLS, and parsing work never blocks the Arduino display loop.

Transient failures use exponential retry delays from 5 seconds up to 5 minutes. A rate limit honors a valid Retry-After value. A usage 401 gets one bounded refresh/login recovery path and one usage retry; repeated failures enter backoff. Successful fetches clear the stale marker, reset backoff, and resume the configured polling interval.

The API server's configured timezone defines "today". The firmware sends no timezone query parameter and does not recalculate daily totals locally.

About

ESP32 firmware that displays Sub2API daily cost, token usage, and TPM on a 128x32 SSD1306 OLED.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Contributors

Languages