2

--------- LAST UPDATE ---------- I moved on to a different question since I had not accurately spotted the problem. The problem is that cv2 module can not be found when the script is triggered either by crontab or a .desktop -> bash script...

I'm trying to have a python script triggered at boot, followed several guides but it doesn't happen 😊

I've tried putting a .desktop file with the following contents

[Desktop Entry]
Encoding=UTF-8
Type=Application
Name=<GUI Controller>
Comment =
Exec = python3 /home/username/Recorder/main.py
StartupNotify=false
Terminal=true
Hidden=false

Both at

/home/username/.config/autostart/autorun.desktop

And at

/etc/xdg/autostart/screenrecorder.desktop

Any obvious mistakes I made?

------------- EDIT -------

It is set to auto-login so the relevant user is logged in at boot.

I have also tried this guide with no effect https://www.instructables.com/Raspberry-Pi-Launch-Python-script-on-startup/

If I run the .sh script manually my py script launches, but adding it to the crontab does not start it, nor does it add anything to the logs directory as in the tutorial.

The script is a work i progress, but here it is, and it works great if I doubleclick the main.py icon but for some reason nothing I do will trigger it to run on boot

import cv2
import time
import os
import sys
import configparser
from playsound import playsound

config = configparser.ConfigParser()
config.read('config.ini')


### >>> Breakout into reusable snippet? Also used in cleanup.py
#
# Recordings_buffer = int(config['SETTINGS']['Recordings_buffer'])
# OS_buffer = int(config['SETTINGS']['OS_buffer'])
# disk_size = int(config['SETTINGS']['disk_size'])
#
# accumulated_recordings = xxGB #(check recordings folder)
#
#disk_free = disk_size - os_buffer - ackumulated_recordings # OR read from OS actual disk_free value
### <<< Breakout into reusable snippet?

# if (disk_free < Minimum_disk) {
#    
#    #write to log file 
#    print("[" + time.strftime("%Y%m%d-%H%M%S")) + "] Error: recording stopped, disk space too low (" + disk_free + "GB) /main.py"
#
#   #create flagfile out_of_disk.txt
#
#    return 0
# }


minutes = int(config['SETTINGS']['Minutes'])
width = int(config['SETTINGS']['Width'])
height = int(config['SETTINGS']['Height'])
video_codec = cv2.VideoWriter_fourcc("D", "I", "V", "X")
cwd = os.getcwd()
name = os.path.join(cwd, "RadarRecordings")

if os.path.isdir(str(name)) is False:
    os.mkdir(str(name))

print("RadarRecorder started: " + time.strftime("%Y%m%d-%H%M%S"))
print("Files will be saved in this location: ", name)

cap = cv2.VideoCapture(0)
fps = cap.get(cv2.CAP_PROP_FPS)
ret = cap.set(3, width)
ret = cap.set(4, height)
cur_dir = os.path.dirname(os.path.abspath(sys.argv[0]))

start = time.time()
video_file = os.path.join(name, time.strftime("%Y%m%d-%H%M%S") + ".avi")
   
# Create a video write before entering the loop
video_writer = cv2.VideoWriter(
    video_file, video_codec, fps, (int(cap.get(3)), int(cap.get(4)))
)

frame_counter = 0
signal_state = True

while cap.isOpened():
    start_time = time.time()
    ret, frame = cap.read()
    if ret == True:
        is_frame_black = cv2.countNonZero(cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)) == 0

        if is_frame_black == False and signal_state == False:
            print("signal restored")
            signal_state = True
        
        if is_frame_black == True and signal_state == True:
            print("signal lost")

            # Skapa textfil
            with open(f"{cwd}\signal_lost.txt", "w") as f:
                f.write("signal lost")

            # for loop nedan ska tas bort
            for x in range(10):
                playsound('warning_signal_lost.wav')

            # create logfile if doesnt exist, write [timestamp - message]
            # if logfile exists, newline and insert [timestamp - message]
            signal_state = False

        frame_counter += 1

        cv2.putText(frame, time.strftime("%Y-%m-%d %H:%M:%S" + " UTC" + " - www.naviation.se"), (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 3, cv2.LINE_AA)
        cv2.putText(frame, time.strftime("%Y-%m-%d %H:%M:%S" + " UTC" + " - www.naviation.se"), (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1, cv2.LINE_AA)

        cv2.imshow("Naviation RadarRecorder", frame)

        video_length = int(fps) * 60 * minutes

        if frame_counter > video_length:
            frame_counter = 0
            start = time.time()
            video_file = os.path.join(name, time.strftime("%Y%m%d-%H%M%S") + ".avi")
            video_writer = cv2.VideoWriter(
                video_file, video_codec, fps, (int(cap.get(3)), int(cap.get(4)))
            )

        # Write the frame to the current video writer
        video_writer.write(frame)
        if cv2.waitKey(1) & 0xFF == ord("q"):
            break
    else:
        break
cap.release()
cv2.destroyAllWindows()

------------- Details added --------

Raspbian GNU/Linux 11 (bullseye) Systemd 247.3.7

--------------- Progress -------------------

I managed to get Raspbian to attempt to launch my script via a launcher.sh looking like this

#!/bin/sh
# launcher.sh
# navigate to home directory, then to this directory, then 
execute python script, then back home

cd /
cd home/RecorderV1/Recorder
/usr/bin/python3 main.py
cd /

And a line in the sudo crontab like this: @reboot sh /home/RecorderV1/Recorder/launcher.sh >/home/RecorderV1/Recorder/logs/cronlog 2>&1

However, running that launcher script manually (doubleclicking it) works fine. Triggering it via crontab generates the following error log:

RuntimeError: module compiled against API version 0xf but this version of numpy is 0xd Traceback (most recent call last): File "/home/NaviationRadarRecorderV1/RadarRecorder/main.py", line 1, in import cv2 File "/usr/local/lib/python3.9/dist-packages/cv2/init.py", line 181, in bootstrap() File "/usr/local/lib/python3.9/dist-packages/cv2/init.py", line 153, in bootstrap native_module = importlib.import_module("cv2") File "/usr/lib/python3.9/importlib/init.py", line 127, in import_module return _bootstrap._gcd_import(name[level:], package, level) ImportError: numpy.core.multiarray failed to import

I tried pip install numpy --upgrade as suggested here (https://stackoverflow.com/questions/71986643/userwarning-failed-to-initialize-numpy-module-compiled-against-api-version-0xf) but no difference.

--------- LAST UPDATE ---------- I moved on to a different question since I had not accurately spotted the problem. The problem is that cv2 module can not be found when the script is triggered either by crontab or a .desktop -> bash script...

5
  • "I'm trying to have a python script triggered at boot" what does this mysterious script DO?
    – Milliways
    Sep 5 at 9:51
  • Hehe, is it relevant to whether it triggers or not? =) It's video capture. Sep 5 at 11:17
  • Yes, it could very relevant. Perhaps video capture needs the windowing system active...
    – NomadMaker
    Sep 5 at 12:37
  • Is the windowing system disabled as per my config above? Sep 5 at 14:46
  • Try this. Exec=/usr/bin/python3 /home/username/Recorder/main.py Sep 14 at 9:33

3 Answers 3

0

The obvious mistake is, that you do not run at boot time, but only when username logs in.

The most obvious way to start something at boot is to use a systemd unit file /lib/systemd/system/recorder.service with

[Unit]
Description=Recorder
After=multi-user.target

[Service]
Type=idle
ExecStart=/usr/bin/python3 /home/username/Recorder/main.py

[Install]
WantedBy=multi-user.target

and tell systemd to start it at boot:

sudo systemctl daemon-reload
sudo systemctl enable recorder.service

Another way would be to use cron. Do sudo crontab -e and add the line

@reboot /usr/bin/python3 /home/username/Recorder/main.py
1
  • I've tried both of those methods you suggest, nothing happens on boot. If I try to start your code manually by "systemctl --user start recorder.service I get the following error: "Failed to start recorder.service: Unit recorder.service not found" Sep 5 at 14:59
0

There are 2 obvious errors python3 lacks path BUT more fundamental problems are that crontab runs and BEFORE there IS a GUI!

1
  • Are you saying that my dot-desktop file needs full path to python3 rather than my "Exec = python3 /home/"? And your second comment, is that essentially saying I can't use crontab for this but should use the approach with a dot-desktop file or is there a way to trigger my script from crontab After GUI is loaded rather than to do it at boot? Sep 11 at 8:03
0

Try running python3 -m site > site.log from  crontab and check the sys.path section. Perhaps you have multiple versions of numpi or cv2 installed on your system and your script fails to find the right one.

Note that Python packages installed with apt usually go to /usr/lib/, while packages installed with pip end up in /usr/local/lib/. Perhaps adding the path containing numpy / cv2 to sys.path in your crontab script will resolve your issue. You can do this by modifying PYTHONPATH environment variable before calling Python, or using sys.path.append() in your Python code. E.g.

export PYTHONPATH=/usr/local/lib/python3.9/dist-packages/:$PYTHONPATH python3 /home/username/Recorder/main.py

It could be that the right directory is already in sys.path. In that case, removing outdated versions of numpy / cv2 might help, as it will force Python to keep searching for the correct version through the rest of sys.path.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.