Skip to content

llinzzi/slumbercube

Repository files navigation

SlumberCube 安睡小方

GitHub ESP32-C3 SSD1322 License

Slumber = 安睡 · Cube = 方块 —— 床头那块陪你安稳入眠的小方块。

简介

一款定位于床头的AI Agent项目, 他哄你入睡,伴你睡眠,唤你起床。

特色功能:

  • 🌙 深夜极暗显示模式 — 4×4 抖动数码管 + 极暗对比度,在深夜实现无光污染的时间展现。
  • 🌙 深夜广播 — 有AI Agent驱动的小方DJ生成广播词,播报天气预报及自动下载睡眠歌单。
  • 🌙 深夜气温检测 — 睡眠阶段采集室内温度,健康晚睡空调等是否合理。
  • 🎵 早安广播 — 早上定时唤醒,开始播报起床广播,小方DJ也进行播报。

后端服务:llinzzi/slumbercube-server

🎬 演示视频Bilibili BV13ETt6JEUU

夜间使用场景

正面 反面

线框图 3D 渲染图
线框图 3D 渲染

硬件规格

原理图版本:Schematic1_9 · 2026-06-27 (P2 修订 2026-06-23)

主控

项目 规格
模组 ESP32-C3-MINI-1-N4 (RISC-V 单核, WiFi, SMD 模组)
Flash 4MB DIO @ 80MHz
内部 RTC ESP32-C3 内置 RC 振荡器(精度较低, 深度睡眠期间不计时)
外部 RTC PCF85063ATT/AJ (U3) — 见下文"实时时钟"
复位 CHIP_PU 上拉 R5 10K, 按键 SW14 可手动复位

芯片清单

位号 型号 角色
U6 ESP32-C3-MINI-1-N4 主控 MCU (SMD 模组)
U5 NS4168 Class-D 数字功放
U3 PCF85063ATT/AJ I²C 实时时钟芯片 (自带 32.768kHz 晶振)
U20 SHTC3-TR-10KS I²C 温湿度传感器 (与 U3 共用总线)
U1 TP4056X 锂电池充电管理
U2 (LDO SOT-23-5) 3.3V 线性稳压
D1 1N5819WS 防反肖特基二极管
D2 USBLC6-2SC6 USB 数据线 ESD 保护
Q1 (P-MOSFET) 电池防反接
X1 32.768kHz PCF85063 专用 RTC 晶振 (C9/C11 22pF, R10 5M 偏置)

电源

flowchart LR
    A[USB-C 5V] -->|VBUS| B[USBLC6-2SC6<br/>ESD]
    B -->|VIN| C[TP4056X<br/>充电管理]
    C -->|VBAT| D[H6 电池接口<br/>锂电池]
    D --> Q1[P-MOSFET<br/>防反]
    Q1 -->|VBAT| E[U2 LDO 3.3V]
    A -->|D1 肖特基| E
    E --> F[3.3V 电源轨]
    F --> G[ESP32-C3]
    F --> H[SHTC3]
    F --> I[NS4168 逻辑]
    F --> J[PCF85063]
Loading
项目 规格
输入 USB Type-C (MC-802YC-H105), 5V, CC1/CC2 各 5.1K 下拉
充电 IC TP4056X, PROG=R2 10K → ~130mA 充电电流
充电指示 LED1 (CHRG#) + R1 1K
防反 D1 (1N5819WS) + Q1 (P-MOSFET, R3 10K 偏置)
电池接口 H6 2-pin 2.0mm wafer
稳压 U2 LDO, 输入/输出各 1µF 去耦
OLED 供电 直接取自 USB 5V (H2 pin 1), 不经过电池

实时时钟 (PCF85063ATT/AJ)

板载独立 RTC 芯片,深度睡眠期间持续计时,唤醒后 ESP32-C3 通过 I²C 读取时间,避免每次 WiFi SNTP 同步。

项目 规格
芯片 NXP PCF85063ATT/AJ (SO-8)
接口 I²C (与 SHTC3 共用 SCL/SDA 总线, 地址 0x51)
晶振 外置 32.768kHz (X1 + C9/C11 22pF + R10 5M 偏置)
中断输出 INT# → ESP32-C3 IO0 (RTC_INT, 可作秒中断/闹钟唤醒)
精度 取决于晶振, 典型 ±20 ppm @ 25°C
去耦 C17 100nF

设计动机:ESP32-C3 内置 RTC 在深度睡眠时若使用内部 RC 振荡器会丢失精度,外部 32.768kHz 晶振本应直接接到 ESP32-C3 的 XTAL_32K 脚。新版原理图把晶振挪到了 PCF85063,由 PCF85063 独立计时,ESP32-C3 唤醒后再去 I²C 读——这样深度睡眠期间 ESP32-C3 内部 RTC 完全断电也无所谓。

显示

项目 规格
型号 SSD1322
分辨率 256×64 灰度 OLED
接口 SPI 10MHz, I4 灰度 (16 级)
连接器 H2 PM254-2-08-S-8.5 (8-pin 2.54mm)
供电 5V (从 USB VBUS 直接取电)

音频

项目 规格
功放 NS4168 Class-D
接口 I2S (ESP32-C3 → NS4168)
输出 差分 VON/VOP, 经 L1/L2 + C14/C15 (1nF) LC 滤波
喇叭接口 H5 2-pin 2.0mm wafer
关断 NS_CTRL 低电平 = 关功放

温湿度 & RTC (I²C 总线)

项目 规格
总线 I²C, SCL = IO9, SDA = IO21
上拉 R41/R42 各 4.7K → 3.3V
设备 1 Sensirion SHTC3 (地址 0x70) — 温湿度
设备 2 NXP PCF85063ATT/AJ (地址 0x51) — RTC

两设备共用同一 I²C 总线,靠地址区分。

按键

位号 型号 接至 触发 功能
SW1 TC-6615-5-260G (侧按 5mm) IO1 低电平 左键 (媒体):短按播放/暂停 / 长按下一首
SW12 TC-6615-5-260G (侧按 5mm) IO3 低电平 右键 (电源):短按睡眠 / 长按切换日夜模式 / 三击重置配网 / 深度睡眠唤醒
SW13 TS342A2P 160gf IO9 ⚠️ 低电平 预留按键(三重共用, 见下)
SW14 TS342A2P 160gf CHIP_PU/EN 低电平 硬件复位

⚠️ IO9 三重共用:SW13、SHTC3 SCL、PCF85063 SCL 都接到 IO9。I²C 总线空闲时 SW13 按下会把 SCL 拉低,可能导致 I²C 通信失败。固件目前使用 SW1(IO1, 左键)和 SW12(IO3, 右键),SW13 暂留空。

按键使用指南

操作 右键 (电源键, IO3) 左键 (媒体键, IO1)
短按 (< 2s) 立即进入深度睡眠 播放/暂停音频(首次自动连接 WiFi)
长按 (≥ 2s) 强制切换日间/夜间显示模式 跳过当前曲目,请求下一首
三击 恢复出厂设置 → 进入配网模式

右键 是唯一能唤醒深度睡眠的按键,也是电源控制键。在任何状态下短按右键都会立即睡眠。

左键 仅在非夜间模式且已配置 WiFi 时有效。未连接 WiFi 时短按左键会自动触发 WiFi 连接后再播放。夜间模式下左键操作被忽略。

无网络唤醒(按键唤醒)时,屏幕底部显示 按左键播放 提示,室内温湿度和闹钟时间直接展示,不发起 WiFi 连接——WiFi 仅在 RTC 闹钟唤醒或用户按左键时才启动。

USB 与接口

接口 型号 用途
USB-C MC-802YC-H105 充电输入(5V)
H5 WAFER-PH2.0-2PWB 锂电池接入
H6 WAFER-PH2.0-2PWB 喇叭接入
H2 PM254-2-08-S-8.5 OLED 模组接入

USB 数据线 D+_OUT/D-_OUT 经 USBLC6-2SC6 ESD 后直连 ESP32-C3 原生 USB (IO19/IO18),本固件未使用 USB CDC(仍走串口烧录)。

GPIO 配置

GPIO 功能 连接 备注
IO0 RTC_INT PCF85063 INT# RTC 闹钟/秒中断输出, 可唤醒 ESP32-C3
IO1 LEFT_KEY SW1 左键 (媒体): 播放暂停/下一首
IO2 NS_CTRL NS4168 CTRL 功放关断, 低 = 静音
IO3 RIGHT_KEY / WAKEUP SW12 右键 (电源): 睡眠/日夜切换/三击重置/深度睡眠唤醒
IO4 I2S_SDIN NS4168 SDATA
IO5 I2S_SCLK NS4168 BCLK
IO6 I2S_LRCLK NS4168 LRCLK
IO7 SPI_SCK SSD1322 SCLK
IO8 SPI_DC SSD1322 DC
IO9 I2C_SCL (三重共用) SHTC3 + PCF85063 + SW13 ⚠️ 三方复用, 固件仅作 I²C 用
IO10 SPI_SDA SSD1322 MOSI
IO18 USB_D-_OUT USB-C D- 原生 USB, 固件未用
IO19 USB_D+_OUT USB-C D+ 原生 USB, 固件未用
IO20 SPI_RST SSD1322 RST 深度睡眠期间 GPIO hold 拉低
IO21 I2C_SDA SHTC3 SDA + PCF85063 SDA R42 4.7K 上拉, 总线共享
CHIP_PU EN SW14 + R5 10K 上拉 复位按键, 高 = 运行

SPI CS 硬件接地(SSD1322 始终选中)。 唤醒 GPIO 与右键 (电源键) 共用 IO3。 ESP32-C3 不再外接 32.768kHz 晶振(晶振移到 PCF85063)。


程序启动流程

flowchart TD
    A[深度睡眠] -->|RTC/右键唤醒| B[esp_sleep_get_wakeup_cause]
    B --> C{唤醒源}
    C -->|RTC| D[wake=rtc]
    C -->|右键| E[wake=btn]
    C -->|冷启动| F[wake=sys]

    D --> G[GPIO 早期初始化]
    E --> G
    F --> G

    G --> H[ssd1322_init<br/>显示保持关闭]
    H --> I[双键初始化<br/>右键: 短=睡眠 长=日夜 三击=重置<br/>左键: 短=播放 长=下一首]
    I --> J[wifi_set_timezone<br/>CST-8]
    J --> K[PCF85063 RTC 初始化<br/>读取时间恢复到系统]
    K --> L[lvgl_adapter_init<br/>L8→I4 DMA]
    L --> M{首次启动无 WiFi 凭据?}
    M -->|是| MA[config_screen<br/>QR 码配网页面]
    M -->|否| MB[clock_screen_create<br/>首帧渲染]
    MA --> MC[ssd1322_display_on]
    MB --> MC

    MC --> N{夜间模式?}

    N -->|是| O[跳过 WiFi/天气/音频<br/>极暗数码管显示]
    N -->|否| P{唤醒源 = RTC?}

    P -->|否 (按键唤醒)| NA[无网络模式<br/>显示室内温湿度 + 闹钟时间<br/>底部提示: 按左键播放]
    P -->|是 (RTC 闹钟)| Q[WiFi STA 连接]
    Q --> R[SNTP 时间同步]
    R --> RC[PCF85063 时间回写]
    RC --> S{Agent 已启用?}
    S -->|否| SA[clock-only 模式<br/>跳过 /api/esp]
    S -->|是| T[audio_fetch_api<br/>单次 HTTP GET /api/esp]
    T --> U[解析天气 + 电台URL]
    U --> V{有电台URL?}
    V -->|是| W[audio_play_url<br/>HTTP 流 MP3 解码]
    V -->|否| WA[跳过音频]
    T --> TB[arm_pcf85063_alarm<br/>写入下次闹钟]

    O --> X[主循环 1800s]
    NA --> X
    SA --> X
    W --> X
    WA --> X

    X --> Y{事件驱动 1s tick}
    Y -->|右键短按| Z[深度睡眠]
    Y -->|右键三击| ZA[恢复出厂 → 重启]
    Y -->|右键长按| ZB[强制切换日夜模式]
    Y -->|左键短按| ZC[播放/停止<br/>首次自动连 WiFi]
    Y -->|左键长按| ZD[下一首]
    Y -->|歌曲结束/卡住| ZE[auto_advance<br/>请求下一首]
    Y -->|超时 1800s| Z
    Y -->|每10秒| ZF[刷新 SHTC3 传感器]
    ZE --> T
    ZC --> T
    ZD --> T
    ZF --> X
Loading

屏幕布局

y=0   ┌──────────────────────────────────────────────┐
      │ 左: 16:30 (digital-7 48px)   右: 小雨 22°(内25.3°58%)  │
y=18  │                                    22° - 30°         │
y=36  │              [ 歌曲名居中滚动 / 按左键播放 ]               │
      └──────────────────────────────────────────────┘
                        256×64 SSD1322
区域 字体 内容
时间 lv_font_digital (digital-7, 48px, 4bpp) HH:MM
天气行 lv_font_station (fusion-pixel, 10px, 1bpp) 天气文字 + 当前温度 + 室内温湿度
温度行 lv_font_station 今日最低温度 – 最高温度
歌名行 lv_font_station 歌曲名居中滚动;无网络时显示 按左键播放

夜间模式

触发条件: 23:00–6:00(跨天,可通过 menuconfig 配置)

  • 显示切换到 Canvas 7 段数码管 (12px 灰度像素, 8×8 网格抖动)
  • 对比度降到 0x01 (极暗)
  • 跳过 WiFi、天气、SHTC3、音频 — 纯时钟
  • 手动切换:长按右键可强制切换日间/夜间显示模式(本次唤醒有效,下次唤醒恢复自动判断)

唤醒机制

唤醒来源 ?wake= 触发条件
PCF85063 外部 RTC 闹钟 rtc IO0 (RTC_INT) 收到 PCF85063 闹钟中断,主要唤醒来路(默认 7:50;Server 可用 alarm.time/api/esp 响应里覆盖,存入 PCF85063 闹钟寄存器)
ESP32-C3 内部 RTC 定时器 rtc PCF85063 不可用 / 未配置 / 闹钟被禁用时的 fallback,由 esp_sleep_enable_timer_wakeup() 触发
GPIO3 右键 (SW12) btn 短按唤醒 → 无网络模式(仅显示时间+温湿度+闹钟时间)
冷启动 (上电/烧录) sys 第一次启动

唤醒源在启动最早期通过 esp_sleep_get_wakeup_cause() 检测,随后拼接到 /api/esp URL 中。

按需联网

只有 RTC 闹钟唤醒才会自动连接 WiFi 并请求 /api/esp 按键唤醒时设备进入无网络模式:

  • 显示当前时间 + 室内温湿度 + 闹钟时间
  • 屏幕底部提示 按左键播放
  • 用户按左键后设备才连接 WiFi 并开始播放
  • 夜间模式下左键操作被忽略

闹钟禁用与周末跳过

Server 可通过 /api/esp 响应中的 alarm 字段控制闹钟行为:

字段 类型 说明
alarm.enabled bool false = 整体关闭——不写 PCF85063 闹钟,ESP 内部 timer 也不启用,仅保留右键唤醒
alarm.weekend_saturday bool false = 周六不触发闹钟
alarm.weekend_sunday bool false = 周日不触发闹钟

注意ESP_SLEEP_WAKEUP_GPIO 这一路会被两个引脚共用——CONFIG_PCF85063_INT_GPIO (IO0) 走 rtc 分支、右键 (IO3) 走 btn 分支(main.c L366-396)。


/api/esp API 规范

请求

GET http://{server}:3000/api/esp/{device_id}?wake={src}&t={temp}&h={humidity}
参数 类型 示例 说明
device_id path 543204470994 ESP32-C3 MAC 地址 (12 hex)
wake query rtc / btn / sys 唤醒源
t query 25.3 室内温度 °C (SHTC3, 可选)
h query 58 室内湿度 %RH (SHTC3, 可选)

响应 JSON

{
  "url": "http://stream.example.com/track.mp3",
  "name": "电台名称",
  "song": "当前歌曲",
  "volume": 50,
  "weather": {
    "temp": "26",
    "text": "小雨",
    "humidity": "85",
    "tempMax": "30",
    "tempMin": "22",
    "textDay": "小雨",
    "textNight": ""
  },
  "alarm": {
    "enabled": true,
    "time": "07:50",
    "weekend_saturday": false,
    "weekend_sunday": true
  }
}
字段 类型 说明
url string 音频流 URL, 为空字符串则不播放
name string 电台/专辑名
song string 当前歌曲名, 优先显示
volume number 音量 0.0–1.0 或 0–100
weather.temp string 当前温度
weather.text string 天气描述 (晴/多云/阴/雨/雪/雾/风 等)
weather.humidity string 室外湿度
weather.tempMax string 今日最高温
weather.tempMin string 今日最低温
weather.textDay string 白天天气
weather.textNight string 夜间天气
alarm.enabled bool 是否启用 PCF85063 闹钟与自动唤醒。true = 启用(按 alarm.time 设闹钟,到点自动唤起);false = 整体关闭——不写 PCF85063 闹钟,且 ESP 内部 timer 也不启用,仅保留右键唤醒
alarm.time string 闹钟时间,"HH:MM" 24h 制(CST 本地时间),写入 PCF85063 闹钟寄存器;缺省回退到 CONFIG_WAKEUP_HOUR/MINUTE
alarm.weekend_saturday bool 周六是否触发闹钟(false = 跳过当天,避免周末被吵醒)
alarm.weekend_sunday bool 周日是否触发闹钟(false = 跳过当天)

响应示例 (无音乐)

{
  "weather": { "temp": "26", "text": "", "humidity": "50", "tempMax": "32", "tempMin": "22", "textDay": "", "textNight": "多云" }
}

url 缺失或为空 → 不启动音频播放, 仅显示天气。

请求时机

sequenceDiagram
    participant ESP as ESP32-C3
    participant API as /api/esp Server
    participant Stream as Audio Stream Server

    Note over ESP: 启动 (任意唤醒源)
    ESP->>API: GET /api/esp/{id}?wake=rtc&t=25.3&h=58
    API-->>ESP: { url, name, song, volume, weather }

    alt url 存在
        ESP->>Stream: HTTP GET audio stream
        Stream-->>ESP: MP3 data
        Note over ESP: I2S 播放
    else url 为空
        Note over ESP: 仅显示天气, 不播放
    end

    Note over ESP: 歌曲结束 (或卡住3秒)
    ESP->>API: GET /api/esp/{id}?wake=rtc&t=25.4&h=57
    API-->>ESP: { url, ... }
    ESP->>Stream: HTTP GET next track

    Note over ESP: 左键长按 (下一首)
    ESP->>API: GET /api/esp/{id}?wake=rtc&t=25.6&h=55
    API-->>ESP: { url, ... }
    ESP->>Stream: HTTP GET new track
Loading

启动阶段只发 一次 HTTP GET: audio_fetch_api() 同时解析天气和电台 URL, audio_play_url() 判断 URL 已缓存则直接播放, 不再重复请求。


无 Agent 模式(配置 Server 地址)

设备支持 完全跳过 Agent 后端 的运行模式——只显示时间 + 室内温湿度,不发起 /api/esp 请求,不播放音频。这种模式在 captive portal(SoftAP 配网页面)上配置。

配置入口

三击右键进入 WiFi 配网页面后,表单最下方多出两项:

字段 说明
配置安睡小方Agent 复选框;未勾选 = 整机退化为无 Agent 模式
Server 地址 文本输入,默认 192.168.8.192(只填 host;端口 :3000 和路径 /api/esp 写死)

行为差异

模式 /api/esp 请求 天气显示 音频播放 屏幕底部
启用 Agent(默认) 电台名 + 歌曲
无 Agent 模式 ❌ 跳过 仅默认图标 ❌ 跳过 仅时间 + 室内温湿度

未勾选复选框时:

  • audio_fetch_api() 直接返回 ESP_ERR_NOT_SUPPORTED,整个 HTTP 流程短路
  • audio_play_url() 同样短路,长按按键不会播放
  • 复选框未勾选但 host 输入框仍保留之前保存的地址——重新勾选即恢复,不必重输

数据存储

字段 NVS namespace Key 类型
Host agent_cfg host string (≤ 64)
启用标志 agent_cfg enabled uint8 (0/1)

wifi_cfgclock 命名空间平行。各命名空间的 NVS 数据互不影响:擦除 WiFi 凭据只动 wifi_cfg,反之亦然。

Host 校验

api_wifi_handler 在保存前调用 sanitize_host()

  • 空字符串 / NULL192.168.8.192
  • 包含 :/、空格 → 192.168.8.192(回退到默认 + 写一条 WARN)

/api/esp 的端口 :3000 和路径 /api/esp 是与后端的契约,用户不可配置

重新配置

三击右键 → 恢复出厂设置 + 重启 → SoftAP 配网页面 → 提交新表单 → 设备保存到 NVS → 自动重启。重启后从 NVS 重新读取 WiFi 凭据 + Agent 配置。


温度传感器 (SHTC3)

flowchart LR
    A[主循环 每10秒] --> B[shtc3_read]
    B --> C{测量成功?}
    C -->|是| D[audio_set_indoor_env<br/>缓存温度+湿度]
    D --> E[clock_screen_set_indoor_env<br/>更新屏幕显示]
    C -->|失败| F[保留上次值<br/>3次重试后放弃本周期]
Loading
  • 芯片: Sensirion SHTC3 (I2C, 0x70)
  • 引脚: GPIO9 (SCL), GPIO21 (SDA)
  • 读取频率: 每 10 秒
  • 容错: 每次读取尝试 3 种策略 (正常 → 软复位 → Clock Stretching), 失败后跳过本次, 10 秒后自动重试
  • 数据用途: 屏幕显示 (内25.3°58%) + 作为 ?t=&h= 参数随下次 /api/esp 请求发送

软件架构

graph TB
    subgraph Entry
        MAIN[main.c]
    end

    subgraph Display
        SSD1322[ssd1322_driver.c<br/>SPI 驱动]
        LVGL_ADAPT[lvgl_adapter.c<br/>L8→I4 DMA]
        CLOCK[clock_screen.c<br/>主界面]
        CONFIG_SCREEN[config_screen.c<br/>首次配网页面]
        FONT_D[font_digital.c<br/>时钟数字 48px]
        FONT_S[font_station.c<br/>通用中文 10px<br/>11031 CJK 全字集]
    end

    subgraph Network
        WIFI[wifi.c<br/>STA + SNTP]
        WIFI_PROV[wifi_provisioning.c<br/>SoftAP + captive portal]
        HTTP[esp_http_client<br/>HTTPS/HTTP]
        JSON[cJSON 解析]
    end

    subgraph Audio
        AUDIO_WRAP[audio_player_wrapper.c]
        MIXER[audio_mixer]
        MP3[esp-libhelix-mp3]
        I2S[esp_driver_i2s]
        NS4168[NS4168 功放]
    end

    subgraph Sensor
        SHTC3[shtc3.c<br/>I2C 温湿度]
        PCF85063[pcf85063.c<br/>I2C RTC + 闹钟]
    end

    subgraph Config
        AGENT_CFG[agent_config.c<br/>NVS agent_cfg]
    end

    subgraph UI_FW
        EEZ[screens.c / ui.c]
    end

    MAIN --> SSD1322
    MAIN --> LVGL_ADAPT
    MAIN --> CLOCK
    MAIN --> CONFIG_SCREEN
    MAIN --> WIFI
    MAIN --> WIFI_PROV
    MAIN --> AUDIO_WRAP
    MAIN --> SHTC3
    MAIN --> PCF85063

    LVGL_ADAPT --> SSD1322
    CLOCK --> FONT_D
    CLOCK --> FONT_S
    CLOCK --> EEZ

    AUDIO_WRAP --> HTTP
    AUDIO_WRAP --> JSON
    AUDIO_WRAP --> MIXER
    AUDIO_WRAP --> MP3
    AUDIO_WRAP --> AGENT_CFG
    MIXER --> I2S
    MP3 --> MIXER
    I2S --> NS4168
Loading

核心模块

模块 文件 说明
入口 main.c 初始化 + 双键事件循环 + 深度睡眠 + 唤醒检测 + 按需联网
显示驱动 ssd1322_driver.c/h SSD1322 SPI 命令, 复位序列, 对比度控制
LVGL 适配 lvgl_adapter.c/h LVGL flush callback, L8→I4 格式转换
WiFi/对时 wifi.c/h STA 连接, SNTP 同步, 设备 ID (MAC)
WiFi 配网 wifi_provisioning.c/h SoftAP + DNS 重定向 + captive portal + QR
首次配网页面 config_screen.c/h 首次启动 QR 码页面(无 NVS 凭据时替代时钟页面)
Agent 配置 agent_config.c/h NVS agent_cfg 命名空间, host + enabled
天气/电台 API audio_player_wrapper.c/h /api/esp HTTP + JSON 解析 + I2S 音频播放 + 闹钟配置
屏幕 UI clock_screen.c/h 时间/天气/温度/歌名布局 + Canvas 绘制 + 按键提示
PCF85063 RTC components/pcf85063/pcf85063.c/h I²C RTC 读写, 闹钟配置, 中断清除
SHTC3 驱动 components/shtc3/shtc3.c/h I²C 传感器读取, CRC8 校验
UI 框架 ui/screens.c, ui/ui.c EEZ Studio 生成 (实际 UI 在 clock_screen.c + config_screen.c)
数字字体 font_digital.c/h digital-7 48px 4bpp (时钟)
通用字体 font_station.c/h fusion-pixel 10px 1bpp (11031 CJK + ASCII + 标点)

构建

# 环境 (ESP-IDF v5.5.2)
. ~/esp/v5.5.2/esp-idf/export.sh

# 构建
idf.py build

# 配置 (WiFi, API keys, GPIO, 夜间模式, 睡眠参数)
idf.py menuconfig

# 烧录 & 监视
idf.py -p /dev/ttyUSB0 flash
idf.py -p /dev/ttyUSB0 monitor

分区表

分区 大小 说明
bootloader 32KB
partition table 4KB
nvs 24KB WiFi 凭证等
phy_init 4KB
factory 4032K (3.94MB) 单 app 分区, 最大化利用 4MB Flash

字体生成

lv_font_conv --size 10 --bpp 1 --format lvgl --no-compress --lv-include lvgl.h \
  --font assets/fonts/fusion-pixel-10px-monospaced-zh_hans.ttf \
  -r 0x0020-0x007F -r 0x00A0-0x00FF -r 0x2000-0x206F \
  -r 0x3000-0x303F -r 0xFF00-0xFFEF \
  -r 0x4E00-0x9FFF -r 0x3400-0x4DBF \
  --output main/font_station.c --lv-font-name lv_font_station

Unicode 范围覆盖: Basic Latin, Latin-1 Supplement, General Punctuation, CJK 标点, 全角字符, CJK 统一汉字 (GB2312/GB18030)


配置

idf.py menuconfig → SlumberCube Configuration

分类 选项 说明
WiFi SSID, 密码
Sleep 活跃时长, 唤醒 GPIO, 闹钟时间 默认 1800s, GPIO3, 7:50
Night 开始/结束小时 默认 23→6
Audio 默认音量 0–100 (默认 10)
GPIO SPI/I2S/NS4168/左键/右键 右键 GPIO3, 左键 GPIO1
I²C SDA/SCL/频率 GPIO21/GPIO9/400kHz
PCF85063 RTC 启用/I²C 地址/INT 引脚 默认启用, 0x51, IO0
WiFi 配网 SoftAP 密码/超时/首次自动配网 默认 5min, 首次自动

首次启动与配网

设备首次上电(或恢复出厂设置后),若 NVS 中没有 WiFi 凭据:

  1. 显示 QR 码配网页面(替代时钟页面),展示 SSID SlumberCube-XXXX 和二维码
  2. 启动 SoftAP + captive portal,手机连接 WiFi 后自动弹出配置页面
  3. 配置页面可填写:WiFi SSID/密码、Agent Server 地址、是否启用 Agent
  4. 提交后凭据写入 NVS → 自动重启 → 进入正常时钟模式
  5. 若超时(默认 5 分钟)未提交,设备进入 clock-only 模式(仅显示时间)

配网页面可通过三击右键重新进入(会先恢复出厂设置清除所有 NVS 数据)。

防白闪机制

深度睡眠唤醒时, SSD1322 GDDRAM 内容随机, 如果显示过早打开会出现白闪。

修复策略 (多层防护):

  1. 睡眠前 GPIO hold 拉低 RST → SSD1322 在睡眠期间保持复位
  2. ssd1322_init() 复位后立即发 0xAE → 显示关断
  3. 加载正确页面后调用 lv_refr_now() 同步刷新 → GDDRAM 写入用户黑底界面
  4. 首帧渲染完成后才调用 ssd1322_display_on() → GDDRAM 中已是正确内容

依赖

组件 说明
lvgl/lvgl ^9.4 图形库
espressif/button ^4.1 GPIO 按键
chmorgan/esp-libhelix-mp3 MP3 解码
esp-audio-player 音频框架 (HTTP 流 + 混音器 + I2S)
ESP-IDF >=5.0 开发框架

硬件设计文件

文件 路径
原理图 (PDF, 2026-06-27) assets/hardware/SCH_Schematic1_9_2026-06-27.pdf
3D 外壳 (Shapr3D 原生) assets/hardware/安睡小方.shapr
3D 外壳 (STEP 通用格式) assets/hardware/安睡小方.step
Gerber 文件 待生成(基于 2026-06-27 原理图)

SlumberCube 安睡小方 · 固件 v2.3 · 2026-07-05 · 原理图 Schematic1_9

About

SlumberCube 安睡小方 — ESP32-C3 床头睡眠时钟,SSD1322 OLED 灰度屏,WiFi 对时 + 天气 + 电台流 + 深度休眠

Resources

Stars

1 star

Watchers

1 watching

Forks

Packages

 
 
 

Contributors

Languages