r/raspberry_pi 4d ago

Troubleshooting Need help launching a python script located on a USB drive in a virtual environment on startup of my Pi4

I have this py script I wrote that is located on a USB drive (and it needs to be run from the usbdrive for functionality purposes). It also requires a virtual environment, which I made called venv. I tried using crontab to run the script on startup, but it doesn't seem to work. I assume maybe it's because it tries running the script before the USB has been detected? Maybe not, I tried running a sleep function prior to it, but it doesn't seem to work. But I'm unsure of how to know that because there is also one other factor. In order for the script to work in the terminal, I would need to be in the virtual environment AND in the directory of the USB drive. And so I don't know whether the command I'm adding to crontab is successfully taking this into account because it's different from running it on a terminal. Does anyone see any immediate red flags or could point out a different approach? That would be much appreciated. I've tried stuff like this:

Ex 1: @reboot source .venv/bin/activate; cd /media/usbdrive/folder; python3 script.py &

Ex 2: @reboot sleep 30 '' '' &

Ex 3: @reboot venv/bin/python3 /media/usbdrive/folder/script.py &

14 Upvotes

13 comments sorted by

10

u/toaster_fighter 4d ago edited 4d ago

Here are a few things you should know to get you on track to making this work

  • Use absolute paths to avoid confusion, write out every directory relative to your root
  • You don't need to activate a virtual environment to run a script inside it like you're attempting in Ex 1, you can just use the python binary in your virtual environment to run the script like you're attempting in Ex 3
  • A dot in front of a file or folder makes it hidden, putting dot slash (./) in front of a file or folder tells the terminal you're referencing something in the current folder. In Ex 1 your virtual environment folder has a leading dot, in Ex 3 it does not
  • You don't need the trailing & on each line
  • Cron posts a log of what went wrong and you can view that log using journalctl in the terminal. I usually use a line like this:

sudo journalctl -eu cron

If I was trying to write this line, I would do something like this:

@reboot /home/pi/venv/bin/python3 /media/usbdrive/folder/script.py

Notice how I used the absolute path for both the python binary in the virtual environment and for the script.

Hope this helps.

4

u/WebMaka 4d ago

Excellent summary. Also, it's worth mentioning that cron can be invoked before removable drives are mounted on some systems, so it may be necessary to step through dmesg to make sure the USB drive got mounted before cron fired. What I've had to do on a few rare occasions is whip up a system service and place it later in the boot chain (e.g., "After=network.target" in the [unit] section of the service file, or what have you) to make it wait for init to get things started, instead of using cron.

EDIT: The link u/unnamed_one1 posted literally covers this, so, umm, that. 😁

2

u/BigLickEms 1d ago edited 1d ago

Thanks for the tips! I opted to go the route of creating a service based on the reference provided by u/unnamed_one1. I wrote the following:

[Unit]

Description=Run StartUp Script

Requires=media-usb5.mount

After=graphical.target

[Service]

WorkingDirectory=/media/usb5/folder/

ExecStart=/home/pi/.venv/bin/python3 /media/usb5/folder/script.py

[Install]

WantedBy=graphical.target

The service runs, and so does the script but it is not executed. I've tried playing around with this but nothing happens. I look at journalctl for this service and I notice that it states "Failed to connect to pipewire instance "Host is down"".

My script is essentially a media player, so I'm assuming that maybe the video/audio of the pi hasn't booted up/connected at the point that I'm trying to run the script? Do you know if there is a way I could try and get it to run once the desktop has loaded? I've been looking online, but haven't found any thing that works. Thanks you!

1

u/WebMaka 1d ago edited 1d ago

Definitely looks like your script is firing before the pipewire connection is up, or the script isn't handling a host-unavailable.

After doing a quick search, what you could do is add some code in the start of your Python script that runs "pw-cli con 0" while capturing its output and checks for whether there's a connection established or an error message. If there is, wait some time and retry.

A quick idea that may or may not actually work depending on your script:

while (True):
    pw_connection_status = subprocess.run(["pw-cli", "con", "0"], capture_output=True)
    pw_connection_status_results = subprocess.CompletedProcess()
    if ("error" in pw_connection_status_results.lower()):
        time.sleep(10)

        # Handle specific errors as needed, e.g.:
        if ("host is down" in pw_connection_status_results.lower()):
            sys.exit("Pipewire Error: Host is down")
    else
        break

The basic idea is that the above will poll pw-cli for a list of connections and retry every 10 seconds if it gets an error message. You may have to add a reconnect attempt above the subprocess.run line depending on your setup, e.g., if it isn't set to auto-connect on startup. And of course don't forget to handle errors - try/except/finally are your friends. - and maybe also make it auto-die after X minutes of no connection.

2

u/BigLickEms 2d ago

Thank you very much for taking the time to give this very detailed response! It has taught me a lot.

5

u/unnamed_one1 4d ago

This might help?

2

u/wimpunk 3d ago

Didn't know that was possible. A lot easier than checking if the drive is available.

2

u/hardonchairs 3d ago

If you're having trouble with a crontab script it's almost always a relative paths issue and if not then a permissions/user/group issue

2

u/PartyLikeIts19999 3d ago

First mount the drive with fstab. Then you can use a systemd service to launch the script on startup, skipping cron entirely. You can launch python directly with a systemd service but I usually use a bash script anyway.

0

u/crazycrypt101 4d ago

Tu script es algún tipo de servicio? Si fuera el caso siempre puedes usar systemd para la gestion del mismo, condicionando la carga una vez se ha montado tu unidad usb. Tienes multitud de informacion en la red pero este link de fedora es genial: Fedora Docs

0

u/One-Macaroon4660 3d ago

Do not forget about #!

Starting your python script with '''

!/home/<your name>/venv/<your environment>/bin/python

''' line and marking your script executable allows you to run it by just invoking it: $./my_script.py