1 line
7.8 KiB
JSON
1 line
7.8 KiB
JSON
{"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"}}}} |