safemode.py is only available in CircuitPython 8.1.0 and later.

safemode.py Runs When Safe Mode Occurs

Normally, safe mode indicates some serious problem, and you might want to investigate that problem. However, if you are running a program that is unattended, you may want start it up again, despite getting a serious safe mode error. The safemode.py file lets you do that.

When safe mode occurs, boot.py and code.py are not run. However, if and only if safe mode occurs, and a file named safemode.py exists, that file is executed.

Like boot.py, safemode.py is run before any connection is made via USB, or via the WiFi or BLE workflow. Anything printed by safemode.py is not written anywhere (unlike boot.py, which writes to boot_out.txt).

Doing a Reset in safemode.py

The main use of safemode.py is to decide automatically when to leave safe mode and restart normally, with a hard reset. For instance, if you're running a long-lived program that uses WiFi, fatal errors can sometimes occur due to various bugs. So if you want to just ignore safe mode and try again, this simple safemode.py will leave safe mode and do a reset, as if you pressed the RESET button. 

import microcontroller

microcontroller.reset()

Conditional Resetting in safemode.py

In other cases, you may want to restart only on certain safe mode problems. For instance, you may want to protect only against power outages, and restart automatically if they occur. In that case you can check the reason the safe mode happened in safemode.py:

import microcontroller
import supervisor

if supervisor.runtime.safe_mode_reason == supervisor.SafeModeReason.BROWNOUT:
    microcontroller.reset()    # Reset and start over.
    
# Otherwise, do nothing. The safe mode reason will be printed in the
# console, and nothing will run.

Sleeping in safemode.py

Another reason for a power brownout is that you may, for instance, have a solar-powered battery charger. When the battery is low, it may be just enough to start the microcontroller, but not enough to continue running. So you might want to sleep after a brownout, and try again later. You could do that in code.py after checking the battery voltage. Or you could sleep for a few minutes in safemode.py and then reset to try again:

# safemode.py
import alarm
import microcontroller
import supervisor
import time

if supervisor.runtime.safe_mode_reason == supervisor.SafeModeReason.BROWNOUT:
    # Sleep for ten minutes and then run code.py again.
    time_alarm = alarm.time.TimeAlarm(monotonic_time = time.monotonic + 10*60)
    alarm.exit_and_deep_sleep_until_alarms(time_alarm)

Manual (USER) Safe Mode Skips safemode.py

When you force safe mode by pressing one or more buttons, safemode.py is not run. The reasoning is that you are present, and you have decided not to run anything at all. For instance, you may need to fix an error in safemode.py itself. So when supervisor.runtime.safe_mode_reason == USER, safemode.py is skipped.

This guide was first published on Mar 01, 2023. It was last updated on Mar 08, 2024.

This page (safemode.py) was last updated on Mar 08, 2024.

Text editor powered by tinymce.