Files

1 line
7.8 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"repo": "alexzhu2/aink", "files": {"README.md": {"c92b7b68f84ef7fe3de7c8a812c2ca05fb88217c": {"t": 1785595222.040851, "n": 6943, "h": "f2525d65349e1f84", "c": "<p align=\"center\">\n <img src=\"assets/logo-circuit-ink.png\" alt=\"AInk — Circuit Ink\" width=\"360\">\n</p>\n\n<p align=\"center\">\n <strong>A pocket e-paper computer on ESP32-S3</strong><br>\n 200×200 monochrome display · two-button UX · seven mini-apps · bilingual firmware\n</p>\n\n<p align=\"center\">\n <a href=\"README.md\">English</a> · <a href=\"README.zh-CN.md\">简体中文</a>\n</p>\n\n---\n\n## 1. Product overview\n\n**AInk** (*Circuit Ink*) is firmware for a minimalist handheld built around the **Seeed XIAO ESP32-S3 Sense** and a **Waveshare 1.54″** black-and-white e-paper panel. It targets users who want glanceable information and small interactive apps without a phone — and developers who want a complete, hackable reference for LVGL on constrained e-paper hardware.\n\n| Attribute | Specification |\n|-----------|----------------|\n| Display | 200×200 px, 1-bit, partial refresh |\n| Input | 2 buttons (A / B), optional serial simulation |\n| Connectivity | WiFi + captive portal provisioning |\n| On-device UI | LVGL 8.3, custom 1-bit flush pipeline |\n| Locale | English / 中文 (NVS-persisted) |\n| Apps | Clock, Weather, AI Vision, Answers, Stocks, Life, Settings |\n\n**Design principles**\n\n- **Calm UI** — tiered refresh (`FAST` / `NAV` / `QUALITY` / `FULL`) balances latency and ghosting.\n- **Home vs app** — launcher keeps a 20 px status bar; every app runs **full-screen** for maximum content area.\n- **Offline-first where it matters** — Answers and Life work without cloud keys; Weather/Stocks/Vision degrade gracefully.\n\n---\n\n## 2. System architecture\n\n```\n┌─────────────────────────────────────────────────────────┐\n│ Aink.ino — boot, WiFi portal, refresh scheduler, NTP │\n├─────────────────────────────────────────────────────────┤\n│ ui_nav / ui_home — paged 2×2 launcher, routing │\n│ ui_status_bar — date, WiFi, weather peek, battery │\n│ ui_* apps — Clock, Weather, Vision, Answers, … │\n├─────────────────────────────────────────────────────────┤\n│ ui_lvgl + epaper_canvas — LVGL 8.3 → 1-bit framebuffer │\n├─────────────────────────────────────────────────────────┤\n│ Services: weather, stock, vision, voice, camera, NVS │\n└─────────────────────────────────────────────────────────┘\n │ HTTPS / gzip (puff) │ EPD SPI\n ▼ ▼\n QWeather, OpenAI, MiMo, … Waveshare 1.54″ V2\n```\n\n---\n\n## 3. Applications\n\n| App | Capability |\n|-----|------------|\n| **Clock** | 40 px digit font; optional date line |\n| **Weather** | Live conditions, 3-day forecast, humidity / UV / wind / AQI / sunrise / pressure / **PM2.5 & PM10** |\n| **AI Vision** | Camera JPEG → cloud vision API → ≤40-character caption |\n| **Answers** | Offline Book of Answers (100 entries); photo / voice / random seeds |\n| **Stocks** | Up to **6** watchlist symbols; detail view with intraday chart |\n| **Life** | Conway’s Game of Life; classic seeds (Pulsar, LWSS, Gosper gun, …) |\n| **Settings** | WiFi, QWeather, AI provider & key, display, about |\n\n### Weather data pipeline\n\n1. IP geolocation → QWeather geo lookup (LocationID)\n2. `/v7/weather/now`, `/v7/weather/7d`, `/airquality/v1/current/{lat}/{lon}`\n3. Auth via `X-QW-Api-Key`; gzip decompressed in-firmware (`puff.c`)\n4. City label uses prefecture (`adm2`); forecast excludes today\n\n### Cloud integrations\n\n| Feature | Providers / APIs |\n|---------|------------------|\n| Weather | [QWeather](https://console.qweather.com) |\n| Vision | OpenAI, Gemini, Kimi, MiMo Token Plan |\n| Voice | MiMo ASR + chat (Token Plan key) |\n\nAnswers and Life require **no API key**.\n\n---\n\n## 4. Interaction model\n\n| Input | Global behavior |\n|-------|-----------------|\n| **A** click | Next / app action |\n| **A** double | Previous |\n| **A** long | Back to home |\n| **B** click | Open / confirm |\n| **B** double | Voice record toggle |\n\nSet `BTN_SERIAL_SIM=1` in `btn_input.h` to map `n` / `p` / `b` / `c` / `v` on serial **115200**.\n\n---\n\n## 5. Hardware & firmware requirements\n\n| Component | Detail |\n|-----------|--------|\n| MCU | Seeed **XIAO ESP32-S3 Sense** (camera + PDM mic) |\n| Panel | [EPD_1in54_V2](https://www.waveshare.com/1.54inch-e-paper.htm) |\n| Button A | D6 / GPIO43 |\n| Button B | D7 / GPIO44 |\n| EPD pins | See `DEV_Config.h` |\n\n| Arduino option | Value |\n|----------------|--------|\n| Board | Seeed XIAO ESP32S3 Sense |\n| PSRAM | OPI PSRAM **Enabled** |\n| Partition | Huge APP (3 MB+) |\n| LVGL | **8.3.x** |\n| ESP32 core | **3.x** |\n\n---\n\n## 6. Developer guide\n\n### 6.1 Quick start\n\n```text\n1. Install Arduino IDE 2.x (or arduino-cli) + esp32 board package 3.x\n2. Install lvgl 8.3.x\n3. Open Aink.ino (this directory = sketch root)\n4. Upload → serial monitor 115200\n```\n\nFirst boot without saved WiFi enters **captive portal** (QR / AP) for WiFi, weather key, and optional AI key.\n\n### 6.2 Boot splash\n\n```powershell\npython tools/bmp_to_boot_splash.py path\\to\\splash.bmp --out boot_splash_image.h\n```\n\nRequires 200×200 1-bit BMP.\n\n### 6.3 Vision API smoke test (PC)\n\n```powershell\ncd Aink\n$env:MIMO_API_KEY = \"your-key\"\npython tools/test_vision_api.py --provider mimo --image photo.jpg\n```\n\n### 6.4 Fonts & assets\n\n```bash\npython tools/build_cn_symbols.py\npython tools/build_fonts.py # Node npx required\npython tools/build_clock_font.py\npython tools/svg_to_weather_icons.py\npython tools/png_to_tile_icons.py # gear.png / eye.png in sketch root (local)\n```\n\nCJK: ~3500 chars in `tools/cn_font_symbols.txt` → `aink_3500_12.c` / `aink_3500_14.c`. \nManual path: [LVGL Font Converter](https://lvgl.io/tools/fontconverter) (LVGL 8.x, bpp 1). Strip `.static_bitmap = 0` if present.\n\n### 6.5 Source map\n\n| Module | Role |\n|--------|------|\n| `Aink.ino` | Boot, portal, refresh orchestration |\n| `epaper_canvas.*` | Framebuffer, rotation, async upload |\n| `ui_nav / ui_home` | Launcher + routing |\n| `ui_status_bar.*` | Status bar (home only) |\n| `ui_lvgl.*` | LVGL init; screen vs fullscreen |\n| `ui_*` | Per-app UI |\n| `*_service.*` | Weather, stock, vision, voice backends |\n| `settings_api.*` | NVS configuration |\n| `app_locale.*` | EN/ZH strings |\n| `puff.c` | Gzip inflate |\n| `tools/` | Build & test scripts |\n\n---\n\n## 7. Operations & troubleshooting\n\n| Symptom | Likely cause |\n|---------|----------------|\n| Chinese □ boxes | LVGL 8.3.x; missing glyphs in `cn_font_symbols.txt`; remove `.static_bitmap` from font `.c` |\n| Camera / PSRAM fail | Enable OPI PSRAM; Huge APP; Sense board with camera |\n| Weather 401/403 | API Host / Key mismatch; plan lacks Air Quality |\n| PM2.5 / PM10 `--` | No pollutant data for coordinates |\n| `undefined reference to puff` | Clean build; ensure `puff.c` in sketch |\n| Vision HTTP -1 | WiFi + PSRAM; validate with `test_vision_api.py` |\n\nSerial tags: `[Weather]`, `[Vision]`, `[Stock]`, `[Life]`, `[LVGL]`.\n\n---\n\n## 8. License\n\nMIT — see `LICENSE`. Waveshare EPD driver files retain their original header terms.\n\n---\n\n<p align=\"center\">\n <sub>AInk · Circuit Ink · firmware v0.1</sub>\n</p>\n"}}}}