How do I get a Python program to run at boot?
Hello all,
I'm primarily a PLC programmer trying to get my head wrapped around Linux OS programming and execution. I've written a Python program that simply watches for a flag on a PLCNext Engineer PLC variable, does some epic math, and writes a value into another PLC variable. I'd like the python script to run at boot along with the PLC so that it's effectively on whenever the PLC is running.
However, I've tried many stackExchange recommended processes for getting a python program to run at boot on a Linux system and I've found that many of the commands for accomplishing that are simply missing from the PLCNext OS.
Help would be really appreciated
Comments
Hi potatoSalad.
One of my colleagues with an interest in python found this blog post useful:
It uses a different Linux distribution, but most of it can be applied to PLCnext Control devices, I think.
I hope this helps.
Thank you for your suggestion, Martin. In following this process, I've found I'm not able to create a new shell script to the init.d folder. Attempting to add testApp_Service.sh to the folder through my ssh VSCode gives me an error message indicating that I don't have permission, logged in as admin, to create said file. I attempted to open permissions with chmod and change ownership to admin with chown, but those were both not allowed commands.
The directory
/etc/init.d
is owned byroot
and can only be written to by the owner:... so you will need to log in as root to write a file to that directory.
Ah! I see that I can log in as root. I was not aware of that- I assumed that admin would have all permissions. So, this is confusing.
Activating SSH login as root user
Step 1: Connect to the controller and log in as the root user.
This link was more helpful. I was able to set the root password and log in. Attempting to create boot script now.
No, never mind. I'm not able to log in as root.
Ok, I've come a long way (I think) toward actually making this work. Now, I'm getting a few errors.
Firstly, the service script in the article you linked has this line:
This is, I think, meant to evoke the daemon functions used?
Help would be really really appreciated. I feel like I'm close. *fingers crossed*
So, I commented out the daemon logging and the init-functions call. I was able to execute my bootService_testApp.sh and the python script apparently executed as a result. Awesome! Bad news, it wasn't able to find the PyPlcnextRsc module.
My PyPlcnextRsc module is installed at:
I get the feeling that this install location may be making my service execution in /etc/init.d/ fail?
I don't know much about python or anything about that package, but does this help?
https://stackoverflow.com/questions/36936212/how-do-i-install-a-pip-package-globally-instead-of-locally
Running a pip -H install to the global root did allow the script to run. Now, as root user, I can execute the
This is resulting in my python program running in the background. However, it isn't running with a power cycle of the PLCNext controller.
~~~~~~~~~~~~~~~~~~~~
Running the update-rc command from the article, I'm getting:
Hello,
please make sure that there is no linebreak or space at the start of your script - init.d does not like that.
e.g.
"
#! /bin/bash
"
Also please check /var/log/boot and other log files for a indicator if the script is started - but crashes.
How do you call your binary in the Init.d Script?
python mypy.py
python mypy.py &
start-stop-daemon ....
kind regards,
Oliver
Hi Oliver,
This is the script I'm using:
So I have two directories that I'm working with...
First, obviously, is /etc/init.d/
My "working" directory is /opt/plcnext/testApp/
Inside the testApp folder I have a copy of the bootService_testApp.sh that I edit while logged in as admin. I am unable to ssh with root login. So, my process is this:
The python program main.py in /testApp/ does then run (I have it toggling a bit in the PLC which I can view live in PLCnext Engineer.
Thanks for taking a look at this, Oliver. My much more linux savvy coworker took a look at this with me over the weekend and we could NOT figure it out.
And, I did reboot the controller after eliminating all spaces in the .sh, as you can see, and the python program did not run.
As you can see, I commented out all of the log_daemon_msg and log-end-msg stuff because Phoenix Contact's implementation of Linux just doesn't have the /lib/lsb/init-functions source file. 🤷♂️
Hello potatoSalad,
how is your app connecting to a PLCnext Service and what is the behavior when this service is not yet available?
PLCnext Runtime and the Services are starting very late during boot.
Maybe that service is not started yet resulting in a crash of your Py application.
Maybe $local_fs $network is required for start?
For some debugging in /var/log you can substitute
with echo or 'echo "..." >> /var/log/yourlog.'
or start -stop daemon with
-C, --no-close
and
This is the package I'm using for PLC interface:
Here:
you can see under Create Connection:
This is the python program main.py:
Because the with-block style instantiation of a connected device is supposed to automatically handle connections, I didn't think booting before the PLC start would be an issue.
I don't think that will work if the PLCnext Runtime is not running when the
while True
loop is entered.You could try putting a delay (maybe 30-60 seconds) in your code, before the
while True
loop, to see if that makes a difference.Well, I put a 60 second timer on it and it actually worked! It must have been that the python program was crashing. I'll look into how to bulletproof that process. There must be a way to query whether the PLCnext Runtime is running before attempting variable read/write.
Also, someone had asked about whether I could run
which I cannot. The status command calls the case block
And fails on
I'm guessing status_of_proc is part of the /lib/lsb/init-functions source file that PLCnext's Linux implementation does not support.
So, I figured it all out. And I made a tutorial explaining how to do it, start to finish.
https://youtu.be/PgFZlK38kKc
And, the timer is no longer necessary because I wrapped the RSC connection in a Try Except block so that the PLC will attempt to connect once per second upon boot until the PLC Runtime is able to connect.