模块: sleep
约 4274 字大约 14 分钟
2026-08-26
构建固件和导入到JS
在 C++ 里加入以下代码, 然后重新编译构建固件:
// 为了控制固件的尺寸,BeShell 的 module 是按需引入的。
beshell.use<be::Sleep>() ;在JS中导入 sleep module:
import * as sleep from 'sleep'import sleep简介
系统睡眠模块, 提供 ESP32 的 light/deep/modem 睡眠以及各种唤醒源的设置
三种睡眠方式在调用逻辑上有本质区别:
light()/modem(): 同步阻塞函数。调用后当前 JS 线程挂起 (事件循环停止, 定时器/网络回调等不再执行), 直到唤醒源触发才返回, 返回值为唤醒源字符串, 之后的代码继续执行, JS 运行环境完全保留deep(): 调用后不会返回。唤醒时设备整体重启, 脚本从头重新执行, JS 运行环境无法恢复, 唤醒原因需在重启后用wakeupCause()查询
唤醒源字符串: "timer" "ext0" "ext1" "gpio" "uart" "touch" "wifi.data" "wifi.disconnected" "wifi.beacon-timeout" 等
示例:
import * as sleep from "sleep"
// 1. 最简单的 light sleep: 睡 5 秒 (同步阻塞, 5 秒后才执行下一行)
let source = sleep.light(5000)
console.log("wakeup source:", source) // "timer"
// 2. light sleep + 按钮唤醒: 定时与 GPIO 唤醒源叠加, 任一触发即返回
import * as gpio from "gpio"
gpio.setMode(4, "input")
gpio.pull(4, "up")
sleep.enableLightGPIOWakeup(4, 0) // GPIO 4 接地时唤醒
source = sleep.light(60000) // 最多睡 60 秒, 按钮可提前唤醒
console.log("wakeup source:", source) // "gpio" 或 "timer"
// 3. deep sleep: 睡 1 小时后重启 (此行之后的代码不会执行)
// 需要跨睡眠保存的数据先写入 NVS
sleep.deep(3600_000)
console.log("这行永远不会执行")
// 4. deep sleep + 按钮唤醒, 重启后判断唤醒原因
// (脚本开头)
if(sleep.wakeupCause() == "ext0") {
console.log("被按钮唤醒")
}
// ... 正常工作逻辑 ...
sleep.enableExt0Wakeup(33, 1) // GPIO 33 高电平唤醒
sleep.deep() // 不返回, 唤醒即重启
// 5. modem sleep: 保持 WiFi 连接的睡眠, 有下行数据时唤醒
// (要求 WiFi STA 已连接)
source = sleep.modem(10000) // 有下行数据或 10 秒超时返回
console.log("wakeup source:", source) // "wifi.data" / "timer" / ...模块函数
函数 light
原型: light (ms:number=)
进入 light sleep (轻睡眠)
这是一个同步阻塞函数: 调用后 CPU 暂停执行, 当前 JS 线程挂起, 事件循环停止运转 (setTimeout/Promise 回调/网络事件等都不会执行)。 唤醒源触发后函数才返回唤醒源字符串, 其后的语句继续执行; SRAM/PSRAM 数据保持, beshell/QuickJS 以及 mongoose 等网络库的状态完全保留。 请勿用 sleep.light(ms).then(...) 之类的异步方式调用。
传入 ms 参数等价于先调用 enableTimerWakeup(ms) 再进入睡眠; 不传参数则一直睡眠, 直到已配置的唤醒源触发。
警告: 不传
ms且没有配置任何唤醒源时, 将永远无法唤醒。
警告: 在 ESP32-S3/C3/C6 等芯片上, 若使用原生 USB (USB Serial/JTAG) 作为 console, 当前版本的 light() 返回后 USB REPL 将失效: 唤醒后 USB 串口无法恢复 (重连串口、物理拔插均可能无法识别设备, 通常需重启 设备才能恢复)。这是 ESP-IDF 官方已知限制: 该类芯片的 USJ 外设不支持 light sleep 保活 (见 ESP-IDF 文档 Light-sleep Limitations); 本模块曾 尝试 BBPLL 保活 + 唤醒后复位 USJ/模拟拔插强制重枚举, 均无法稳定恢复。 如需保留 USB REPL 请改用 deep() (唤醒即重启, USB 正常重新枚举)。 UART0 串口 console 不受此问题影响。
唤醒后将唤醒源字符串作为返回值。
示例:
import * as sleep from "sleep"
// 定时 5 秒唤醒
let source = sleep.light(5000)
console.log("wakeup source:", source)
// 由 GPIO 唤醒
sleep.enableLightGPIOWakeup(4, 0)
source = sleep.light()
console.log("wakeup source:", source) // "gpio"参数:
ms
类型number
默认值
参数说明定时唤醒时间, 单位毫秒, 可选
返回值:
类型string
说明唤醒源, 如 "timer"|"ext0"|"ext1"|"gpio"|"uart"|"touch"|"wifi" 等
函数 deep
原型: deep (ms:number=)
进入 deep sleep (深度睡眠)
此函数不会返回, 调用即意味着重启: CPU、SRAM、PSRAM 全部断电, 仅 RTC 域保持供电。唤醒后设备从入口函数整体重启, 脚本从头开始执行, JS 运行环境无法恢复, 写在 deep() 调用之后的代码永远不会执行到。 重启后可用 wakeupCause() 或 process.resetReason() 查询唤醒原因。
需要跨睡眠保存的数据请使用 NVS (nvs 模块)。
传入 ms 参数等价于先调用 enableTimerWakeup(ms) 再进入睡眠; 不传参数则一直睡眠, 直到已配置的唤醒源触发或外部复位。
警告: 不传
ms且没有配置任何唤醒源时, 只能断电或复位唤醒。
提示: deep sleep 唤醒即重启, USB (USB Serial/JTAG) console 会随启动 正常重新枚举, 不存在 light() 的 USB REPL 失效问题。
示例:
import * as sleep from "sleep"
// 1 分钟后唤醒(重启)
sleep.deep(60000)
// 按钮唤醒 (ext0, GPIO 33 高电平)
sleep.enableExt0Wakeup(33, 1)
sleep.deep()参数:
ms
类型number
默认值
参数说明定时唤醒时间, 单位毫秒, 可选
返回值:
类型undefined
说明此函数不会返回
函数 modem
原型: modem (ms:number=, mode:string="min")
进入 modem sleep (保持 WiFi 连接的睡眠)
开启 WiFi 省电模式(PS Mode)并使能 WiFi 唤醒后进入 light sleep。 睡眠期间 WiFi 连接保持, AP 会为设备缓存下行数据。
唤醒过滤: 仅为监听 beacon 的协议性唤醒(TBTT/DTIM)不会返回, 函数内部会继续睡眠, JS 无感知。只有以下情况会返回:
"wifi.data": 收到下行数据帧"wifi.disconnected": 被 AP 断开连接"wifi.beacon-timeout": beacon 超时- 其他唤醒源字符串: 如
"timer""gpio"等(睡前配置的其他唤醒源)
注意:
- 调用前 WiFi STA 必须已连接。
- 睡眠期间 JS 事件循环不运转, mongoose 等网络库的回调在唤醒返回后才会执行。
- 强制 light sleep 不与 WiFi 驱动协调, 单次睡眠时间不宜过长, 否则可能掉线。
wifi.data检测依赖 STA netif "WIFI_STA_DEF", 非默认 netif 时该检测不可用。- 返回后 WiFi 省电模式保持开启, 可用
wifi.setPS(0)关闭。- 若使用原生 USB (USB Serial/JTAG) console, modem() 返回后 USB REPL 同样会失效 (与 light() 相同), 详见
light()的警告说明。
示例:
import * as sleep from "sleep"
// 保持 WiFi 连接睡眠, 有下行数据或 10 秒超时唤醒
let source = sleep.modem(10000)
console.log("wakeup source:", source) // "wifi.data" / "timer" / ...
// 最大省电模式, 只在 DTIM 周期监听
source = sleep.modem(10000, "max")参数:
ms
类型number
默认值
参数说明最长睡眠时间, 单位毫秒, 可选
mode
类型string
默认值"min"
参数说明WiFi 省电模式, "min"(每个 beacon 周期监听) 或 "max"(按 DTIM/listen interval 监听, 更省电但延迟更高)
异常:
- WiFi 未连接或芯片不支持 WiFi 唤醒时抛出异常
返回值:
类型string
说明唤醒原因, 如 "wifi.data"|"wifi.disconnected"|"wifi.beacon-timeout"|"timer"|"gpio" 等
函数 enableTimerWakeup
原型: enableTimerWakeup (ms:number)
设置定时唤醒 (light sleep 和 deep sleep 均有效)
多个唤醒源可以叠加, 任一触发即唤醒。
示例:
import * as sleep from "sleep"
sleep.enableTimerWakeup(10000) // 10 秒后唤醒
sleep.light()参数:
ms
类型number
参数说明定时唤醒时间, 单位毫秒
返回值:
类型undefined
函数 enableExt0Wakeup
原型: enableExt0Wakeup (pin:number, level:number)
设置 EXT0 唤醒: 单个 RTC GPIO 电平唤醒 (light sleep 和 deep sleep 均有效)
只能监听一个引脚, 引脚必须具有 RTC 功能 (可用 isValidWakeupGPIO() 检查)。 当引脚电平等于指定电平时唤醒。
注意: 部分新芯片 (如 ESP32-C3) 不支持 EXT0, 此时抛出异常, 可改用
enableExt1Wakeup()或enableDeepGPIOWakeup()。
示例:
import * as sleep from "sleep"
// GPIO 33 高电平唤醒
sleep.enableExt0Wakeup(33, 1)
sleep.deep()参数:
pin
类型number
参数说明RTC GPIO 引脚号
level
类型number
参数说明触发电平, 0=低电平唤醒, 1=高电平唤醒
异常:
- 芯片不支持 EXT0 或引脚不是 RTC GPIO 时抛出异常
返回值:
类型undefined
函数 enableExt1Wakeup
原型: enableExt1Wakeup (pins:Array<number>, mode:string)
设置 EXT1 唤醒: 多个 RTC GPIO 电平唤醒 (light sleep 和 deep sleep 均有效)
可同时监听多个引脚, 引脚必须具有 RTC 功能。 唤醒后可用 ext1WakeupPins() 查询是哪个引脚触发的。
触发模式:
"any-high": 任一引脚为高电平时唤醒"all-low": 所有引脚都为低电平时唤醒 (仅 ESP32; 其他芯片上等同于 "any-low")"any-low": 任一引脚为低电平时唤醒 (ESP32 不支持)
注意: RTC 外设断电时内部上下拉失效, 需要外部上下拉电阻, 或配置 RTC 外设电源保持。
示例:
import * as sleep from "sleep"
// GPIO 32 或 33 任一变为高电平时唤醒
sleep.enableExt1Wakeup([32, 33], "any-high")
sleep.deep()
// (重启后)
console.log(sleep.ext1WakeupPins()) // 例如 [33]参数:
pins
类型Array<number>
参数说明RTC GPIO 引脚号数组
mode
类型string
参数说明触发模式, "any-high"|"all-low"|"any-low"
异常:
- 芯片不支持 EXT1 或引脚不是 RTC GPIO 时抛出异常
返回值:
类型undefined
函数 enableLightGPIOWakeup
原型: enableLightGPIOWakeup (pin:number, level:number)
设置 GPIO 唤醒, 仅对 light sleep 有效
与 EXT0/EXT1 不同, 此方式可以使用任意 GPIO (不要求 RTC 功能)。
注意: 此函数不修改引脚配置。引脚必须事先用 gpio 模块配置为 输入模式并设置好上下拉 (低电平唤醒建议上拉, 高电平唤醒建议下拉), 否则浮空电平可能导致无法唤醒或进不了睡眠 (ESP_ERR_SLEEP_REJECT)。
示例:
import * as gpio from "gpio"
import * as sleep from "sleep"
// GPIO 4 低电平唤醒: 输入模式 + 上拉, 接地即可唤醒
gpio.setMode(4, "input")
gpio.pull(4, "up")
sleep.enableLightGPIOWakeup(4, 0)
sleep.light()参数:
pin
类型number
参数说明GPIO 引脚号
level
类型number
参数说明触发电平, 0=低电平唤醒, 1=高电平唤醒
返回值:
类型undefined
函数 enableLightUARTWakeup
原型: enableLightUARTWakeup (uartNum:number)
设置 UART 唤醒, 仅对 light sleep 有效
当 UART RX 引脚上检测到一定数量的正跳变沿时唤醒。 跳变沿数量阈值需事先用 UART 驱动的 uart_set_wakeup_threshold 设置。
注意: 唤醒需要一定时间, 睡眠期间收到的数据可能丢失, 适合"唤醒后再通信"的场景。
示例:
import * as sleep from "sleep"
sleep.enableLightUARTWakeup(1) // UART1 唤醒
sleep.light()参数:
uartNum
类型number
参数说明UART 端口号
异常:
- 该 UART 不支持唤醒时抛出异常
返回值:
类型undefined
函数 enableLightWiFiWakeup
原型: enableLightWiFiWakeup ()
设置 WiFi 唤醒, 仅对 light sleep 有效
使能后 WiFi MAC 可以在收到数据或需要处理时唤醒 CPU。 通常不需要直接调用, 使用 modem() 更方便 (自动设置省电模式和唤醒过滤)。
注意: 需要先开启 WiFi 省电模式, 如
wifi.setPS(1)。
异常:
- 芯片不支持 WiFi 唤醒时抛出异常
返回值:
类型undefined
函数 enableLightBTWakeup
原型: enableLightBTWakeup ()
设置蓝牙唤醒, 仅对 light sleep 有效
异常:
- 芯片不支持蓝牙唤醒时抛出异常
返回值:
类型undefined
函数 enableDeepGPIOWakeup
原型: enableDeepGPIOWakeup (pins:Array<number>, mode:string)
设置 GPIO 唤醒, 仅对 deep sleep 有效 (仅 ESP32-C3/S3 等新芯片支持)
老芯片 (ESP32) 请使用 enableExt0Wakeup() / enableExt1Wakeup()。
示例:
import * as sleep from "sleep"
// GPIO 2 低电平唤醒 (ESP32-S3)
sleep.enableDeepGPIOWakeup([2], "low")
sleep.deep()参数:
pins
类型Array<number>
参数说明RTC GPIO 引脚号数组
mode
类型string
参数说明触发电平, "low"|"high"
异常:
- 芯片不支持 deep sleep GPIO 唤醒时抛出异常
返回值:
类型undefined
函数 enableTouchWakeup
原型: enableTouchWakeup ()
设置触摸唤醒 (light sleep 和 deep sleep 均有效)
注意: 触摸通道需要先通过触摸驱动初始化和配置, 此函数仅使能触摸唤醒源。
异常:
- 芯片不支持触摸唤醒时抛出异常
返回值:
类型undefined
函数 enableULPWakeup
原型: enableULPWakeup ()
设置 ULP 协处理器唤醒 (light sleep 和 deep sleep 均有效)
注意: 需要事先加载并启动 ULP 程序, 此函数仅使能 ULP 唤醒源。
异常:
- 芯片不支持 ULP 时抛出异常
返回值:
类型undefined
函数 disableWakeupSource
原型: disableWakeupSource (source:string)
禁用指定的唤醒源
示例:
import * as sleep from "sleep"
sleep.disableWakeupSource("timer") // 禁用定时唤醒
sleep.disableWakeupSource("all") // 禁用所有唤醒源参数:
source
类型string
参数说明唤醒源, "all"|"ext0"|"ext1"|"timer"|"touch"|"ulp"|"gpio"|"uart"|"wifi"|"bt"
异常:
- 未知的唤醒源或该唤醒源未使能时抛出异常
返回值:
类型undefined
函数 wakeupCause
原型: wakeupCause ()
查询上次睡眠的唤醒原因
deep sleep 唤醒后系统重启, 可在启动时用此函数查询本次启动是否由睡眠唤醒导致。
示例:
import * as sleep from "sleep"
const cause = sleep.wakeupCause()
if(cause == "timer") {
console.log("被定时器唤醒")
} else if(cause == "undefined") {
console.log("正常上电启动")
}返回值:
类型string
说明唤醒原因, "undefined"|"ext0"|"ext1"|"timer"|"touch"|"ulp"|"gpio"|"uart"|"wifi"|"bt"|"cocpu" 等
函数 ext1WakeupPins
原型: ext1WakeupPins ()
查询触发 EXT1 唤醒的引脚
如果上次唤醒不是 EXT1 导致的, 返回空数组。
示例:
import * as sleep from "sleep"
if(sleep.wakeupCause() == "ext1") {
console.log("wakeup pins:", sleep.ext1WakeupPins()) // 例如 [33]
}异常:
- 芯片不支持 EXT1 时抛出异常
返回值:
类型Array<number>
说明触发唤醒的 GPIO 引脚号数组
函数 isValidWakeupGPIO
原型: isValidWakeupGPIO (pin:number)
检查引脚是否可作为唤醒源 (是否具有 RTC 功能)
示例:
import * as sleep from "sleep"
if(sleep.isValidWakeupGPIO(33)) {
sleep.enableExt0Wakeup(33, 1)
}参数:
pin
类型number
参数说明GPIO 引脚号
返回值:
类型boolean
说明是否可用于唤醒
