RetroPie forum home
    • Recent
    • Tags
    • Popular
    • Home
    • Docs
    • Register
    • Login
    Please do not post a support request without first reading and following the advice in https://retropie.org.uk/forum/topic/3/read-this-first

    ensuring ES gracefully finish and save metadata in every system shutdown

    Scheduled Pinned Locked Moved Help and Support
    shutdown scriptemulationstatiofavoriteslast playedmetadata issues
    96 Posts 26 Posters 37.5k Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • F
      Fitz2380
      last edited by

      I just wanted to update my previous post as I did not include the proper information before. I am running Retropie v4.3, RPi3 Model B, 5v @2.5A PSU, 32GB SandDisk Microsd.

      I have installed the killes service and installed the killes.sh script. I can successfully save metadata by running the script from the command line. I cannot save metadata if I run a script that does the 'shutdown now' command which is executed from the main retropie menu as was posted here: https://retropie.org.uk/forum/topic/10736/power-on-off-option-in-main-menu/3

      Additionally how do you put your system information into a footer in your post

      1 Reply Last reply Reply Quote 0
      • B
        Bananu @Yahmez
        last edited by

        @yahmez

        Hi! I´m on your previous situation: Modded Nespi Case soft shutdown, following PDF (working GREAT) and after some iso backups, I installed the killes.sh, but is not working... adding some favs and pressing power down button, and after power it up, favs didn´t save.

        I can see killes.service enabled from :~ $ systemctl status killes
        ● killes.service - Kill EmulationStation
        Loaded: loaded (/etc/systemd/system/killes.service; enabled)
        Active: active (exited) since Sat 2018-03-24 10:05:18 UTC; 3min 46s ago

        Is the fresh install your only way to go? For me, it would be a nightmare re-install 30gb of roms and ports, gamepad config, overclock... I´m making backups every now and then just to not repeat what it´s done (like 6 months of work here)

        So... how can I emulate the "fresh install" on my scripts? is something I should wipe from systemctl or something?

        Thank you!

        YahmezY 1 Reply Last reply Reply Quote 1
        • YahmezY
          Yahmez @Bananu
          last edited by

          @bananu
          Sorry man, I really don't know what is causing this issue for people. Especially because the killes script worked for me both on a system I had already set up completely, and with a fresh install. Wish I could be more of a help here...

          1 Reply Last reply Reply Quote 0
          • J
            julenvitoria Banned
            last edited by

            @meleu HI! I'm trying to make the gracefully finish to work but I can't and I don't know why... I follow all the steps even create the script in the same path than you (/etc) but it does not work. I'm using a raspberry pi 3 with the last version of retropie and shutdown script with a button connected to GPIO 3. Could you guide me about this?
            Thanks

            1 Reply Last reply Reply Quote 0
            • QuackwalksQ
              Quackwalks
              last edited by

              When using this with the Kintaro 9000 case, the power switch doesn't respond but the reset switch does. Using the reset switch won't save metadata. If anyone has experience with this, I'd love some help.

              Pi Model or other hardware: Pi 3b
              Power Supply used: 5.1v 2.5a
              RetroPie Version Used: 4.3.17
              Built From: Pre made SD Image on RetroPie website, updated to 4.3.17
              USB Devices connected: dongle for wireless keyboard
              Controller used: Official PS3 Controller
              How to replicate the problem: Followed install instructions from Kintaro 9000, then followed instructions in this post

              1 Reply Last reply Reply Quote 0
              • meleuM
                meleu
                last edited by

                Hello fellows,

                I've just updated the OP with the following warning:

                UPDATE: many guys are reporting that this trick isn't working anymore. Maybe something has changed after an OS update, but I'm not sure. I don't use GPIO buttons to shutdown my RetroPie myself.

                I'm currently very busy on other projects and unable to provide support here. Sorry mates..

                • Useful topics
                • joystick-selection tool
                • rpie-art tool
                • achievements I made
                S 1 Reply Last reply Reply Quote 2
                • J
                  julenvitoria Banned
                  last edited by julenvitoria

                  Ok, thanks for the reply!!

                  1 Reply Last reply Reply Quote 0
                  • S
                    Semper 5 @meleu
                    last edited by

                    @meleu said in ensuring ES gracefully finish and save metadata in every system shutdown:

                    Hello fellows,

                    I've just updated the OP with the following warning:

                    UPDATE: many guys are reporting that this trick isn't working anymore. Maybe something has changed after an OS update, but I'm not sure. I don't use GPIO buttons to shutdown my RetroPie myself.

                    I'm currently very busy on other projects and unable to provide support here. Sorry mates..

                    Much appreciated for the update and continued hard work. I'll be following along :)

                    1 Reply Last reply Reply Quote 0
                    • F
                      finaluser
                      last edited by

                      Look this script, is working for me
                      https://github.com/RetroFlag/retroflag-picase

                      cyperghostC 1 Reply Last reply Reply Quote 0
                      • cyperghostC
                        cyperghost @finaluser
                        last edited by

                        @finaluser Yes yes... the killall method ;) It's the simpelest method and it will fail if there are emulators running in background.

                        The service @meleu gots following reason. You don't need annother script that explicitly shutdowns emulationstation. Sadly the service seems to not run correctly anymore (users reports that)

                        So I recreated annother script Multi Switch Shutdown Script that suppots all NESPicases, the Pimoroni ONOFFSHIM, the Mausberry and any generic button.

                        It will correctly shutdown emulators and ES and the reset button works more as an reset button ;) It shutdowns emulators if there are any running. Or it just restart ES if you are in main menu. The reboot option can be done by menu or via command line ;)

                        1 Reply Last reply Reply Quote 0
                        • T
                          TicTac_93
                          last edited by

                          @meleu, I recently set up a safe-shutdown script for my Super Kuma 9000 case, and I ended up using a patchwork of your code, @cyperghost's, and @mediamogul's. It all seems to be running cleanly now, at least on my system - I tested shutdowns, resets, and full system reboots both from within Emulator Station and within a game, and it seems to be saving metadata correctly in all instances.

                          I hope this is useful to you or others who come across this thread!

                          I wrote it specifically to work with my modified kintaro pcb.py script, included at the end of this post. Though you should be able to call it from anywhere, as long as you pass it the appropriate option (default is REBOOT):

                          • --SHUTDOWN - Initiates a clean shutdown of any open emulators, then Emulation Station, and finally the Pi itself
                          • --REBOOT - Initiates a clean shutdown of any open emulators, then Emulation Station, and finally reboots the Pi
                          • --RESET - Initiates a clean shutdown of any open emulators, then a clean restart of Emulation Station. If Emulation Station is not open (ie, you crashed to the terminal somehow), this option will restart it.

                          Hopefully it's not too janky, I'm beyond rusty with bash and python.

                          TicTac's killes.sh code

                          #!/bin/bash
                          
                          # Meleu's Graceful Shutdown code, with improvements from mediamogul and cyberghost.
                          # Hacked together by TicTac, and further tweaked to work with his Kintaro control script.
                          
                          # Set the mode of the script.  Options are --SHUTDOWN, --RESET (only restarts ES), and --REBOOT
                          MODE="REBOOT" # Default to system reboot
                          if [ $1 ]; then # If we got an option, use it
                          	key="$1"
                          	case $key in
                          		--SHUTDOWN)
                          		MODE="SHUTDOWN"
                          		;;
                          		--RESET)
                          		MODE="RESET"
                          		;;
                          		--REBOOT)
                          		MODE="REBOOT"
                          		;;
                          	esac
                          fi
                          
                          # New PID code lifted from cyperghost's Multi Switch Shutdown Script
                          # If there's an emulator running, we need to kill it and go back to ES
                          EMUPID="$(pgrep -f -n runcommand.sh)"
                          if [[ -n "$EMUPID" ]]; then
                              pkill -P "$(echo $EMUPID | tr ' ' ',')"
                              kill "$EMUPID"
                          	# Hold in this while loop until the emulator process stops
                          	while s=$(ps -p "$EMUPID" -o s=) && [ "$s" ] && [ "$s" != 'Z' ]; do
                          		sleep 1
                          		done
                          fi
                          
                          ESPID="$(pgrep -f "/opt/retropie/supplementary/.*/emulationstation([^.]|$)")"
                          if [ -n "$ESPID" ]; then # If ES was running...
                          	# Touch appropriate file to trigger ES reset/reboot/shutdown, then kill the ES Process
                          	case $MODE in
                          		SHUTDOWN)
                          		sudo touch /tmp/es-shutdown && chown pi:pi /tmp/es-shutdown && kill $ESPID
                          		;;
                          		RESET)
                          		sudo touch /tmp/es-restart && chown pi:pi /tmp/es-restart && kill $ESPID
                          		;;
                          		REBOOT)
                          		sudo touch /tmp/es-sysrestart && chown pi:pi /tmp/es-sysrestart && kill $ESPID
                          		;;
                          	esac
                          	while s=$(ps -p "$ESPID" -o s=) && [ "$s" ] && [ "$s" != 'Z' ]; do
                          		sleep 1
                          		done
                          	sleep 1
                          else # If it wasn't, directly shutdown / reboot the pi or restart ES
                          	case $MODE in
                          		SHUTDOWN)
                          		sudo shutdown -h now
                          		;;
                          		RESET)
                          		emulationstation
                          		;;
                          		REBOOT)
                          		sudo shutdown -r now
                          		;;
                          	esac
                          	sleep 1
                          fi
                          
                          sleep 1
                          
                          

                          TicTac's /opt/kintaro/pcb.py code

                          #!/usr/bin/python3 -u
                          #Copyright 2017 Michael Kirsch
                          
                          #Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
                          #to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
                          # and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
                          #The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
                          
                          ######################
                          # MODIFIED BY TICTAC #
                          ######################
                          # I stripped out the fan control functionality (it's not used in my build), and am working to make shutdowns / resets safe for Emulation Station.
                          #
                          # WIP Log:
                          # 180525 - Stripped out the fan control code with little issues.  Modified reset switch to indicate when it's changing functionality
                          # 		 - and to be generally less shitty
                          # 180526 - Replaced old code for shutdowns and resets (just calls to sudo shutdown) with appropriate calls to /opt/kintaro/killes.sh
                          # 		 - Also further tweaked reset button functionality.  Tapping reset will restart Emulation Station, holding it for 1-5seconds
                          # 		 - will reboot the system, and holding it for 5+seconds will cancel it.  System seems to be stable now, no metadata is getting
                          # 		 - lost on shutdowns or resets from within a game, or just emulation station itself.
                          
                          import http.server
                          import configparser
                          import time
                          import os
                          import RPi.GPIO as GPIO
                          import subprocess
                          from configparser import SafeConfigParser
                          from enum import Enum
                          
                          pcb_components={"LED":7,"FAN":8,"RESET":3,"POWER":5,"CHECK_PCB":10}
                          
                          class path():
                              kintaro_folder = "/opt/kintaro/"
                              start_folder = "start/"
                              intro_video = kintaro_folder + start_folder + "intro.mp4" # DELETE?
                              config_file = kintaro_folder + start_folder + "kintaro.config"
                              temp_command = 'vcgencmd measure_temp'
                          
                          class vars():
                              reset_hold_short = 10
                              reset_hold_long = 50
                              debounce_time = 0.01
                              counter_time = 0.1
                          
                          GPIO.setmode(GPIO.BOARD) #Use the same layout as the pins
                          GPIO.setup(pcb_components["LED"], GPIO.OUT) #LED Output
                          GPIO.setup(pcb_components["FAN"], GPIO.OUT) #FAN Output # DELETE?
                          GPIO.setup(pcb_components["POWER"], GPIO.IN)  #set pin as input
                          GPIO.setup(pcb_components["RESET"], GPIO.IN, pull_up_down=GPIO.PUD_UP) #set pin as input and switch on internal pull up resistor
                          GPIO.setup(pcb_components["CHECK_PCB"], GPIO.IN, pull_up_down=GPIO.PUD_UP)
                          
                          
                          def temp(): #returns the gpu temoperature
                              res = os.popen(path.temp_command).readline()
                              return float((res.replace("temp=", "").replace("'C\n", "")))
                          
                          class led:  #class to control the led
                              def toggle(status):  #toggle the led on of off
                                  if status == 0:       #the led is inverted
                                      GPIO.output(pcb_components["LED"], GPIO.LOW)
                                  if status == 1:
                                      GPIO.output(pcb_components["LED"], GPIO.HIGH)
                          
                              def blink(amount,interval): #blink the led
                                  for x in range(amount):
                                      led.toggle(1)
                                      time.sleep(interval)
                                      led.toggle(0)
                                      time.sleep(interval)
                          
                          def return_config_bool(searchterm):
                              Config = configparser.ConfigParser()
                              Config.read(path.config_file)  # read the configfile
                              return Config.getboolean("Boot", searchterm)
                          
                          if return_config_bool("video"): # DELETE?
                              os.system("omxplayer " + path.intro_video + " &") #start the bootvideo on start
                          
                          def toggle(toggle_this):  #change one of the values in the config file
                              parser = configparser.ConfigParser()
                              parser.read(path.config_file)
                              if return_config_bool(toggle_this):
                                  parser.set('Boot', toggle_this, "False")
                              else:
                                  parser.set('Boot', toggle_this, "True")
                              with open(path.config_file, "w+") as configfile:
                                  parser.write(configfile)
                          
                          def Falling_Power(channel):
                              if (GPIO.input(pcb_components["POWER"]) == GPIO.HIGH) and (GPIO.input(pcb_components["CHECK_PCB"]) == GPIO.LOW):  # shutdown function if the powerswitch is toggled
                                  led.toggle(0)
                                  os.system("sudo bash /opt/kintaro/killes.sh --SHUTDOWN") # Flag system for shutdown and initiate killes.sh
                          
                          
                          def Falling_Reset(channel):
                          	if (GPIO.input(pcb_components["RESET"]) == GPIO.LOW):  # sanity check to make sure Reset switch is actually toggled
                          		reset_counter = 0  # counter for while loops
                          		reset_stage = 0  # stage toggle for reset functionality
                          		time.sleep(vars.debounce_time)  # debounce time
                          		while (GPIO.input(pcb_components["RESET"]) == GPIO.LOW): # Count up until we hit the first cutoff
                          			if reset_counter == vars.reset_hold_short:  # Check if we're at the first cutoff
                          				reset_stage = 1
                          				led.blink(1, 0.2)  # Blink to indicate reset stage has changed
                          				led.toggle(1)
                          			if reset_counter == vars.reset_hold_long:  # Check if we're at the second cutoff
                          				reset_stage = 2
                          				led.blink(2, 0.2)  # Blink to indicate reset stage has changed again
                          				led.toggle(1)
                          			reset_counter = reset_counter + 1
                          			time.sleep(vars.counter_time)
                          		if reset_stage == 0:
                          			os.system("sudo bash /opt/kintaro/killes.sh --RESET")
                          		elif reset_stage == 1:
                          			os.system("sudo bash /opt/kintaro/killes.sh --REBOOT")
                          		else:
                          			# DO NOTHING.  THIS STAGE IS IN CASE YOU ACCIDENTALLY HIT THE BUTTON
                          			led.blink(3, 0.2)
                          			led.toggle(1)
                          
                          def PCB_Pull(channel):
                              GPIO.cleanup()
                          
                          if (GPIO.input(pcb_components["POWER"]) == GPIO.HIGH) and GPIO.input(pcb_components["CHECK_PCB"]) == GPIO.LOW:  # What the hell is this for?
                              os.system("sudo bash /opt/kintaro/killes.sh --SHUTDOWN") # Flag system for shutdown and initiate killes.sh
                          
                          GPIO.add_event_detect(pcb_components["CHECK_PCB"],GPIO.RISING,callback=PCB_Pull)
                          
                          time.sleep(1)
                          
                          if return_config_bool("pcb") and GPIO.input(pcb_components["CHECK_PCB"])==GPIO.LOW: #check if there is an pcb and if there is then attach the interrupts
                              led.toggle(1)
                              GPIO.add_event_detect(pcb_components["RESET"], GPIO.FALLING, callback=Falling_Reset)
                              GPIO.add_event_detect(pcb_components["POWER"], GPIO.FALLING, callback=Falling_Power)
                          
                          
                              #check for interrupts :D
                          while True:
                              time.sleep(5)
                              led.toggle(1)
                          
                          cyperghostC 1 Reply Last reply Reply Quote 1
                          • cyperghostC
                            cyperghost @TicTac_93
                            last edited by cyperghost

                            @tictac_93 This works in most cases ... yes

                            But look. You take PID of runcommand and use pkill -P switch to kill child PID. That works in most cases but some emulators also just call annother process and this won't be catched by your method. You need at least annother pkill -P call.

                            You should just use your python script and you can use the multi_switch and it's command line options. Therefore use a python call like output = int(subprocess.check_output(['./multi_switch.sh', '--es-pid'])) and you can check if ES is running. If the ouput is 0 then python interprets this as false if a PID is detected the value is grater than 0 - this interprets python as true.
                            So the sniplet in python itself would be look like this.

                            if output:
                                 os.system("./multi_switch.sh --es-poweroff")
                             else:
                                 os.system("sudo shutdown -h now")
                            
                            1 Reply Last reply Reply Quote 1
                            • First post
                              Last post

                            Contributions to the project are always appreciated, so if you would like to support us with a donation you can do so here.

                            Hosting provided by Mythic-Beasts. See the Hosting Information page for more information.