So i have a code that i'm trying to run and when it finish it should display a message to the user saying what changes have happend. This works fine if i run it on terminal. But when i add it to a cronjob nothing happens and no error is shown.
It seems to me that it is losing the display session, but cant figure it how to solve it. Here is the show message code:
def sendmessage(message):
subprocess.Popen(['notify-send', message])
return
I also tried this version:
def sendmessage(message):
Notify.init("Changes")
n = Notify.Notification.new(message)
n.show()
return
Which gives the error (only in background also):
cannot open display:
Activated service 'org.freedesktop.Notifications' failed: Process org.freedesktop.Notifications exited with status
Would be very thankful for any help or alternative given.
I had a similar issue running a system daemon, where I wanted the user to be notified about a network bandwidth upload being exceeded.
The program was designed to run under systemd but at a push also under upstart.
You may get some mileage out of my configuration files:
systemd - bandwidth.service file
[Unit]
Description=Bandwidth traffic monitor
Documentation=man:bandwidth(7)
After=graphical.target
[Service]
Type=simple
Environment="DISPLAY=:0" "XAUTHORITY=/home/#USER#/.Xauthority"
PIDFile=/var/run/bandwidth.pid
ExecStart=/usr/bin/dbus-launch /usr/sbin/bandwidth_logd
ExecReload=/bin/kill -HUP $MAINPID
User=root
[Install]
WantedBy=graphical.target
upstart - bandwidth.conf file
#
# These are the scripts that run when a network appears.
# Use this on an upstart system in /etc/init
# test for systemd or upstart system with
# ps -p1 | grep systemd && echo systemd || echo upstart
# better
# ps -p1 | grep systemd >/dev/null && echo systemd || echo upstart
# Using upstart the script will need to daemonise which is a bugger
# so test for it and import Daemon_server.py
description "Bandwidth upstart events"
start on net-device-up # Start a daemon or run a script
stop on net-device-down # (Optional) Stop a daemon, scripts already self-terminate.
# Automatically restart process if crashed
respawn
# Essentially lets upstart know the process will detach itself to the background
expect fork
#Set environment variables
env DISPLAY=":0"
export DISPLAY
env XAUTHORITY="/home/#USER#/.Xauthority"
export XAUTHORITY
script
# You can put shell script in here, including if/then and tests.
# replace #USER# with your name and ensure that you have .Xauthority in $HOME
/usr/sbin/bandwidth_logd
end script
You will note that in both configuration files the environment becomes key and #USER# is replaced by a real user name with a valid .Xauthority file in their $HOME directory.
In the python code I use the following to emit the message(import notify2).
def warning(msg):
result = True
try:
notify2.init("Bandwidth")
mess = notify2.Notification("Bandwidth",msg,'/usr/share/bandwidth/bandwidth.png')
mess.set_urgency(2)
mess.set_timeout(0)
mess.show()
except:
result = False
return result
Related
I know how to autostart a python script (or so I thought). But I want a programm or something, if my python script is not running anymore, it should start the script again. Has anyone a idea how to do this?
Edit:
I tried running it as a service but that didnt work.
import bluetooth
import pygame
pygame.mixer.init()
server_sock=bluetooth.BluetoothSocket( bluetooth.RFCOMM )
port = 22
server_sock.bind(("",port))
server_sock.listen(1)
client_sock,address = server_sock.accept()
print ("Verbindung Hergestellt mit: ", address)
while True:
recvdata = client_sock.recv(1024)
print ("Nachricht bekommen: %s" % recvdata)
pygame.mixer.pause()
if (recvdata == b"h"):
sound = pygame.mixer.Sound('/home/maxi/Desktop/test.wav')
playing = sound.play()
if (recvdata == b"p"):
sound = pygame.mixer.Sound('/home/maxi/Desktop/test2.wav')
playing = sound.play()
if (recvdata == b"k"):
break
client_sock.close()
server_sock.close()
My startscript is:
[Unit]
Description=MaxiTest
After=multi-user.target
[Service]
Type=simple
Restart=always
ExecStart=/usr/bin/python3 /home/maxi/Desktop/btsound1.py
[Install]
WantedBy=multi-user.target
You can search more about how a python script can perform as a service or daemon. There are many solutions in this link:
How to make a Python script run like a service or daemon in Linux
Between all solutions, I prefer 3 of them (I'm not very familiar with raspberry-pi, so check compatibility):
Cronjob: You can create a cronjob for the script and the OS will run it every x seconds/minutes/... automatically and periodically.
Systemctl/Systemd: Create a custom service file for your script and start and enable it in Systemd. A complete guide is here:
https://medium.com/codex/setup-a-python-script-as-a-service-through-systemctl-systemd-f0cc55a42267
You chose systemd (after editing);
In /PATH_project/ create 2 bash scripts like this:
#!/bin/bash
# This is start.sh
cd /home/maxi/Desktop/
/usr/bin/python3 btsound1.py
And create stop.sh:
#!/bin/bash
for KILLPID in `ps ax | grep ‘myservice’ | awk ‘{print $1;}’`; do
kill -9 $KILLPID;
done
Then give execution permission to both files using:
chmod a+x start.sh
chmod a+x stop.sh
Then create a myservice.service file in /etc/systemd/system :
[Unit]
Description=myservice service
Wants=network-online.target
After=network.target network-online.target
[Service]
Type=simple
Restart=always
ExecStart=/bin/bash /home/maxi/Desktop/start.sh
ExecStop=/bin/bash /home/maxi/Desktop/stop.sh
RestartSec=5
TimeoutSec=60
RuntimeMaxSec=infinity
PIDFile=/tmp/mydaemon.pid
[Install]
WantedBy=multi-user.target
Then:
sudo systemctl daemon-reload
sudo systemctl start myservice.service
sudo systemctl status myservice.service
Benefits of using such bash scripts is that you can handle some more things in this way. For example if you are using a virtual environment, you can use source activate in start.sh file before running the script.py .
Supervisord: Install Supervisor and create a supervisord.conf file for your script. A good guide is here:
https://csjourney.com/managing-processes-with-supervisor-in-depth-tutorial/
I found what was the problem. I used rc.local and started the program 10 seconds after boot. The system needed time first to set up before I could start the script.
I currently am running a program through Thonny, and I want to make the pi autoboot that program whenever it turns on. I currently have the pi 4, and the code is run on Python3. Have tried many ways to autoboot such as using rc local, and bash rc, but none seem to work.
I recommend using the autostart file.
Edit the following file:
sudo nano /etc/xdg/lxsession/LXDE-pi/autostart
The default should look something like:
#lxpanel --profile LXDE-pi
#pcmanfm --desktop --profile LXDE-pi
#xscreensaver -no-splash
Add the command to run your script utilizing the # prefix and save. The new autostart file should look like:
#lxpanel --profile LXDE-pi
#pcmanfm --desktop --profile LXDE-pi
#xscreensaver -no-splash
#python3 /home/pi/your_script.py
More info: https://www.raspberrypi.org/forums/viewtopic.php?t=294014
By using things like .bashrc, your program will only get executed when you open a command prompt or terminal.
You can use systemd services:
create a file your_service.service in /etc/systemd/system/ (you need to be root, so use sudo). The filename will be the name of your service, without the .service extension (in this case your service will be named your_service)
put this in it (without the comments):
[Unit]
Description=A short description of your service
After=network.target # <-- put this if your script needs network, otherwise you can omit this line
StartLimitIntervalSec=0
[Service]
Type=simple
Restart=always # use this to always restart the script if the process ends. If your script only needs to run once at startup and is not a daemon, don't use this.
RestartSec=1
User=root # user account used to run the service
ExecStart=python3 /path/to/your/script.py
[Install]
WantedBy=multi-user.target
Then, you can start your script with this command:
sudo systemctl start your_service
You can finally enable the service to be run automatically at startup with this command:
sudo systemctl enable your_service
You can find more documentation / tutorials on systemd services and on all the available options in the following links:
https://medium.com/#benmorel/creating-a-linux-service-with-systemd-611b5c8b91d6
https://www.digitalocean.com/community/tutorials/how-to-use-systemctl-to-manage-systemd-services-and-units
https://www.freedesktop.org/software/systemd/man/systemd.service.html
https://wiki.archlinux.org/title/Systemd
I have a python script. Script have selenium with Chrome and go to a website, take data and put in CSV file.
This is a very long work.
I put the script on the server. And run. All work.
But I need script work in the background.
chmod +x createdb.py
nohup python ./createdb.py &
And I see
(env)$ nohup ./createdb.py &
[1] 32257
(env)$ nohup: ignoring input and appending output to 'nohup.out'
Press Enter.
(env)$ nohup ./createdb.py &
[1] 32257
(env)$ nohup: ignoring input and appending output to 'nohup.out'
[1]+ Exit 1 nohup ./createdb.py
Then it runs and immediately writes errors to the file, that Chrome did not start or there was no click.
I want to remind you that if you start without nohup, then everything will work.
What am I doing wrong? How to run a script?
Thank you very much.
You could create a background daemon (service)
You taged Ubuntu 16.04 it means you got systemd, for more information on how to set it up, please visit this link
create a file called <my_service>.system
and put it there: /etc/systemd/system
you systemd unit could look like this:
[Unit]
Description=my service
After=graphical.target
[Service]
Type=simple
WorkingDirectory=/my_dir
ExecStart=python my_script.py
[Install]
WantedBy=multi-user.target
then all you have to do is, reload systemd manage and start your service:
sudo systemctl daemon-reload
sudo systemctl myservice start
You can use the screen command, it works perfectly.
Here is a very good link: https://www.rackaid.com/blog/linux-screen-tutorial-and-how-to/
You can use a simple command, from the env directory:
(env)$ python /path/to/createdb.py > logger.txt 2>&1 &
This will help for storing the program logs in a defined file called "logger.txt"
I wanted to put my python code in boot in raspberry pi.
I tried rc.local, ./bashrc but while booting program is working & I am using opencv + camera +voice command. That's not working in boot.
Please give me a way to run voice + camera + opencv + python code in boot.
I would suggest to make it run as a service as mentioned in method 4 of following article:
https://www.dexterindustries.com/howto/run-a-program-on-your-raspberry-pi-at-startup/
Step 1– Create A Unit File
Open a sample unit file using the command as shown below:
sudo nano /lib/systemd/system/sample.service
Add in the following text :
[Unit]
Description=My Sample Service
After=multi-user.target
[Service]
Type=idle
ExecStart=/usr/bin/python /home/pi/sample.py
[Install]
WantedBy=multi-user.target
You should save and exit the nano editor.
This defines a new service called “Sample Service” and we are requesting that it is launched once the multi-user environment is available. The “ExecStart” parameter is used to specify the command we want to run. The “Type” is set to “idle” to ensure that the ExecStart command is run only when everything else has loaded. Note that the paths are absolute and define the complete location of Python as well as the location of our Python script.
In order to store the script’s text output in a log file you can change the ExecStart line to:
ExecStart=/usr/bin/python /home/pi/sample.py > /home/pi/sample.log 2>&1
The permission on the unit file needs to be set to 644 :
sudo chmod 644 /lib/systemd/system/sample.service
Step 2 – Configure systemd
Now the unit file has been defined we can tell systemd to start it during the boot sequence :
sudo systemctl daemon-reload
sudo systemctl enable sample.service
Reboot the Pi and your custom service should run:
sudo reboot
My python script takes multiple directories as input from user and I want that the user should input the directories for once only and then the program should run continuously over the same directories even after the system boots without asking the user again. I want to use Supervisor configuration to set this up. Any help ??
Make a cron-job or create a service init script (see the manual for how to write a init-script under the current Ubuntu version).
Doing a cronjob:
EDITOR=nano; crontab -e
#reboot cd /home/user/place_where_script_is; python3 myscript.py param1 param2
There's no efficient way for the user to input data to startup script, mainly because they run in a root environment.
A cron-job always runs in the environment where you invoked crontab -e (hopefully the users environment) but even then..
You can not interact with it because it's run in a separate "shell".
Unix socket?
In your script, add a listening socket on a unix socket.
in your .bashrc script (not sure where Ubuntu has it's post X startup scripts), invoke callMyScript.py that connects to the unix socket and sends instructions there.
This way you can interact with the cronjob/service script.
Here's how you keep track if a service is dead or not
PID files is the key:
#!/usr/bin/python3
pidfile = '/var/run/MyApplication.pid'
def pid_exists(pid):
"""Check whether pid exists in the current process table."""
if pid < 0:
return False
try:
os.kill(pid, 0)
except OSError, e:
return e.errno == errno.EPERM
else:
return True
if isfile(pidfile):
with open(pidfile) as fh:
thepid = fh.read()
pidnr = int(thepid)
if pid_exists(pidnr):
exit(1) # The previous instance is still running
else:
remove(pidfile) # Prev instance is dead, remove pidfile
# Create a pid-file with the active PID written in it
with open(pidfile, 'w') as fh:
fh.write(str(getpid()))
## Your code goes here...
remove(pidfile)
This way you can convert your Cron job to look like:
EDITOR=nano; crontab -e
* * * */1 cd /home/user/place_where_script_is; python3 myscript.py param1 param2
Which will run the script each minute, and if the script is dead or not started the script will start up again.
Same goes for service status-all myapp if you've written a init script, the init script will check the PID file (you'd have to write this in your init script and check the PID yourself much like the above Python code) and see if the process is dead.
You can add it to your crontab
crontab -e
Add the following line, which will get executed when your computer boot up:
#reboot python /path/to/your/script.py
Make sure have at least one empty line at the end.
As to restarting from where your script left off, you have to program that into your application logic.