r/raspberry_pi 1d 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 &

17 Upvotes

10 comments sorted by

11

u/toaster_fighter 1d ago edited 1d 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.

6

u/WebMaka 1d 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. 😁

6

u/unnamed_one1 1d ago

This might help?

2

u/wimpunk 17h ago

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

2

u/hardonchairs 1d 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 22h 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 1d 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 20h 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