2

I've been trying to implement a custom procedure triggered by a button connected to my raspberry pi. To do that I've tried to launch a python script on boot that always listens to the button trigger.

That's the python script I'd like to run (just makes two system calls on button trigger).

#!/usr/bin/env python

#reset.py

import pigpio import subprocess import time

BUTTON = 16

pi = pigpio.pi('localhost') pi.set_mode(BUTTON, pigpio.INPUT) pi.set_pull_up_down(BUTTON, pigpio.PUD_UP)

if(pi.wait_for_edge(BUTTON, edge = pigpio.FALLING_EDGE, wait_timeout = 5)): subprocess.call(["sudo", "backup_boot"]) subprocess.Popen(["sudo", "restore_boot"], cwd="/home/pi/overlay-factory-reset/src/sbin/")

I've moved the script into /usr/local/bin with

sudo mv reset.py /usr/local/bin/
sudo chmod +x /usr/local/bin/reset.py

I've tested it with python reset.py and everything works fine. I've then created a shell script that handles the scrip on system boot

#!/bin/sh

#listen-for-reset.sh

BEGIN INIT INFO

Provides: reset.py

Required-Start: $remote_fs $syslog

Required-Stop: $remote_fs $syslog

Default-Start: 2 3 4 5

Default-Stop: 0 1 6

END INIT INFO

If you want a command to always run, put it here

echo PROVA

Carry out specific functions when asked to by the system

case "$1" in start) echo "Starting reset.py" /usr/local/bin/reset.py & ;; stop) echo "Stopping reset.py" pkill -f /usr/local/bin/reset.py ;; *) echo "Usage: /etc/init.d/listen-for-reset.sh {start|stop}" exit 1 ;; esac

exit 0

that I then moved into /etc/init.d and made it executable

sudo mv listen-for-reset.sh /etc/init.d/
sudo chmod +x /etc/init.d/listen-for-reset.sh

Then I've registered the script to start on boot

sudo update-rc.d listen-for-reset.sh defaults

Now, if I run

sudo /etc/init.d/listen-for-reset.sh start

the script is called correctly, and performs its job. If I reboot the pi, the script is not launched at boot and I have to start it manually with the command above.

I've tried other solutions like editing rc.local (I also verified the creation of the link inside the rc folder and it's there) and using crontab but none of them worked. It seems like there's a problem in services during the pi boot

I've no clue at all how to resolve the problem.

EDIT I've also tried with systemd but didn't work either. I've tried all the methods here listed

Kar.ma
  • 143
  • 4
Alex
  • 23
  • 1
  • 4
  • I also verified the creation of the link inside the rc folder ... you mean the rc?.d folders, and the links start with S not K, correct? Have you checked the system logs for errors? perhaps $remote_fs $syslog isn't the correct "required start" for your program ... or it could be that running as root is the problem ... does sudo python reset.py also work fine? – Jaromanda X Feb 15 '19 at 12:11
  • Yes, inside /etc/rc2.d and yes the link starts with S, S02listen-for-reset.sh. sudo python reset.py works fine, and everything works fine by starting manually with sudo /etc/init.d/listen-for-reset.sh start but it doesn't start on boot. About the $remote_fs etc I've taken the parameter from this website: https://howchoo.com/g/mwnlytk3zmm/how-to-add-a-power-button-to-your-raspberry-pi It sets up a button for shutdown so I guess it will run at boot as well – Alex Feb 15 '19 at 12:14
  • https://raspberrypi.stackexchange.com/q/40493/5538 – goldilocks Feb 15 '19 at 18:56

2 Answers2

2

From all methods you have tried, systemd is the one you should use. It is the main init system and only emulates deprecated SysV init system. I do not name your script reset.py to avoid possible confusion with system/program calls. Instead I will name it reset_trigger.py. So I would suggest to create a new service with:

rpi ~$ sudo systemctl --force --full edit reset_trigger.service

In the empty editor insert these statements, save them and quit the editor:

[Unit]
Description=Button Trigger
After=multi-user.target

[Service]
# User=pi
# WorkingDirectory=/home/pi/overlay-factory-reset/src/sbin/
ExecStart=/usr/local/bin/reset_trigger.py

[Install]
WantedBy=multi-user.target

Enable the service with:

rpi ~$ sudo systemctl enable reset_trigger.service

Reboot.

This is what I see so far the script needs to run. If not try by uncommenting User= and/or WorkingDirectory=. If it still not run give me feedback so we can look what additional conditions are needed.

Test and check with:

rpi ~$ sudo systemctl stop/start reset_trigger.service
rpi ~$ systemctl status reset_trigger.service


Update to answer questions from comment:
If you want to print the output to a console then the first question is: what console? On boot up there is a console only available from beginning with an attached monitor or on the serial console if you enable it. If you boot to the command prompt on the text console instead to the Graphical User Interface (GUI) then you have 6 pseudo consoles available you can switch to with <Alt>+<F1>..<F6>. If you boot into the GUI then you may consider to start a terminal window within your boot up prozess and redirect the output to it, or alternatively use a screen session this way. Then you can switch to it whenever you want. That are only some ideas to redirect the output. I have never tried one of them. I believe it is not a simple task. Maybe you will find some solutions on the web.

You asked to use StandardOutput=. This is the option to redirect the standard output STDOUT. You can set it in your Unit file for example to tty. Then you should see the output on the console of an attached monitor. On man systemd.exec you will find:

StandardOutput=
Controls where file descriptor 1 (STDOUT) of the executed processes is connected to. Takes one of inherit, null, tty, journal, syslog, kmsg, journal+console, syslog+console, kmsg+console, file:path, socket or fd:name.
[..]

Ingo
  • 42,107
  • 20
  • 85
  • 197
  • Thank you very much for your reply :) It was not still working until I added a while(True): in the py script before the if input and everything started working fine. I've already tried that solution but nothing seems to be working, I'm must had missed something Anyway, i've been monitoring the output in real time with sudo journalctl -f -u reset_trigger (I've called it that way). Is there a way to force the output of the script to be printed in the console? and by making it modal as consequence. I've read about a parameter in the service about the StandardOutput= option but no clue – Alex Feb 16 '19 at 01:05
  • @Alex I have updated the answer. Yes, you need the while loop. Otherwise it will only look one time and then terminate the service. You should have seen it with systemctl status reset_trigger.service showing dead. What do you mean with making it modal? Do you mean to use &? Never use & within a systemd service to send the script to the background. It is already made to run in the background and systemd looses control of the script then. – Ingo Feb 16 '19 at 11:18
  • As modal I mean that I'm not able to use any command while the scripts are called. I'm connected via ssh so as console I mean the terminal where I can type commands (?). I've tried by adding in the unit section as you suggested StandardOutput=journal+console and I've added ExecStart=/usr/bin/python -u /usr/local/bin/reset_trigger.py so that I'm sure that python's output is not buffered. Now I can see every output, even prints, that I use inside the script but still, I'm only able to see it inside journalctl -f -u reset_trigger but not passively in the terminal – Alex Feb 16 '19 at 13:13
  • @Alex man systemd.exec: journal+console, syslog+console and kmsg+console work in a similar way as the three options above but copy the output to the system console as well. Do you know what your system console is? I don't know. – Ingo Feb 16 '19 at 15:38
0

A good method is also described in http://supervisord.org/introduction.html. It is very smart to set up and I did not remember how was my script starting.

Just install the package with

sudo pip install supervisor

and customize the file /etc/supervisord/supervisord.conf You may set parameters like autostart, autorestart, delay to start, etc.

Dirk
  • 3,541
  • 3
  • 18
  • 25