Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions bridge/src/quotaframe_bridge/targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,12 @@ def ota_transfer_bytes(self) -> int:
image_chip_id=9,
ota_partition_bytes=4 * 1024 * 1024,
test_apps=("firmware/targets/waveshare_rlcd_42/test_apps/logic",),
web_flash=WebFlashDefinition(
name="Waveshare RLCD 4.2",
description="400 × 300 黑白反射式 LCD · KEY / BOOT 按键翻页",
chip_family="ESP32-S3",
asset="assets/devices/waveshare_rlcd_42.jpg",
),
),
)

Expand Down
6 changes: 5 additions & 1 deletion bridge/tests/test_target_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,11 @@ def test_ci_plan_cli_accepts_deleted_and_renamed_paths(self) -> None:
)

def test_new_web_targets_match_chip_families(self) -> None:
for target_id, chip in (("waveshare_epaper_397", "ESP32-S3"), ("esp_mosaico", "ESP32-S31")):
for target_id, chip in (
("waveshare_epaper_397", "ESP32-S3"),
("esp_mosaico", "ESP32-S31"),
("waveshare_rlcd_42", "ESP32-S3"),
):
web = TARGETS_BY_ID[target_id].web_flash
self.assertIsNotNone(web)
self.assertEqual(web.chip_family, chip)
Expand Down
8 changes: 8 additions & 0 deletions bridge/tests/test_web_flasher.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,14 @@ def test_public_target_document_contains_only_browser_fields(self) -> None:
"image": "espressif-esp-mosaico-full-v1.2.3.bin",
"manifest": "manifests/esp_mosaico.json",
},
{
"id": "waveshare_rlcd_42",
"name": "Waveshare RLCD 4.2",
"description": "400 × 300 黑白反射式 LCD · KEY / BOOT 按键翻页",
"asset": "assets/devices/waveshare_rlcd_42.jpg",
"image": "waveshare-esp32-s3-rlcd-42-full-v1.2.3.bin",
"manifest": "manifests/waveshare_rlcd_42.json",
},
],
)

Expand Down
2 changes: 1 addition & 1 deletion docs/devices.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

ePaper 3.97 与 ESP-Mosaico 的详细说明见 [ePaper 3.97 固件说明](../firmware/targets/waveshare_epaper_397/README.md) 与 [ESP-Mosaico 固件说明](../firmware/targets/esp_mosaico/README.md)。

RLCD 4.2 使用 400×300 黑白反射式 LCD,提供总览、Codex / Claude 详情、趋势、时钟和设置页;竖屏仅在总览和时钟间轮换。它支持 RTC、温湿度显示、电压估算电量,以及需 FAT microSD 卡的 48 点趋势。屏幕方向由设置选择,未接入 Web 烧录器。当前实机验证范围和完整操作见 [RLCD 4.2 说明](../firmware/targets/waveshare_rlcd_42/README.md)。
RLCD 4.2 使用 400×300 黑白反射式 LCD,提供总览、Codex / Claude 详情、趋势、时钟和设置页;竖屏仅在总览和时钟间轮换。它支持 RTC、温湿度显示、电压估算电量,以及需 FAT microSD 卡的 48 点趋势。屏幕方向由设置选择,可通过 Web 烧录器安装。当前实机验证范围和完整操作见 [RLCD 4.2 说明](../firmware/targets/waveshare_rlcd_42/README.md)。

## 屏幕快捷操作

Expand Down
7 changes: 5 additions & 2 deletions web/assets/devices/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Device photographs

Official product imagery, downloaded on 2026-09-08 and 2026-09-20. These images identify the
Official product imagery, downloaded on 2026-09-08, 2026-09-20 and 2026-10-01. These images identify the
supported hardware. Their screen contents are vendor demos, not QuotaFrame.
The page credits the respective official documentation next to the images.

Expand All @@ -17,8 +17,11 @@ The page credits the respective official documentation next to the images.
- `esp_mosaico.png`: Espressif ESP-Mosaico.
Source: https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s31/esp-mosaico/user_guide.html
Image: https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s31/_images/esp-mosaico-isometric.png
- `waveshare_rlcd_42.jpg`: Waveshare ESP32-S3-RLCD-4.2.
Source: https://docs.waveshare.com/ESP32-S3-RLCD-4.2
Image: https://docs.waveshare.com/assets/images/ESP32-S3-RLCD-4.2-DocHeader-fc9cf7209028a9fad948c565b694bd6b.webp

Images retain the rights of their respective owners and are not covered by the
repository's source code license. No screen replacement or device alteration
has been applied. The M5StickS3 and AMOLED 2.16 photos are cropped and encoded as JPEG.
has been applied. The M5StickS3, AMOLED 2.16 and RLCD 4.2 photos are cropped and encoded as JPEG.
The ePaper 3.97 and ESP-Mosaico images retain their original encoding.
Binary file added web/assets/devices/waveshare_rlcd_42.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 14 additions & 13 deletions web/src/components/HomePage.astro
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@ const assetRoot = locale === "en" ? "../" : "./";
<section id="compare" class="compare wrap" aria-labelledby="compare-title">
<div class="section-intro">
<p class="eyebrow">CHOOSE YOUR SCREEN</p>
<h2 id="compare-title">{t("四块小屏,各有所长。")}</h2>
<h2 id="compare-title">{t("五块小屏,各有所长。")}</h2>
<p>{t("显示内容相同,差别在屏幕与交互。")}</p>
</div>
<p class="compare-hint" aria-hidden="true">{t("左右滑动查看全部设备 →")}</p>
Expand All @@ -454,25 +454,26 @@ const assetRoot = locale === "en" ? "../" : "./";
<th scope="col"><img src={assetRoot + "assets/devices/m5sticks3.jpg"} alt="" loading="lazy" /><small>M5Stack</small>StickS3</th>
<th scope="col"><img src={assetRoot + "assets/devices/waveshare_epaper_397.jpg"} alt="" loading="lazy" /><small>{t("微雪")}</small>ePaper 3.97</th>
<th scope="col"><img src={assetRoot + "assets/devices/esp_mosaico.png"} alt="" loading="lazy" /><small>{t("乐鑫")}</small>ESP-Mosaico</th>
<th scope="col"><img src={assetRoot + "assets/devices/waveshare_rlcd_42.jpg"} alt="" loading="lazy" /><small>{t("微雪")}</small>RLCD 4.2</th>
</tr>
</thead>
<tbody>
<tr><th scope="row">{t("屏幕")}</th><td>{t("480 × 480 圆角方形 AMOLED")}</td><td>135 × 240 LCD</td><td>{t("800 × 480 四灰阶墨水屏")}</td><td>480 × 480 AMOLED</td></tr>
<tr><th scope="row">{t("用量页面")}</th><td>{t("总览 / Codex / Claude")}</td><td>{t("总览 / Codex / Claude")}</td><td>{t("主页同屏显示 Codex 与 Claude,另有趋势页")}</td><td>{t("总览 / Codex / Claude")}</td></tr>
<tr><th scope="row">{t("翻页")}</th><td>{t("触控标签、左右滑动")}</td><td>{t("正面按键")}</td><td>{t("三向拨轮")}</td><td>{t("触控标签、左右滑动、AI 键")}</td></tr>
<tr><th scope="row">{t("时钟屏保")}</th><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span></td><td class="compare-no"><span aria-hidden="true">—</span><span class="sr-only">{t("不支持")}</span></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span><small>{t("断电后需电脑端重新校时")}</small></td></tr>
<tr><th scope="row">{t("屏保用量细条")}</th><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span></td><td class="compare-no"><span aria-hidden="true">—</span><span class="sr-only">{t("不支持")}</span></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span></td></tr>
<tr><th scope="row">{t("自动旋转")}</th><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span><small>{t("四向")}</small></td><td class="compare-no"><span aria-hidden="true">—</span><span class="sr-only">{t("不支持")}</span></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span><small>{t("四向")}</small></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span><small>{t("四向")}</small></td></tr>
<tr><th scope="row">{t("摇动 / 翻转唤醒")}</th><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span></td><td class="compare-no"><span aria-hidden="true">—</span><span class="sr-only">{t("不支持")}</span></td><td class="compare-no"><span aria-hidden="true">—</span><span class="sr-only">{t("不支持")}</span></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span></td></tr>
<tr><th scope="row">{t("屏上设置")}</th><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span><small>{t("亮度、时钟超时")}</small></td><td class="compare-no"><span aria-hidden="true">—</span><span class="sr-only">{t("不支持")}</span></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span><small>{t("刷新间隔、方向")}</small></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span><small>{t("亮度、时钟超时")}</small></td></tr>
<tr><th scope="row">{t("托盘单击切换时钟")}</th><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span></td><td class="compare-no"><span aria-hidden="true">—</span><span class="sr-only">{t("不支持")}</span></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span></td></tr>
<tr><th scope="row">{t("温湿度")}</th><td class="compare-no"><span aria-hidden="true">—</span><span class="sr-only">{t("不支持")}</span></td><td class="compare-no"><span aria-hidden="true">—</span><span class="sr-only">{t("不支持")}</span></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span><small>{t("时钟页")}</small></td><td class="compare-no"><span aria-hidden="true">—</span><span class="sr-only">{t("不支持")}</span></td></tr>
<tr><th scope="row">{t("用量趋势")}</th><td class="compare-no"><span aria-hidden="true">—</span><span class="sr-only">{t("不支持")}</span></td><td class="compare-no"><span aria-hidden="true">—</span><span class="sr-only">{t("不支持")}</span></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span><small>{t("需 SD 卡")}</small></td><td class="compare-no"><span aria-hidden="true">—</span><span class="sr-only">{t("不支持")}</span></td></tr>
<tr><th scope="row">{t("屏幕")}</th><td>{t("480 × 480 圆角方形 AMOLED")}</td><td>135 × 240 LCD</td><td>{t("800 × 480 四灰阶墨水屏")}</td><td>480 × 480 AMOLED</td><td>{t("400 × 300 黑白反射式 LCD")}</td></tr>
<tr><th scope="row">{t("用量页面")}</th><td>{t("总览 / Codex / Claude")}</td><td>{t("总览 / Codex / Claude")}</td><td>{t("主页同屏显示 Codex 与 Claude,另有趋势页")}</td><td>{t("总览 / Codex / Claude")}</td><td>{t("总览 / Codex / Claude,另有趋势页")}</td></tr>
<tr><th scope="row">{t("翻页")}</th><td>{t("触控标签、左右滑动")}</td><td>{t("正面按键")}</td><td>{t("三向拨轮")}</td><td>{t("触控标签、左右滑动、AI 键")}</td><td>{t("KEY / BOOT 按键")}</td></tr>
<tr><th scope="row">{t("时钟屏保")}</th><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span></td><td class="compare-no"><span aria-hidden="true">—</span><span class="sr-only">{t("不支持")}</span></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span><small>{t("断电后需电脑端重新校时")}</small></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span></td></tr>
<tr><th scope="row">{t("屏保用量细条")}</th><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span></td><td class="compare-no"><span aria-hidden="true">—</span><span class="sr-only">{t("不支持")}</span></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span></td></tr>
<tr><th scope="row">{t("自动旋转")}</th><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span><small>{t("四向")}</small></td><td class="compare-no"><span aria-hidden="true">—</span><span class="sr-only">{t("不支持")}</span></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span><small>{t("四向")}</small></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span><small>{t("四向")}</small></td><td class="compare-no"><span aria-hidden="true">—</span><span class="sr-only">{t("不支持")}</span></td></tr>
<tr><th scope="row">{t("摇动 / 翻转唤醒")}</th><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span></td><td class="compare-no"><span aria-hidden="true">—</span><span class="sr-only">{t("不支持")}</span></td><td class="compare-no"><span aria-hidden="true">—</span><span class="sr-only">{t("不支持")}</span></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span></td><td class="compare-no"><span aria-hidden="true">—</span><span class="sr-only">{t("不支持")}</span></td></tr>
<tr><th scope="row">{t("屏上设置")}</th><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span><small>{t("亮度、时钟超时")}</small></td><td class="compare-no"><span aria-hidden="true">—</span><span class="sr-only">{t("不支持")}</span></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span><small>{t("刷新间隔、方向")}</small></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span><small>{t("亮度、时钟超时")}</small></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span><small>{t("自动轮播、告警、方向")}</small></td></tr>
<tr><th scope="row">{t("托盘单击切换时钟")}</th><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span></td><td class="compare-no"><span aria-hidden="true">—</span><span class="sr-only">{t("不支持")}</span></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span></td></tr>
<tr><th scope="row">{t("温湿度")}</th><td class="compare-no"><span aria-hidden="true">—</span><span class="sr-only">{t("不支持")}</span></td><td class="compare-no"><span aria-hidden="true">—</span><span class="sr-only">{t("不支持")}</span></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span><small>{t("时钟页")}</small></td><td class="compare-no"><span aria-hidden="true">—</span><span class="sr-only">{t("不支持")}</span></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span><small>{t("时钟页")}</small></td></tr>
<tr><th scope="row">{t("用量趋势")}</th><td class="compare-no"><span aria-hidden="true">—</span><span class="sr-only">{t("不支持")}</span></td><td class="compare-no"><span aria-hidden="true">—</span><span class="sr-only">{t("不支持")}</span></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span><small>{t("需 SD 卡")}</small></td><td class="compare-no"><span aria-hidden="true">—</span><span class="sr-only">{t("不支持")}</span></td><td><span aria-hidden="true">✓</span><span class="sr-only">{t("支持")}</span><small>{t("需 SD 卡")}</small></td></tr>
</tbody>
</table>
</div>
<p class="compare-note">
{t("四块屏都支持:Codex / Claude 用量显示、电量与充电显示、断连保留最后用量、在托盘图标上滚动翻页、电脑端 OTA 更新与网页安装。")}
{t("五块屏都支持:Codex / Claude 用量显示、电量显示、断连保留最后用量、在托盘图标上滚动翻页、电脑端 OTA 更新与网页安装。")}
</p>
</section>
<section id="privacy" class="privacy-section wrap" aria-labelledby="privacy-title">
Expand Down
9 changes: 7 additions & 2 deletions web/src/i18n/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,22 +114,25 @@ export default {
"上一页": "Previous page",
"下一页": "Next page",
"演示使用示例数据,无需连接设备。实际操作需配套 Bridge 与固件,并作用于所有已连接且支持相应功能的设备。": "The demo uses sample data; no device connection is required. Real controls require Bridge and firmware and affect all connected devices that support the corresponding feature.",
"四块小屏,各有所长。": "Four displays. Find your fit.",
"五块小屏,各有所长。": "Five displays. Find your fit.",
"显示内容相同,差别在屏幕与交互。": "The same usage data, with different screens and controls.",
"左右滑动查看全部设备 →": "Swipe to compare all devices →",
"微雪": "Waveshare",
"乐鑫": "Espressif",
"屏幕": "Display",
"480 × 480 圆角方形 AMOLED": "480 × 480 rounded-square AMOLED",
"800 × 480 四灰阶墨水屏": "800 × 480 four-level grayscale e-paper",
"400 × 300 黑白反射式 LCD": "400 × 300 black-and-white reflective LCD",
"用量页面": "Usage pages",
"总览 / Codex / Claude": "Overview / Codex / Claude",
"主页同屏显示 Codex 与 Claude,另有趋势页": "Codex and Claude together, plus a trends page",
"总览 / Codex / Claude,另有趋势页": "Overview / Codex / Claude, plus a trends page",
"翻页": "Page controls",
"触控标签、左右滑动": "Touch tabs and swipe left or right",
"正面按键": "Front button",
"三向拨轮": "Three-way wheel",
"触控标签、左右滑动、AI 键": "Touch tabs, swipe left or right, and AI button",
"KEY / BOOT 按键": "KEY / BOOT buttons",
"时钟屏保": "Clock screensaver",
"支持": "Yes",
"不支持": "No",
Expand All @@ -141,12 +144,13 @@ export default {
"屏上设置": "On-device settings",
"亮度、时钟超时": "Brightness, clock timeout",
"刷新间隔、方向": "Refresh interval, orientation",
"自动轮播、告警、方向": "Auto cycle, alerts, orientation",
"托盘单击切换时钟": "Click tray icon to toggle clock",
"温湿度": "Temperature / humidity",
"时钟页": "Clock page",
"用量趋势": "Usage trends",
"需 SD 卡": "SD card required",
"四块屏都支持:Codex / Claude 用量显示、电量与充电显示、断连保留最后用量、在托盘图标上滚动翻页、电脑端 OTA 更新与网页安装。": "All four support Codex / Claude usage, battery and charging status, keeping the last usage when disconnected, scrolling the tray icon to change pages, desktop OTA updates, and browser installation.",
"五块屏都支持:Codex / Claude 用量显示、电量显示、断连保留最后用量、在托盘图标上滚动翻页、电脑端 OTA 更新与网页安装。": "All five support Codex / Claude usage, battery level, keeping the last usage when disconnected, scrolling the tray icon to change pages, desktop OTA updates, and browser installation.",
"凭证留在本机,": "Credentials stay local.",
"小屏只收摘要。": "Only a summary reaches your display.",
"QuotaFrame 不接管账号登录,只将本机整理的用量摘要发送到已配对的小屏。": "QuotaFrame does not manage account sign-in. It sends a locally prepared usage summary to your paired display.",
Expand Down Expand Up @@ -248,6 +252,7 @@ export default {
"480 × 480 圆角方形 AMOLED · 触控与滑动操作": "480 × 480 rounded-square AMOLED · Touch and swipe controls",
"800 × 480 四灰阶墨水屏 · 三向拨轮操作": "800 × 480 four-level grayscale e-paper · Three-way wheel",
"480 × 480 AMOLED · 触控与 AI 按键翻页": "480 × 480 AMOLED · Touch and AI button navigation",
"400 × 300 黑白反射式 LCD · KEY / BOOT 按键翻页": "400 × 300 black-and-white reflective LCD · KEY / BOOT button navigation",
"当前为{current},点击切换到{next}": "Showing {current}. Click to view {next}.",
"、": ", "
};
Loading
Loading