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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ The data source handles account sign-in and usage retrieval. Bridge sends only u
| Waveshare AMOLED 2.16 | 480×480 AMOLED | Touchscreen, clock screensaver, auto-rotation |
| M5StickS3 | 135×240 LCD | Button navigation, compact size |
| Waveshare ePaper 3.97 | 800×480 e-paper with four grayscale levels | Temperature and humidity, usage trends (microSD card required) |
| ESP-Mosaico | 480×480 AMOLED | Touchscreen, AI button, auto-rotation |
| ESP-Mosaico | 480×480 AMOLED | Touchscreen, AI button, auto-rotation, camera gestures (experimental) |
| Waveshare RLCD 4.2 | 400×300 monochrome reflective LCD | KEY / BOOT navigation, clock, usage trends (microSD card required) |

All devices support Codex / Claude usage display, retain the last usage data when disconnected, and support firmware updates over Bluetooth. See the [device guide](docs/devices.md) for a full feature comparison and control shortcuts.
Expand Down
2 changes: 1 addition & 1 deletion README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ flowchart LR
| Waveshare AMOLED 2.16 | 480×480 AMOLED | 触屏、时钟屏保、自动旋转 |
| M5StickS3 | 135×240 LCD | 按键翻页、小尺寸 |
| Waveshare ePaper 3.97 | 800×480 四灰阶墨水屏 | 温湿度、用量趋势(需 microSD 卡) |
| ESP-Mosaico | 480×480 AMOLED | 触屏、AI 键、自动旋转 |
| ESP-Mosaico | 480×480 AMOLED | 触屏、AI 键、自动旋转、摄像头手势(实验性) |
| Waveshare RLCD 4.2 | 400×300 黑白反射式 LCD | KEY / BOOT 翻页、时钟、用量趋势(需 microSD 卡) |

所有设备均支持 Codex / Claude 用量显示、断连保留最后用量与蓝牙固件更新。完整功能对照及快捷操作见[设备说明](docs/devices.md)。
Expand Down
63 changes: 60 additions & 3 deletions THIRD_PARTY_LICENSES.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ For ESP Component Registry entries, `Registry license` is the API value for the
- Source: https://components.espressif.com/components/espressif/usb/versions/1.3.0
- SPDX: `Apache-2.0`
- Copyright/notice: https://github.com/espressif/esp-usb/blob/ded385702ecae4d5c15c497149062ce577fa167a/host/usb/LICENSE
- ESP-Mosaico version: `1.5.0`; source: https://components.espressif.com/components/espressif/usb/versions/1.5.0; copyright/notice: https://github.com/espressif/esp-usb/blob/eb4618660a83e80cd57dcda736edbfa884cb88cc/host/usb/LICENSE

## `idf`

Expand Down Expand Up @@ -527,10 +528,10 @@ SOFTWARE.

## `espressif/dhara`

- Version: `1.0.0`
- Source: https://components.espressif.com/components/espressif/dhara/versions/1.0.0
- Version: `1.1.0`
- Source: https://components.espressif.com/components/espressif/dhara/versions/1.1.0
- SPDX conclusion from distributed license: `ISC`
- Copyright/notice: https://components.espressif.com/components/espressif/dhara/versions/1.0.0/license
- Copyright/notice: https://components.espressif.com/components/espressif/dhara/versions/1.1.0/license

## `espressif/esp_lcd_touch_cst9220`

Expand Down Expand Up @@ -566,3 +567,59 @@ SOFTWARE.
- Source: https://components.espressif.com/components/tangyumei3535/bmm150_sensorapi/versions/1.0.0
- SPDX conclusion from distributed license: `BSD-3-Clause`
- Copyright/notice: https://components.espressif.com/components/tangyumei3535/bmm150_sensorapi/versions/1.0.0/license

## `espressif/esp-dl`

- ESP-Mosaico version: `3.3.11`
- Source: https://components.espressif.com/components/espressif/esp-dl/versions/3.3.11
- SPDX conclusion: `MIT`
- Copyright/notice: https://components.espressif.com/components/espressif/esp-dl/versions/3.3.11/license

## `espressif/esp_video`

- ESP-Mosaico version: `2.5.0`
- Source: https://components.espressif.com/components/espressif/esp_video/versions/2.5.0
- SPDX conclusion: `LicenseRef-Espressif-MIT`
- Copyright/notice: https://components.espressif.com/components/espressif/esp_video/versions/2.5.0/license

## `espressif/esp_cam_sensor`

- ESP-Mosaico version: `2.6.0`
- Source: https://components.espressif.com/components/espressif/esp_cam_sensor/versions/2.6.0
- SPDX conclusion: `Apache-2.0`
- Copyright/notice: https://components.espressif.com/components/espressif/esp_cam_sensor/versions/2.6.0/license

## `espressif/esp_sccb_intf`

- ESP-Mosaico version: `0.0.8`
- Source: https://components.espressif.com/components/espressif/esp_sccb_intf/versions/0.0.8
- SPDX conclusion: `Apache-2.0`
- Copyright/notice: https://components.espressif.com/components/espressif/esp_sccb_intf/versions/0.0.8/license

## `espressif/dl_fft`

- ESP-Mosaico version: `0.7.0`
- Source: https://components.espressif.com/components/espressif/dl_fft/versions/0.7.0
- SPDX conclusion: `MIT`
- Copyright/notice: https://components.espressif.com/components/espressif/dl_fft/versions/0.7.0/license

## `espressif/usb_host_uvc`

- ESP-Mosaico version: `2.5.1`
- Source: https://components.espressif.com/components/espressif/usb_host_uvc/versions/2.5.1
- SPDX conclusion: `Apache-2.0`
- Copyright/notice: https://components.espressif.com/components/espressif/usb_host_uvc/versions/2.5.1/license

## `espressif/hand_detect`

- ESP-Mosaico version: `0.2.0`
- Source: https://components.espressif.com/components/espressif/hand_detect/versions/0.2.0
- SPDX conclusion: `MIT`
- Copyright/notice: https://components.espressif.com/components/espressif/hand_detect/versions/0.2.0/license

## `espressif/hand_gesture_recognition`

- ESP-Mosaico version: `0.2.0`
- Source: https://components.espressif.com/components/espressif/hand_gesture_recognition/versions/0.2.0
- SPDX conclusion: `MIT`
- Copyright/notice: https://components.espressif.com/components/espressif/hand_gesture_recognition/versions/0.2.0/license
3 changes: 2 additions & 1 deletion bridge/src/quotaframe_bridge/sources/firmware_release.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@
from quotaframe_bridge.protocol.validation import unique_object, validate_identifier
from quotaframe_bridge.release_config import release_repository
from quotaframe_bridge.versioning import SemVer, VersionError
from quotaframe_bridge.targets import TARGETS

_SHA256 = re.compile(r"^[0-9a-f]{64}$")
MAX_MANIFEST_BYTES = 64 * 1024
MAX_IMAGE_BYTES = 4 * 1024 * 1024
MAX_IMAGE_BYTES = max(target.ota_partition_bytes for target in TARGETS)
Comment thread
eMUQI marked this conversation as resolved.


class FirmwareReleaseError(ValueError):
Expand Down
2 changes: 1 addition & 1 deletion bridge/src/quotaframe_bridge/targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ def ota_transfer_bytes(self) -> int:
full_image="mosaico_usage_panel_full.bin",
release_stem="espressif-esp-mosaico",
image_chip_id=32,
ota_partition_bytes=4 * 1024 * 1024,
ota_partition_bytes=7 * 1024 * 1024,
test_apps=("firmware/targets/esp_mosaico/test_apps/logic",),
web_flash=WebFlashDefinition(
name="ESP-Mosaico",
Expand Down
13 changes: 12 additions & 1 deletion bridge/tests/test_firmware_release.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,13 +113,24 @@ async def test_rejects_oversized_manifest_image_and_fetch_result(self) -> None:
with self.assertRaises(FirmwareReleaseError):
await source.download_image(manifest.for_target("m5sticks3"))

too_large = json.loads(self.manifest(size=4 * 1024 * 1024 + 1))
too_large = json.loads(self.manifest(size=7 * 1024 * 1024 + 1))
source = FirmwareReleaseSource(
fetcher=lambda _url, _limit: json.dumps(too_large).encode()
)
with self.assertRaises(FirmwareReleaseError):
await source.fetch_manifest(self.manifest_url)

async def test_accepts_mosaico_image_within_expanded_ota_slot(self) -> None:
source = FirmwareReleaseSource(
fetcher=lambda _url, _limit: self.manifest(
target="esp_mosaico", firmware_project="mosaico_usage_panel",
size=7 * 1024 * 1024,
)
)
manifest = await source.fetch_manifest(self.manifest_url)
image = manifest.for_target("esp_mosaico", "mosaico_usage_panel")
self.assertEqual(image.size, 7 * 1024 * 1024)

async def test_rejects_noncanonical_semver(self) -> None:
for version in ("01.2.3", "1.02.3", "1.2.03", "1.2.3-alpha..1", "1.2.3-01"):
with self.subTest(version=version):
Expand Down
11 changes: 7 additions & 4 deletions docs/design/amoled-ui.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,18 +72,21 @@ Waveshare:屏幕边距 24px;卡片宽 432px;卡片内边距 20–22px;
- **底部导航**:方屏为**纯文字标签 + 下划线指示**,不用色块、不用卡片底。34px 高的三等分标签条,标签 13px 600 大写、字距 0.06em;未选中 `#565D68`,选中 `#C7CCD4` 并在标签下方 7px 处加一条 26×2px(圆角 1px)`#C7CCD4` 短横。导航是次要信息,任何情况下都不能成为屏幕上最亮的元素。**下划线是三个标签共用的同一条**,翻页时以 180ms 缓出横向滑到新标签下方,而不是在旧位置熄灭、新位置点亮;页面本身仍是硬切换。
- **连接状态**:右上角一个 8px 状态色圆点 + 14px `#C7CCD4` 文字。不显示 `SECURE` 之类无操作价值的标签。
- **电池**:连接状态右侧,30×14 描边(1px `#565D68`)+ 2px 正极点,内含 4 段。**分级显示,不显示百分比**:FULL=4 段、HIGH=3 段、MID=2 段、LOW=1 段、无数据=0 段;点亮色 `#C7CCD4`,熄灭段 `#2C313B`;仅 LOW 时点亮段转 `#F5B84C`。**充电**:外框左侧 gap 5px 有 7×12 闪电槽,**始终占位**(不充电时留空,绝不收起,否则插拔 USB 会让 `LINKED` 平移);充电时填 `#C7CCD4`,段数照常反映电量,不做动画;充电时 LOW 不再变黄(外部供电已接入,此时低电量告警不再提供操作价值),屏保 `LOW` 角标同时撤掉。USB 只是供电,不改变 `LINKED`,界面不出现 `USB` 标签。
- **摄像头标识**(仅 Mosaico,实验性手势):`CAMERA` 开关已保存为打开时,连接状态点左侧 10px 显示 26×16 实心相机剪影(顶部 8×4 取景凸起,bg 色镜头环内含 4px 镜头点),与状态点垂直居中。采集中(启动或识别)为 `text` 色;开关打开但采集暂停(设置、配对、OTA)为 `dim`;采集失败时为 `dim` 并叠加 `#C7CCD4` 斜杠(外圈 bg 色描边)。开关关闭时不占位。顶栏不显示手势文字提示,仅保留 OK / 点赞停留进度条。保持灰阶,不使用 good/warn/bad 色。屏保不显示。
- **相机预览**(仅 Mosaico):识别就绪且处于普通页面时,点击顶栏摄像头标识切换预览,再次点击关闭;每次启动默认隐藏,不持久化。浮层位于内容区右上角,距右侧 24px、距内容区顶部 8px;按画面比例显示,最长边 160px,不裁切、不拉伸。只显示相机图像及 2px `text` 色手部定位框,无手时隐藏定位框,不叠加检测数量、置信度或状态文字。开关只控制预览显示,手势识别由设置页 CAMERA 控制。时钟、设置、配对、OTA、相机暂停或故障时隐藏浮层;识别恢复且返回普通页面后恢复本次运行的预览选择。
- **时间**:顶栏左侧,22px 700,`text` 色,24 小时制不显示秒。页面归属由底部导航指示,无需重复标题。硬件无温湿度传感器,界面不出现环境信息。
- **屏保态(SCREENSAVER)**:空闲 5 分钟后进入,触摸屏幕或晃动(IMU)唤醒,回到进入前的页面。规则是**整体降一级**——时钟 `muted #8B93A1`(120px,居中 top 158)、日期一行 20px `dim`、顶栏与底部导航全部隐藏、卡片去掉 panel 底与描边(纯 `bg`,AMOLED 省电)。屏幕上不得出现 `text` 级亮度。底部 13px `#2C313B` 提示 `TAP OR SHAKE TO WAKE`,进入 3 秒后淡出。仅电池 LOW 时右上角显示降亮的 `LOW` + 电池图标(`#8A6A2E`),其余状态一概不显示。防烧屏:整块内容每 60 秒随机位移 ±10px。

## 6. 本地显示设置

微雪设备长按触屏约 0.8 秒进入全屏设置页。亮度范围 1–100%,调整时预览;自动进入时钟支持 OFF、1、5、10、30 分钟。SAVE 写入 NVS,CANCEL 恢复已保存值;首次启动使用 menuconfig 默认值。OFF 不影响主动切换时钟。设置页打开时保持唤醒,配对和 OTA 优先于设置并撤销未保存预览。
微雪 AMOLED 2.16 与 ESP-Mosaico 长按触屏约 0.8 秒进入全屏设置页。亮度范围 1–100%,调整时预览;自动进入时钟支持 OFF、1、5、10、30 分钟。SAVE 写入 NVS,CANCEL 恢复已保存值;首次启动使用 menuconfig 默认值。OFF 不影响主动切换时钟。设置页打开时保持唤醒,配对和 OTA 优先于设置并撤销未保存预览。

设置页采用 24px 边距的行式布局,两项设置以 1px `#1D2128` 分隔线分组,不增加卡片底色与描边。顶栏左侧显示 DISPLAY,右侧复用连接状态与电池;LINKED 保持绿色。设置操作优先保证近距离触控,不要求全部读数使用远距离展示字号。
设置页采用 24px 边距的行式布局,设置项以 1px `#1D2128` 分隔线分组,不增加卡片底色与描边。顶栏左侧显示 DISPLAY,右侧复用连接状态与电池;LINKED 保持绿色。设置操作优先保证近距离触控,不要求全部读数使用远距离展示字号。

- **亮度设置行**:复用现有 48px 数值字体;右侧加减按钮为 80×80px,间隔 8px。仅通过按钮调整,不显示不可操作的滑条。到达 1% 或 100% 时禁用对应按钮,边界不循环。
- **有限选项选择**:AUTO CLOCK 下方标明 AFTER IDLE / MIN;OFF、1、5、10、30 五项为 80×64px,间隔 8px,一次点击选定。只有当前选项反色,不累计填充;OFF 不拼接 MIN。保留非标准 menuconfig 默认时长,未匹配预设时显示当前秒数,直到用户主动选择预设。
- **亮度设置行**:复用现有 48px 数值字体;右侧加减按钮为 80×80px,Mosaico 为 80×72px,间隔 8px。仅通过按钮调整,不显示不可操作的滑条。到达 1% 或 100% 时禁用对应按钮,边界不循环。
- **有限选项选择**:AUTO CLOCK 下方标明 AFTER IDLE / MIN;OFF、1、5、10、30 五项为 80×64px,Mosaico 为 80×52px,间隔 8px,一次点击选定。只有当前选项反色,不累计填充;OFF 不拼接 MIN。保留非标准 menuconfig 默认时长,未匹配预设时显示当前秒数,直到用户主动选择预设。
- **操作状态**:16px 圆角,可见边界与点击区域一致。选中项及可用 SAVE 使用 text 底、bg 字;未选项和 CANCEL 使用 panel 底、muted 字。按下时背景和边框产生灰阶反馈;禁用控件使用 panel 底、dim 字,不响应点击。不使用主题阴影或过渡。
- **开关**(仅 Mosaico `CAMERA`):独立一行,与上方以分隔线隔开;右侧 80×44px 胶囊开关,与加减按钮右对齐。关闭为 panel 底、muted 圆钮居左;打开为反色 text 底、bg 圆钮居右。与亮度、自动时钟一样只是预览:切换后启用 SAVE,SAVE 一并写入 NVS,CANCEL 恢复已保存值。
- **保存与取消**:底部按钮均为 206×64px,间隔 20px。未修改时禁用 SAVE,修改后启用;CANCEL 始终可用。保存成功后退出,失败时保留页面和预览,在按钮上方显示 SAVE FAILED - TRY AGAIN 并允许重试。不常驻显示持久化实现说明。

实机验证需覆盖最低亮度恢复操作、桌面支架姿态下的按钮命中、OFF、未修改/已修改以及保存失败状态;像素尺寸与桌面预览不能替代触控和 AMOLED 可读性验收。
Expand Down
Loading
Loading