Raspberry Pi 2 W power saving configuration. - Digital-Waters/WaterMonitorDevice GitHub Wiki

Many of these techniques are paraphrased from Jean-Luc Afranc's writeup.

By disabling unused services and turning off unused features of the chip via the overlays, it seems possible to reduce the power consumption of the Rpi. Jean Luc's numbers suggest that he was able to get the unit down to an idle current of around 74mA. His best numbers had energy consumption of around 468 mWh but our use case is different and his setup was a little unclear to me. I've seen lower numbers quoted in other places, especially with the USB turned off. Wifi also seems to consume about 19mA. There are some notes as well that suggest powering the unit from 3.3V may also save power.

Adjust boot configuration

  • Navigate to /boot/firmware

cd /boot/firmware

  • Edit the config file with your choice of editors (you'll have to use sudo):

sudo vi config.txt

  • Turn off audio:

dtparam=audio=off

  • Turn off display autodetect:

display_auto_detect=0

  • Turn off composite video
# disable composite video output
enable_tvout=0
  • Turn off HDMI support by commenting out the dtoverlay line (this is necessary for disabling the real power hog later):
# Enable DRM VC4 V3D driver
#dtoverlay=vc4-kms-v3d
max_framebuffers=2
  • Turn off boost mode:

arm_boost=0

  • and reduce the CPU clock speed:

arm_freq=600

  • Disable bluetooth

dtoverlay=disable-bt

  • Turn off power LED
[all]
dtparam=act_led_trigger=default-off
  • Turn off the console UART:
[all]
dtparam=act_led_trigger=default-off
enable_uart=0
  • Script-based LED turn off:

$ echo none | sudo tee /sys/class/leds/ACT/trigger

Additional script based power savings (post-boot)

These can (should) be added as a systemd service. Details to follow.

HDMI

Turn off the HDMI drivers. This depends on using the Bullseye release of the OS. It will not work with Bookworm. Note that you'll have to comment out the dtoverlay in the config.txt file as explained above in the HDMI section.

$ tvservice -o

USB power

Turn off USB port power (note the register address may differ according to the board family)

$ echo 0 | sudo tee /sys/devices/platform/soc/3f980000.usb/buspower >/dev/null

Wifi Radio

The Wifi radio seems to use about 10 - 20mA average for a decent Wifi signal. Probably more when the signal is weak (TBC). Turn off the Wifi for 30 seconds, attempt to connect for 5 seconds, turn off again. Note that this should be tweaked depending on how long it takes to connect to the phone app. 5 seconds is a long time power-wise. If we can get away with less, that would be better. This can be accomplished many ways but the "Linux-y" way to do it is to create a system service or run a cron job. I used the info here to write this example. The script file is wifi_probe.sh which will be copied to /usr/bin with the appropriate permissions set (prob 755 root:root)

/usr/bin/wifi_scan.sh
-------------------------------
#!/bin/bash

# 
# This script is meant to be run either as a cron job or from a systemd timer.
# If there is an existing, active connection then there is no change to that connection.
# If the radio was off, it is turned on and we wait NUM_SEC_FOR_CONNECTION seconds
# If there is a connection after that time then we are done.
# If there is no connection then we assume that there is no AP in range, and turn 
#  off the radio to save power.
#

NUM_SEC_FOR_CONNECTION=5

radio_on () {
    if [[ $(nmcli radio wifi) == "enabled" ]]; then
        echo 1 
    else
        echo 0
    fi
}

connected () {
    nmcli device | awk '{if ($2 == "wifi") { if ($3 !~ "dis") {print 1;} else {print 0;}}}'
}

# Check the radio status
if [[ $( radio_on ) == "0" ]]; then
    # if the radio is off, turn it on and wait a bit for a connection
    nmcli radio wifi on
    sleep $NUM_SEC_FOR_CONNECTION
fi

# Check to see if we are connected
if [[ $( connected ) == "0" ]]; then
    # There is no connction so turn the radio off unti the next cycle
    nmcli radio wifi off
fi

# Else there is a connection and we quit silently until the next cycle

/etc/systemd/system/wifi_scan.service
--------------------------------------------
[Unit]
Description=Wifi connection power saver

[Service]
ExecStart=/usr/bin/wifi_scan.sh

/etc/systemd/system/wifi_scan.timer
------------------------------------------
[Unit]
Description=Run wifi_scan Every 30 Seconds

[Timer]
# First run after boot
OnBootSec=30
# Interval to run 
OnUnitActiveSec=30

[Install]
WantedBy=timers.target

To install the service:

$ systemctl daemon-reload

Then, enable the timer to start it automatically at boot:

$ systemctl enable wifi_scan.timer

Finally, start the timer manually for the first time (optional):

$ systemctl start wifi_scan.timer

Check the Timer Status:

To verify that your timer is running correctly, you can check its status with:

$ systemctl status wifi_scan.timer

TODO: Remove unused services

This one is a little weird. I got some power savings by removing alsa-utils, however, it removed a bunch of stuff we want like libcamera, raspi-config, and others.

⚠️ **GitHub.com Fallback** ⚠️