This is the older software
These instructions are for Pi3D PictureFrame, which is still the right choice on a Raspberry Pi 2, 3 or Zero 2 W. On a Pi 4 or 5, start with the 2026 guide instead.
Tested with
Raspberry Pi OS March 2021, Raspberry Pi 2, 3 and 4, Pi3D 2.43, PictureFrame 2021.03.20, 1080p and 4K displays. The commands below have been corrected for current Raspberry Pi OS but the script has not been re-run on Trixie.
Changing the display brightness via software is really difficult to do from a Raspberry Pi. It works with some selected displays, but for the large majority, it doesn’t. But there is a workaround.
With a digital picture frame, you may want to automatically dim the screen a little bit in the evening so that it doesn’t shine too bright in the room.
Fortunately, this functionality is built into the PictureFrame image viewer.
This article describes the pi3d PictureFrame way of doing it. If you run picframe3 on a Pi 4 or Pi 5, the idea is the same but the topic names and the automation are different — there is a section on that at the end.
How it works
In my Raspberry Pi digital picture frame setup tutorial, I mention the Pi3D PictureFrame image viewer, which produces those wonderful crossfading image transitions.
It turns out that the same image algorithms can be used to reduce the brightness of an image.
The brightness can be controlled via MQTT or Home Assistant, which means that you can remote control it from mobile devices or simply through a time-controlled Python script.
In this article, I will show you how to do it either way.
Remote control via MQTT
The new parameter to control the brightness variable is unsurprisingly called “brightness”.
The payload value can range from “0.0” (nothing to see here) to “1.0” (full brightness).
So, if your device ID is called “picframe”, and you wanted to dim your screen to 80%, you would send a message like
mosquitto_pub -h localhost -t picframe/brightness -m "0.8"
If you want to know how this works with Apple devices, check here, for Android, here.
Control the brightness automatically with sunrise/sunset
Rather than manually changing the screen’s brightness, in most cases, an automation will be fine for most of the cases.
This is easy to do with a Python script.
First install the astral package. Since Bookworm, Raspberry Pi OS refuses a system-wide pip install — it answers with error: externally-managed-environment — so either take the packaged version:
sudo apt install python3-astral python3-paho-mqtt python3-tz
or install into a virtual environment and run the script with that environment’s Python.
Create a new file and paste this code. Save as “brightness_automation.py”.
#!/usr/bin/python3
import logging
import time
import traceback
from datetime import datetime
import paho.mqtt.client as mqtt
from astral import LocationInfo
from astral.sun import sun
from pytz import timezone
logging.basicConfig(filename="log.txt",format="%(asctime)s-%(levelname)s-%(message)s",level=logging.DEBUG)
MQTT_HOST="localhost" #enter your MQTT server here
MQTT_PORT=1883
#MQTT_USER=""
#MQTT_PASWD=""
completed=False
connected=False
def on_connect(client, userdata, flags, reason_code, properties):
print("Connected. %s." % (reason_code))
global connected
connected=True
update_brightness()
def update_brightness():
city = LocationInfo(name="Bad Soden am Taunus", region="Germany", timezone="Europe/Berlin", latitude=50.1420634310433, longitude=8.496851921081545) #enter your location info here
c_data = sun(city.observer, tzinfo=city.timezone)
dawn=str(c_data["dawn"])
sunrise=str(c_data["sunrise"])
sunset=str(c_data["sunset"])
dusk=str(c_data["dusk"])
current_local_time=datetime.now(tz=timezone(city.timezone))
print("Current Time: ",current_local_time)
print("Dawn: " + dawn)
print("Sunrise: " + sunrise)
print("Sunset: " + sunset)
print("Dusk: " + dusk)
dawn=datetime.fromisoformat(dawn)
sunrise=datetime.fromisoformat(sunrise)
sunset=datetime.fromisoformat(sunset)
dusk=datetime.fromisoformat(dusk)
bright_val=1.0
if current_local_time>=dawn and current_local_time<sunrise: #this is where you adjust your brightness settings depending on sunrise and sunset
bright_val=0.9
elif current_local_time>=sunrise and current_local_time<sunset:
bright_val=1.0
elif current_local_time>=sunset and current_local_time<dusk:
bright_val=0.9
else:
bright_val=0.8
print("Brightness: ",bright_val)
# publish screen brightness value
client.publish("picframe/brightness", bright_val, qos=0, retain=True)
global completed
completed=True
if __name__ == "__main__":
try:
# MQTT Broker
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
client.on_connect=on_connect
client.username_pw_set(username=MQTT_USER,password=MQTT_PASWD)
client.connect(host=MQTT_HOST,port=MQTT_PORT,keepalive=60)
client.loop_start()
while completed!=True:
time.sleep(0.01)
if not connected:
print(".",end="")
except:
traceback.print_exc()
logging.error("Error",exc_info=True)
Two things to watch in that script. paho-mqtt reached version 2 in 2024 and changed both of these: mqtt.Client() now has to be told which callback API you are writing against, which is the CallbackAPIVersion.VERSION2 argument, and on_connect takes five arguments instead of four. The version above is the 2.x form; on an old 1.x install it is the other way round.
The second is client.username_pw_set(username=MQTT_USER,password=MQTT_PASWD). Those two variables are commented out at the top of the script, because my broker has no password. If yours has none either, comment that line out as well, or the script stops with a NameError before it ever connects.
Adjust the values in your script as it works best with your screen and the room environment.
To start it automatically at boot and keep it running in the background, create a service with systemd.
Enter
sudo nano /etc/systemd/system/brightness_control.service
Paste the following text into the editor window
[Unit]
Description=Control display brightness automatically
After=multi-user.target
[Service]
Type=idle
User=pi
ExecStart=/usr/bin/python3 /home/pi/brightness_automation.py
Restart=always
RestartSec=300
[Install]
WantedBy=multi-user.target
Save and close.
Now change the file permissions with
sudo chmod 644 /etc/systemd/system/brightness_control.service
and update the services with
sudo systemctl daemon-reload
sudo systemctl enable brightness_control.service
Reboot.
Raspberry Pi OS has had no default pi user since 2022, so put your own user name and your own home folder in the two lines above. The script talks to a broker over the network and needs nothing privileged, so there is no reason to run it as root.
The same thing on picframe3
picframe3 also dims in software, so any monitor works, but the plumbing is different.
For a fixed evening dim there is no script at all — it is a setting:
power:
dim_schedule:
"20:00-23:00": 0.45
For a remote command, the topic is picframe/picframe/brightness/set and the payload is 0–255, the way Home Assistant expects a light. The frame also announces itself to Home Assistant by discovery and turns up there as a light entity with on/off and a brightness slider, which means a sunrise/sunset automation can be built on Home Assistant’s own sun triggers without this Python script, this broker call or this systemd unit.
Conclusion
Being able to soft-control your screen’s brightness through the Pi3D image viewer allows you to hide any monitor controls that you would otherwise need access to.
You could obviously also attach a brightness sensor, but I didn’t want to drill a hole in the frame. But if someone has a great idea how to do this without showing a fat sensor on the front of the frame, please contact me.
Thank You, Paddy, for a great addition to the PictureFrame script.
Was this article helpful?
Thank you for your support and motivation.