Skip to main content

Power module

Power puts the board to sleep so that it uses less power: sleep() puts it in light sleep mode until one of the sources you set wakes it up: a time, an RTC pin or one or several GPIO pins. When it wakes up, the program carries on right after sleep(), with all its variables. It is useful in devices that run on a battery or a solar panel.

On Windows it is simulated: sleep() waits and wakeReason() always says the timer woke it up, so that you can test the logic of the program before taking it to the board.

Illustration of the JARU Power module for putting the board to sleep and waking it up

use Power

To put the board to sleep, set one or more wake-up sources (wakeOnTimer, wakeOnPin or wakeOnGPIO) and call sleep().

Platforms​

WindowsESP32 / ESP32-S3ESP32-P4ESP32-S31
sleep()Waits the time of wakeOnTimer(), only the first time; without it, 100 msPuts the board in light sleepPuts the board in light sleepPuts the board in light sleep
wakeOnPin()Does nothingAn RTC pin; wakes up with WAKE_EXT0An RTC pin; wakes up with WAKE_EXT1An RTC pin; wakes up with WAKE_EXT1
wakeOnGPIO()Does nothing, and does not check the pinAny pinAny pinAny pin
wakeReason()Always WAKE_TIMERThe cause of the last wake-upThe cause of the last wake-upThe cause of the last wake-up
  • On the board, each run of the program starts with no wake-up sources, even if the board has not restarted: the ones the previous program set do not count.
  • On the board, sleep() waits 100 ms before sleeping, so that whatever is left to print gets out, and another 100 ms after waking up.
The Waveshare ESP32-S3-Touch-LCD-2.8 loses its USB when it sleeps

This board connects to the PC through the chip's own USB. From the first Power.sleep(), the PC no longer sees it: nothing reaches the serial monitor and nothing can be flashed to it. To flash it again, start it in download mode: restart it with the BOOT button held down. If you are going to put it to sleep, test the program without Power.sleep() first.

Functions​

FunctionWhat it doesReturns
wakeOnTimer(microseconds)Wakes the board up after a while.true or false
wakeOnPin(pin, level)Wakes the board up with an RTC pin.true or false
wakeOnGPIO(pin, level)Wakes the board up with any pin; you can set several.true or false
sleep()Puts the board to sleep until one of the sources wakes it up.true or false
wakeReason()Tells what woke the board up last time.One of the constants

The errors are not thrown: they are returned, as a value: with the wrong number of arguments, ERR_INVALID_ARG_NUMBER, and with an argument that is not a number, ERR_TYPE_MISMATCH. On the board, they are also written to the serial monitor. More on error values in Errors and exceptions.

wakeOnTimer​

wakeOnTimer(microseconds) sets a timer as a wake-up source: the board wakes up when that time has passed.

use Power

// Wake up after 5 seconds (5000000 microseconds)
Power.wakeOnTimer(5000000)
Power.sleep()

println("Awakened by the timer!")

Parameters:

  • microseconds: the time until waking up, in microseconds (integer or decimal; the whole part counts).

Returns: true if it set it, false if not.

Seconds to microseconds

Multiply the seconds by a million: 30 seconds are 30000000 microseconds. Call wakeOnTimer() before each sleep(): on Windows, the time only applies to the next sleep().

wakeOnPin​

wakeOnPin(pin, level) sets an RTC pin as a wake-up source: the board wakes up when the pin reaches that level.

use Power

// Wake up when pin 33 goes HIGH
Power.wakeOnPin(33, HIGH)
Power.sleep()

println("Awakened by the pin!")

Parameters:

  • pin: GPIO pin number (it has to be an RTC pin)
  • level: the level that wakes the board up (HIGH or LOW)

Returns: true if it set it, false if not (for example, with a pin that is not RTC).

RTC pins

Only the RTC pins work with wakeOnPin(). On the ESP32 they are 0, 2, 4, 12, 13, 14, 15, 25, 26, 27, 32, 33, 34, 35, 36, 37, 38 and 39. On the other boards, look up which pins are RTC in the documentation of their chip. To use any pin, or several, there is wakeOnGPIO().

On the ESP32 and the ESP32-S3, the board wakes up with WAKE_EXT0; on the ESP32-P4 and the ESP32-S31, with WAKE_EXT1.

wakeOnGPIO​

The wakeOnGPIO(pin, level) function configures a GPIO pin as a wake-up source. Unlike wakeOnPin(), it works with any pin, not just the RTC ones, and you can set several: each call adds one.

use Power
use GPIO

// Two buttons between the pin and GND, with the internal pull-up to 3.3 V
GPIO.pinmode(32, GPIO.PULLUP)
GPIO.pinmode(33, GPIO.PULLUP)

// Wake up when either of them is pressed
Power.wakeOnGPIO(32, LOW)
Power.wakeOnGPIO(33, LOW)
Power.sleep()

println("Awakened by a button!")

Parameters:

  • pin: GPIO pin number
  • level: the level that wakes the board up (HIGH or LOW)

Returns: true if it set it, false if the pin doesn't exist on the board.

Keep in mind
  • Each call adds a pin, or changes its level if it was already set. The pins stay set for the following sleep() calls.
  • Configure the pin as an input with GPIO.pinmode() first.
  • If the pin is already at that level when you call sleep(), the board doesn't go to sleep: sleep() returns false right away. With a button, wait until it's released before going back to sleep.
  • If the pin also has a GPIO.onInterrupt() interrupt, the interrupt keeps working after waking up.

sleep​

sleep() puts the board in light sleep, the low-power mode, until one of the sources you set wakes it up.

use Power

// Wake up with the timer
Power.wakeOnTimer(10000000) // 10 seconds

println("Entering sleep mode...")
Power.sleep()
println("Awakened!")

Returns: true if the board has slept, false if it did not get to sleep (for example, because a wakeOnGPIO() pin was already at its level).

Light sleep and deep sleep

Light sleep keeps the state of the CPU and the RAM, so the program carries on right where it left off. Deep sleep restarts the whole program. The Power module only does light sleep.

wakeReason​

The wakeReason() function returns the cause of the last wake-up. This allows the program to take different actions depending on what triggered the wake-up.

use Power

// Check wake-up cause
var reason = Power.wakeReason()

if (reason == Power.WAKE_TIMER) then
println("Awakened by timer")
elsif (reason == Power.WAKE_EXT0) then
println("Awakened by RTC pin")
elsif (reason == Power.WAKE_GPIO) then
println("Awakened by GPIO")
else
println("Unknown reason or first boot")
end

Returns: an integer that corresponds to one of the wake-up cause constants.

Constants​

The wake-up causes that wakeReason() returns:

ConstantValueWhat woke the board up
Power.WAKE_UNDEFINED0Nothing defined: it is the device's first boot, or the cause is unknown.
Power.WAKE_TIMER2The timer configured with wakeOnTimer().
Power.WAKE_EXT03An RTC pin (ext0): it's what wakeOnPin() uses on the ESP32 and the ESP32-S3.
Power.WAKE_EXT14An RTC pin (ext1): it's what wakeOnPin() uses on the ESP32-P4 and the ESP32-S31.
Power.WAKE_GPIO6A GPIO configured with wakeOnGPIO().
Power.WAKE_UART7Activity on the UART port. Power has no function to set it as a source.
use Power

if (Power.wakeReason() == Power.WAKE_UNDEFINED) then
println("First boot or unknown cause")
end

Full example​

Sensor with power saving​

It reads a sensor every 30 seconds, or when a button is pressed, and sleeps between readings with the screen off.

use Power
use GPIO
use Display

// Initial setup
Display.open(320, 240)
var draw = Display.draw

// The sensor, on pin 34
GPIO.pinmode(34, GPIO.INPUT)

// Reading interval: 30 seconds
var interval = 30000000

func showTemperature(temp)
draw.cls(0x000000)
draw.color = 0x00FF00
draw.text(60, 100, "Temperature: " + temp.toString() + " C")
Display.update()
end

func readSensor()
// A simulated temperature reading
return 20 + (GPIO.aread(34) / 100)
end

// Main loop
while (true)
// What woke it up?
var reason = Power.wakeReason()

if (reason == Power.WAKE_TIMER) then
println("Scheduled reading")
elsif (reason == Power.WAKE_EXT0) then // WAKE_EXT1 on the ESP32-P4 and the ESP32-S31
println("Reading asked for with the button")
end

// Read and show the temperature
var temp = readSensor()
showTemperature(temp)

// Two seconds to see the screen
pause(2000)

// The wake-up sources
Power.wakeOnTimer(interval)
Power.wakeOnPin(33, HIGH) // the reading button

// Turn the screen off and sleep
Display.backlight(0)
Power.sleep()

// When it wakes up, turn the screen on
Display.backlight(1)
end

Motion detector​

A PIR sensor wakes the board up, which sends a notice over MQTT and goes back to sleep.

use Power
use GPIO
use MQTT

// The PIR sensor pin
var pirPin = 27

// The MQTT broker connection (server, port, credentials) is set in the board profile

// Wake up with the sensor
Power.wakeOnPin(pirPin, HIGH)

while (true)
// Did it wake up because of the motion? (WAKE_EXT1 on the ESP32-P4 and the ESP32-S31)
if (Power.wakeReason() == Power.WAKE_EXT0) then
println("Motion detected!")
MQTT.publish("home/alarm", "motion")

// Wait for the sensor to settle
pause(5000)
end

// Go back to sleep
Power.wakeOnPin(pirPin, HIGH)
Power.sleep()
end

Pitfalls and known issues​

  • On Windows nothing sleeps: sleep() only waits, and wakeReason() always returns WAKE_TIMER, also before the first sleep().
  • The time of wakeOnTimer() is in microseconds, not in milliseconds like pause() or Timer.
  • wakeOnPin() wakes up with WAKE_EXT0 or with WAKE_EXT1 depending on the chip. If your program goes to several boards, compare with both.
  • With a wakeOnGPIO() pin already at its level, the board does not go to sleep: sleep() returns false right away.
  • The Waveshare ESP32-S3-Touch-LCD-2.8 loses its USB when it sleeps: see Platforms.
  • Errors are returned, not thrown: try does not catch them.

All the known issues of JARU, together, are in Known issues.