{"id":13852517,"url":"https://github.com/TonyLHansen/raspberry-pi-safe-off-switch","last_synced_at":"2025-07-13T05:33:36.175Z","repository":{"id":161843556,"uuid":"82999430","full_name":"TonyLHansen/raspberry-pi-safe-off-switch","owner":"TonyLHansen","description":"A set of scripts that can be used to provide a \"safe power off switch\" for a Raspberry Pi.","archived":false,"fork":false,"pushed_at":"2023-11-30T13:52:12.000Z","size":32740,"stargazers_count":193,"open_issues_count":0,"forks_count":26,"subscribers_count":19,"default_branch":"master","last_synced_at":"2024-11-22T07:36:41.591Z","etag":null,"topics":["gpio","on-off","raspberry-pi","shutdown","switch"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TonyLHansen.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-02-24T03:59:26.000Z","updated_at":"2024-10-21T12:44:28.000Z","dependencies_parsed_at":"2024-11-22T07:41:06.308Z","dependency_job_id":null,"html_url":"https://github.com/TonyLHansen/raspberry-pi-safe-off-switch","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/TonyLHansen/raspberry-pi-safe-off-switch","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TonyLHansen%2Fraspberry-pi-safe-off-switch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TonyLHansen%2Fraspberry-pi-safe-off-switch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TonyLHansen%2Fraspberry-pi-safe-off-switch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TonyLHansen%2Fraspberry-pi-safe-off-switch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TonyLHansen","download_url":"https://codeload.github.com/TonyLHansen/raspberry-pi-safe-off-switch/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TonyLHansen%2Fraspberry-pi-safe-off-switch/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265095274,"owners_count":23710620,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gpio","on-off","raspberry-pi","shutdown","switch"],"created_at":"2024-08-04T22:01:23.869Z","updated_at":"2025-07-13T05:33:34.339Z","avatar_url":"https://github.com/TonyLHansen.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"# Add a Safe Off Switch to Power Down Your Raspberry Pi\n\nAdd a switch to your Raspberry Pi to safely shut it down without pulling the power.\n\n## Intro\nTo keep prices down, the Raspberry Pi is missing something that most electronic devices come with:\na switch to turn it on or off. That's okay, you say, we'll just pull the plug to turn it off. \nUnfortunately, this can lead to corruption problems with the SD card. All the instructions say\nyou should run the shutdown command before pulling the plug, but this is not always possible, \nparticularly when your Raspberry Pi is running headless without a connected keyboard and monitor, \nand possibly even without any network connection. So, what CAN a self-respecting DIY-er do? \nThe answer, of course, is: add your own switch!\n\nLots of articles are available to tell you how to use a breadboard to connect a button or LED\nto a Raspberry Pi's GPIO pins.\nThis article focuses on doing something useful with those switches and LEDs.\n\nThe safe off switch is complementary to a reset switch (an on switch), which is the best method to start the\nRaspberry Pi back up again.\n[Issue 42](https://magpi.raspberrypi.com/issues/42) of TheMagPi had an excellent article on how to connect a Reset Button.\n\n(A version of this article appeared in\n[Issue 57](https://magpi.raspberrypi.com/issues/57) of The MagPi.)\n\n## You'll Need\n\n* [Raspberry Pi](raspberrypi.org) (any model)\n* Momentary normally open (NO) push button switches, such as [these](https://www.amazon.com/s/ref=nb_sb_noss?url=search-alias%3Daps\u0026field-keywords=Momentary+Push+Button+Switch+cable+motherboard)\nor [these](https://www.amazon.com/gp/product/B008DS188Y/).\n\n## Special Note for Raspberry Pi 5\nThe Raspberry Pi 5 **has** a built-in switch that both turns the Raspberry Pi on AND off.\nThat is, it acts as **both** an _off_ switch and a _reset_ switch.\nThere is also a jumper (J2) between the run time clock battery connector and the edge of the board.\nYou can connect a momentary normally open push button switch, as described above, to that jumper;\nit is [documented](https://www.raspberrypi.com/documentation/computers/raspberry-pi-5.html) to act the exact same way as the built-in power button.\n\n## Pictures\n### Safe Off Switch + Reset Using I2C GPIO Pin, Plus Other Low Profile Switches\n![safe off switch plus reset using i2c gpio pin](pictures/low_profile_switches.png)\n\n### Momentary switch connected to pins 39 and 40\n![momentary switch connected to pins 39 and 40](pictures/raspi3.jpg)\n\n### A Safe Off Switch\n![a safe off switch](pictures/raspi2.jpg)\n\n### A reset button on the same system\n![A reset button on the same system](pictures/raspi-reset.jpg)\n\n### Example of Both an Off and Reset Switch on a Raspberry Pi Zero. Right angle headers are used for a compact connection. The switches are mounted directly onto an Adafruit case.\n![Example of Both an Off and Reset Switch on a Raspberry Pi Zero. Right angle headers are used for a compact connection. The switches are mounted directly onto an Adafruit case.](pictures/raspizero.jpg)\n\n## Using GPIO Zero\nWith the GPIO Zero library module, the Python code to deal with a button \npress becomes extremely simple.\n(If you are on a system that does not already have the gpiozero module, such as some of the lite distributions,\nyou will see a message such as `ModuleNotFoundError: No module named 'gpiozero'`.\nIf that is true, then install the module using a command such as `sudo apt install python3-gpiozero`.)\nAssuming your button is connected between\nGPIO 21 and Ground, the code can look like as easy as [this](python/shutdown-press-simple.py):\n\n``` python\n#!/usr/bin/env python3\nfrom gpiozero import Button\nimport os\nButton(21).wait_for_press()\nos.system(\"sudo poweroff\")\n```\n\nThis code creates a button on GPIO 21, waits for it to be pressed, \nand then executes the system command to power down the Raspberry Pi.\nGPIO 21 is nice because it's on pin 40 of the 40-pin header and sits\nright next to a ground connection on pin 39. This combination makes \nit difficult for an off switch to get plugged in incorrectly. \nOn a 26-pin header, GPIO 7 is similarly situated at the bottom there \non pin 26, next to a ground connection on pin 25.\n\nIf you don't mind losing your I2C connectivity, an alternative choice would be GPIO 3, \nsituated on pin 5.\nWhat is particularly nice about GPIO 3 is that it **also** acts as a reset pin \nwhen the computer is powered down.\nBy using GPIO 3, you can use a single button for **both** an ON and OFF switch.\n\nCreate the script on your Raspberry Pi using your favorite text editor\n(e.g., nano, vim or emacs), and make certain that it's executable, as in\n\n```shell\n$ nano shutdown-press-simple.py\n$ chmod a+x shutdown-press-simple.py\n```\n\nThen add a line to the end of /etc/rc.local to run it at boot time:\n\n```shell\n$ sudo su\n# echo '~pi/shutdown-press-simple.py \u0026'  \u003e\u003e /etc/rc.local\n```\n\nIf your /etc/rc.local ends with an `exit` statement, this new line will be ignored because it is after the exit statement.\nRun `tail /etc/rc.local` to check.\nIf so, use your favorite editor to move the lines around so that the invocation of the python script goes before the exit statement.)\n\n```shell\n$ tail /etc/rc.local\n$ sudo nano /etc/rc.local\n```\n\nNow after rebooting, your script will be running and listening for \na button (connected between GPIO 21 on pin 40 and ground) to be pushed.\n\n## Preventing Accidental Button Pushes\nOne major drawback of the previous code is that any accidental push \nof the button will shut your Raspberry Pi down. \nIt would be better if you needed to hold the button down for several\nseconds before everything powers down.\n\n[shutdown-with-hold.py](python/shutdown-with-hold.py)\n``` python\n#!/usr/bin/env python3\nfrom gpiozero import Button\nfrom signal import pause\nimport os, sys\n\noffGPIO = int(sys.argv[1]) if len(sys.argv) \u003e= 2 else 21\nholdTime = int(sys.argv[2]) if len(sys.argv) \u003e= 3 else 6\n\n# the function called to shut down the RPI\ndef shutdown():\n    os.system(\"sudo poweroff\")\n\nbtn = Button(offGPIO, hold_time=holdTime)\nbtn.when_held = shutdown\npause()    # handle the button presses in the background\n```\n\nInstead of hard-coding the GPIO number 21 and the hold time, this code \ndoes a few things differently.\nFirst, it defines variables to hold these numbers at the top of the code.\nFor a program this small, declaring the values at the top is not necessary, \nbut it is good practice to declare any configurable variables near the top \nof the code. \nWhen making changes later, you won't have to hunt through the code to find \nthese variables.\nSecondly, it allows the GPIO number and hold time to be overridden on the \ncommand line, so that you can change them later without modifying the program.\nWe then define a function named `shutdown()` to execute the `poweroff` system command.\nThe button is also assigned to a variable for use in the next statement. \nThis time, we are also specifying that the button must be held down, and \nwhen the hold time (6 seconds) has passed, any function assigned to the \n`when_held` event will be executed. We then assign that event to the \n`shutdown()` function we defined earlier. \nThe call to `pause()` is needed to cause the script to wait for the button presses.\n\nIf you look at the examples that come with the GPIO Zero source, you'll find a \n[script](https://github.com/RPi-Distro/python-gpiozero/blob/master/docs/examples/button_shutdown.py)\nvery similar to this one.\n\n## Feedback While Pressing the Button\nBut, we can do better. \nThe major thing lacking with the above code is any sort of feedback -- it's hard to tell\nthat anything is really happening while you have the button pressed down. \nFortunately, GPIO Zero allows us to do much more with a button press, as well as controlling\nother devices.\nFor example, we can turn an LED on and off, or set it blinking, when the button is first \npressed by attaching to the button's `when_pressed` event.\nWe need to ensure that the LED is turned off if the button is not held down for the entire \nlength of time.\nThis can be accomplished by attaching to the when_released event.\nAs before, the important work has been moved into functions named `when_pressed()`,\n`when_released()` and the same `shutdown()` function we used before. \nThese are assigned to their corresponding button events.\n\n### Using the on-board LEDs\nInstead of wiring in your own LED, many versions of the Raspberry Pi come with several \nLEDs already on them that can be controlled. \nThe Raspberry Pi A+, B+ and Pi2 boards have an Activity Status LED and a Power LED that\ncan be accessed through the GPIO numbers 47 and 35, respectively.\n(Early versions of the Raspberry Pi used GPIO 16 for the Activity Status LED, but did \nnot provide access to the Power LED.)\nThe Raspberry Pi Zero and Computation Modules have the Activity Status LED on GPIO 47.\n(The GPIO Zero library does not yet have a way to control the LEDs on the Pi3.)\n\n[shutdown-led-simple.py](python/shutdown-led-simple.py)\n``` python\n#!/usr/bin/env python3\nfrom gpiozero import Button, LED\nfrom signal import pause\nimport os, sys\n\noffGPIO = int(sys.argv[1]) if len(sys.argv) \u003e= 2 else 21\nholdTime = int(sys.argv[2]) if len(sys.argv) \u003e= 3 else 6\nledGPIO = int(sys.argv[3]) if len(sys.argv) \u003e= 4 else 2\n\ndef when_pressed():\n    # start blinking with 1/2 second rate\n    led.blink(on_time=0.5, off_time=0.5)\n\ndef when_released():\n    # be sure to turn the LEDs off if we release early\n    led.off()\n\ndef shutdown():\n    os.system(\"sudo poweroff\")\n\nled = LED(ledGPIO)\nbtn = Button(offGPIO, hold_time=holdTime)\nbtn.when_held = shutdown\nbtn.when_pressed = when_pressed\nbtn.when_released = when_released\npause()\n```\n\nThe GPIO Zero library will print a warning message if you try using either of these LEDs. \nThe workaround for now is to turn off the warning message temporarily. \nWith current versions of the GPIO Zero library you are using, you can use:\n\n[turn-off-power-led-warnings.py](python/turn-off-power-led-warnings.py)\n``` python\nimport warnings\n...\nledGPIO = 47\n...\nwith warnings.catch_warnings():\n    warnings.simplefilter(\"ignore\")\n    led = LED(ledGPIO)\n```\n\nIf you cannot use the on-board LEDs, you can connect an LED (with a small resistor) to \nthe GPIO of your choice.\nSee numerous other articles on how to connect an LED to a GPIO pin.\n\n### Progressive Blinking\n\nTo make it more obvious what is happening, it is possible to be more dynamic in your feedback. \nFor example, how about starting with a slow blink, but progressively blink faster and faster? \nThe GPIO Zero makes this easy because it passes information to the event functions that lets \nyou make changes during the button press, and can be set up to call the button press event\nfunction repeatedly instead of just once.\nIn this code, we switched to using GPIO Zero's LEDBoard() class to blink multiple LEDs together. \n(Here, we're passing in the Activity Status and Power LED GPIO numbers.) \nThe constructor for `Button()` has a new parameter (`hold_repeat=True`) and we've set the hold\ntime to 1 second instead of the full hold time.\nThe `when_pressed()` and `when_released()` functions remain the same, but the `shutdown()` function \nnow declares its button parameter, and asks the button how long it's been pressed so far. \nThe blink rate is then updated accordingly. \nWhen the maximum hold time is finally passed, only at that time is the `poweroff` system command executed.\n\n[shutdown-ledboard.py](python/shutdown-ledboard.py)\n``` python\n#!/usr/bin/env python3\nfrom gpiozero import Button, LEDBoard\nfrom signal import pause\nimport warnings, os, sys\n\noffGPIO = int(sys.argv[1]) if len(sys.argv) \u003e= 2 else 21\nofftime = int(sys.argv[2]) if len(sys.argv) \u003e= 3 else 6\nmintime = 1       # notice switch after mintime seconds\nactledGPIO = 47   # activity LED\npowerledGPIO = 35 # power LED\n\ndef shutdown(b):\n    # find how long the button has been held\n    p = b.pressed_time\n    # blink rate will increase the longer we hold\n    # the button down. E.g., at 2 seconds, use 1/4 second rate.\n    leds.blink(on_time=0.5/p, off_time=0.5/p)\n    if p \u003e offtime:\n        os.system(\"sudo poweroff\")\n\ndef when_pressed():\n    # start blinking with 1/2 second rate\n    leds.blink(on_time=0.5, off_time=0.5)\n\ndef when_released():\n    # be sure to turn the LEDs off if we release early\n    leds.off()\n\nwith warnings.catch_warnings():\n    warnings.simplefilter(\"ignore\")\n    leds = LEDBoard(actledGPIO, powerledGPIO)\n\nbtn = Button(offGPIO, hold_time=mintime, hold_repeat=True)\nbtn.when_held = shutdown\nbtn.when_pressed = when_pressed\nbtn.when_released = when_released\npause()\n```\n\n## Playing Sounds?\nIf you have a speaker connected to your Raspberry Pi, you could play audio clips \ninstead of blinking LEDs.\nAn easy way to do this is to use the `pygame.mixer.Sound` class to play your audio clips.\nFor example, you could repeatedly play the audio clip that says \"I'm melting, melting\"\nfrom the Wizard of Oz, and then play the audio clip that says \"There's no place like home\"\nright before powering down the Raspberry Pi.\n\nThe basic structure of the code remains the same.\nAt the beginning, we need to initialize the sound system, and then create the sound clips.\nWhen the button is pressed, we start playing the \"I'm melting\" [clip](sounds/ImMeltingMelting.ogg), looping it enough times \nfor it to last the hold time.\nIf the button is released early or the hold time has elapsed, we need to stop that clip. \nWhen the hold time has elapsed, we then start playing the \"There's no place like home\" [clip](sounds/NoPlaceLikeHome.ogg)\nand power down.\n\n[shutdown-melting.py](python/shutdown-melting.py)\n``` python\n#!/usr/bin/env python3\nfrom gpiozero import Button\nfrom signal import pause\nimport pygame.mixer\nfrom pygame.mixer import Sound\nimport time, os\n\nholdTime = 10\noffGPIO = 21\n\npygame.mixer.init()\nmelting = Sound(\"ImMeltingMelting.ogg\")\nnohome = Sound(\"NoPlaceLikeHome.ogg\")\n\ndef shutdown():\n    # stop playing one sound and switch to another\n    melting.stop()\n    nohome.play()\n    # give it a chance to play\n    time.sleep(1)\n    # and shutdown for real\n    os.system(\"sudo poweroff\")\n\ndef when_pressed():\n    # start playing\n    melting.play(loops=holdTime/melting.get_length())\n\ndef when_released():\n    # stop playing if released early\n    melting.stop()\n\nbtn = Button(offGPIO, hold_time=holdTime)\nbtn.when_held = shutdown\nbtn.when_pressed = when_pressed\nbtn.when_released = when_released\npause()\n```\n\n## Going Further\nCan you think of other ways to provide feedback while pressing the hold button? \nHow about using a buzzer, or popping up a message on a screen? Let your imagination run wild. :) \n\nCan you think of other ways to be signaled that it is time to turn off? \nHow about watching the \"low battery\" signal from a battery pack? \nWhat else can be used to trigger a shutdown?\n\nNow, which of your projects are you going to add shutdown and reset buttons to?\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FTonyLHansen%2Fraspberry-pi-safe-off-switch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FTonyLHansen%2Fraspberry-pi-safe-off-switch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FTonyLHansen%2Fraspberry-pi-safe-off-switch/lists"}