Page 1 of 1

python file won't run on boot from crontab

Posted: Wed Jun 10, 2020 10:47 pm
by alphanumeric
I have done the sudo crontab -e and added the following line

Code: Select all

@reboot python3 /home/pi/scroll_clock.py &  
But It doesn't run on boot up. I have done this many times in the past and it worked fine?
If I run

Code: Select all

python3 /home/pi/scroll_clock.py
from a terminal window it runs fine. Launching it from idle also works.

Raspberry Pi Zero running the latest Raspberry Pi OS with a Unicorn Hat Mini attached.
The following code displays the day, date, time in a repeating scrolling message. The brightness up down works as does the shutdown when button X is pressed.

Code: Select all

#!/usr/bin/env python3
import sys
import os
import time, datetime
import RPi.GPIO as GPIO

from PIL import Image, ImageDraw, ImageFont
from unicornhatmini import UnicornHATMini

unicornhatmini = UnicornHATMini()

GPIO.setmode(GPIO.BCM)  
GPIO.setwarnings(False)
GPIO.setup(5, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(6, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(16, GPIO.IN, pull_up_down = GPIO.PUD_UP)

# button_map
#  5: "A",
#  6: "B",
# 16: "X",
# 24: "Y"}

X = 0



def Dim(channel):  
    unicornhatmini.set_brightness(0.5)

def Bright(channel):  
    unicornhatmini.set_brightness(1.0)

def Shutdown(channel):  
    global X
    X = 1    

GPIO.add_event_detect(5, GPIO.FALLING, callback = Dim, bouncetime = 2000)
GPIO.add_event_detect(6, GPIO.FALLING, callback = Bright, bouncetime = 2000)
GPIO.add_event_detect(16, GPIO.FALLING, callback = Shutdown, bouncetime = 2000)
#GPIO.add_event_detect(24, GPIO.FALLING, callback = Shutdown, bouncetime = 2000)

rotation = 180
if len(sys.argv) > 1:
    try:
        rotation = int(sys.argv[1])
    except ValueError:
        print("Usage: {} <rotation>".format(sys.argv[0]))
        sys.exit(1)

unicornhatmini.set_rotation(rotation)
display_width, display_height = unicornhatmini.get_shape()

print("{}x{}".format(display_width, display_height))

unicornhatmini.set_brightness(0.5)

font = ImageFont.truetype("5x7.ttf", 8)

offset_x = 0

while True:

    if offset_x == 0:
        text = time.strftime("%A %B %-d %-I:%M %p")
        text_width, text_height = font.getsize(text)
        image = Image.new('P', (text_width + display_width + display_width, display_height), 0)
        draw = ImageDraw.Draw(image)
        draw.text((display_width, -1), text, font=font, fill=255)
    else:
        
        for y in range(display_height):
            for x in range(display_width):
                if image.getpixel((x + offset_x, y)) == 255:
                    unicornhatmini.set_pixel(x, y, 0, 255, 0)
                else:
                    unicornhatmini.set_pixel(x, y, 0, 0, 0)

    offset_x += 1
    if offset_x + display_width > image.size[0]:
        offset_x = 0

    if X == 1:
        unicornhatmini.set_all(0, 0, 0)
        unicornhatmini.show()
        os.system("sudo shutdown now -P")
        time.sleep(30)

    unicornhatmini.show()
    time.sleep(0.05)

# Last edited on June 6th 2020
# added shutdown via button X
# also added Dim and Bright function to button A and B
# run sudo crontab -e
# add
# @reboot python3 /home/pi/scroll_clock.py &




Re: python file won't run on boot from crontab

Posted: Thu Jun 11, 2020 9:15 am
by pcmanbob
Try changing your cron line to this

Code: Select all

@reboot python3 /home/pi/scroll_clock.py >> /home/pi/error.txt 2>&1
then reboot your pi , hope fully you will have an error message in the file error.txt which will give you a clue as to why it stopped working.

As a side not you don't need the & at the end of a cron line, all programs run by cron are run in the background , even if you have multiple cron lines they will be run one after another without waiting for each program to complete.

Re: python file won't run on boot from crontab

Posted: Thu Jun 11, 2020 11:01 am
by alphanumeric
Thank you I will try that. I was going to try again without then & at the end.

Re: python file won't run on boot from crontab

Posted: Thu Jun 11, 2020 1:55 pm
by alphanumeric
Ok, the error is as follows

Code: Select all

Traceback (most recent call last):
  File "/home/pi/scroll_clock.py", line 58, in <module>
    font = ImageFont.truetype("5x7.ttf", 8)
  File "/usr/lib/python3/dist-packages/PIL/ImageFont.py", line 280, in truetype
    return FreeTypeFont(font, size, index, encoding, layout_engine)
  File "/usr/lib/python3/dist-packages/PIL/ImageFont.py", line 145, in __init__
    layout_engine=layout_engine)
OSError: cannot open resource
If I change
font = ImageFont.truetype("5x7.ttf", 8)
to
font = ImageFont.load_default()
My file runs from crontab. It looks awful on the LED Matrix, but it runs.
The font file 5x7.ttf is in the same folder as my file, and running my file from command line or from idle3 works OK.

Re: python file won't run on boot from crontab

Posted: Thu Jun 11, 2020 2:34 pm
by alphanumeric
I found a solution, it looks like you need to include the path to the file.
I changed
font = ImageFont.truetype(“5x7.ttf”, 8)
to
font = ImageFont.truetype(“/home/pi/5x7.ttf”, 8)
and now it runs on boot. =)

Re: python file won't run on boot from crontab

Posted: Thu Jun 11, 2020 9:50 pm
by pfletch101
alphanumeric wrote:
Thu Jun 11, 2020 2:34 pm
I found a solution, it looks like you need to include the path to the file.
I changed
font = ImageFont.truetype(“5x7.ttf”, 8)
to
font = ImageFont.truetype(“/home/pi/5x7.ttf”, 8)
and now it runs on boot. =)
If you are running a script from crontab, it needs to include the full path to any file that it may need to access, since you cannot make any assumptions about where its home directory is.

Re: python file won't run on boot from crontab

Posted: Thu Jun 11, 2020 10:21 pm
by GlowInTheDark
If you are running a script from crontab, it needs to include the full path to any file that it may need to access, since you cannot make any assumptions about where its home directory is.
This is FRN (*). First of all, the home directory is what it is. Regardless of where you are, your home directory is /home/pi. You can assume that. Always.

What I think you meant to say is that you cannot make any assumption about what the current directory is; that also is FRN. When a cronjob runs as user X, the current directory (unless/until changed by the job itself) is the home directory of X (often written: ~X). In our case, it will be /home/pi.

The confusion that results in people asserting this FRN is that the PATH in cronjobs is minimal compared to what it usually is (when one is running interactively). This leads people to the (often correct) assumption that they need to supply full paths on the programs they run (e.g., if you are running something that is stored in, say, /usr/games, you will need to specify /usr/games/whatever, since /usr/games in not in the default [minimal] PATH). This leads them to the incorrect assumption that *everything* needs a full path.

Note: I think (but am not certain, that is why I say "think") that fonts are looked up via a PATH sort of mechanism that, like the executable PATH mechanism, doesn't look in the current directory by default. This is probably why OP's problem occurred in the first place and why it went away when he full-path'd the font file. It is likely that using :./whatever.font would have worked as well.

Note also: I have not personally tested the @reboot functionality of crontab; I assume it works the same as regular cron jobs. If this is not the case - if, indeed, when you run via @reboot, it does indeed place you in some randomly determined directory on startup, then please let me know. I will update my files accordingly...


(*) Frequently repeated nonsense.

Re: python file won't run on boot from crontab

Posted: Thu Jun 11, 2020 11:41 pm
by pfletch101
GlowInTheDark wrote:
Thu Jun 11, 2020 10:21 pm
If you are running a script from crontab, it needs to include the full path to any file that it may need to access, since you cannot make any assumptions about where its home directory is.
This is FRN (*). First of all, the home directory is what it is. Regardless of where you are, your home directory is /home/pi. You can assume that. Always.
I said 'its home directory''. If you want to pick nits, 'current directory' is probably more correct, but not necessarily clearer to the novice.
What I think you meant to say is that you cannot make any assumption about what the current directory is; that also is FRN. When a cronjob runs as user X, the current directory (unless/until changed by the job itself) is the home directory of X (often written: ~X). In our case, it will be /home/pi.
You may or may not be right about @reboot cron jobs having the user's home directory as current directory. I didn't mean to imply that the current directory was random under these circumstances, just that you shouldn't (which would have been a better word than 'cannot') make assumptions about it. If you get into the habit of specifying full paths in scripts which you are developing to be run by cron (or systemd), you will not experience the 'my script runs at the command line but not in cron/systemd' problem which turns up in these forums at least once a week. If, on the other hand, you specify file names on the basis of assumptions about the current directory, and subsequently change how you are executing the script (user cron to different user cron or root cron; user cron to systemd unit) you will need to change all the file references, and I guarantee (from bitter experience) that you will frequently forget to do so.

Re: python file won't run on boot from crontab

Posted: Fri Jun 12, 2020 5:46 am
by GlowInTheDark
I repeat: This is FRN.

Re: python file won't run on boot from crontab

Posted: Fri Jun 12, 2020 10:03 am
by DougieLawson
GlowInTheDark wrote:
Fri Jun 12, 2020 5:46 am
I repeat: This is FRN.
Stop spouting this junk. Prove it or shut up!

If you don't know the current working directory you can't use relative file names. If you use full path names you won't go wrong (unless the file ownership prevents you).

With systemd cron (I've replaced anacron with that as I like the integration of cron with systemd)

Code: Select all

*/1 * * * * env 
gets

Code: Select all

Jun 12 10:52:06 ulysses env[4235]: LANG=en_GB.UTF-8
Jun 12 10:52:06 ulysses env[4235]: PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
Jun 12 10:52:06 ulysses env[4235]: HOME=/home/pi_u
Jun 12 10:52:06 ulysses env[4235]: LOGNAME=pi
Jun 12 10:52:06 ulysses env[4235]: USER=pi
Jun 12 10:52:06 ulysses env[4235]: SHELL=/bin/bash
Jun 12 10:52:06 ulysses env[4235]: INVOCATION_ID=96f2d69a40f94946a297ed890bac6005
Jun 12 10:52:06 ulysses env[4235]: JOURNAL_STREAM=8:589201
So python3 or any other program found in that path won't need a full path. The environment is more limited than your regular bash shell and it's running cron things with /bin/sh.

Code: Select all

*/1 * * * * pwd > /tmp/pwd
gets

Code: Select all

pi@ulysses:~ $ cat /tmp/pwd
/
pi@ulysses:~ $
so any file accessed by any script MUST have a full path.

Note: anacron may be different, so you may want to run your own tests.

Re: python file won't run on boot from crontab

Posted: Fri Jun 12, 2020 12:15 pm
by thagrol
GlowInTheDark wrote:
Thu Jun 11, 2020 10:21 pm
If you are running a script from crontab, it needs to include the full path to any file that it may need to access, since you cannot make any assumptions about where its home directory is.
This is FRN (*). First of all, the home directory is what it is. Regardless of where you are, your home directory is /home/pi. You can assume that. Always.
Not true. The home directory is wherever the admins have put it. "/home/user" is the default convention but it doesn't mean it's "always" the case.

Edit: plus not every user has a home directory. End edit.
What I think you meant to say is that you cannot make any assumption about what the current directory is; that also is FRN. When a cronjob runs as user X, the current directory (unless/until changed by the job itself) is the home directory of X (often written: ~X). In our case, it will be /home/pi.
Possible correct but also irrelevant. The OP is talking about root's crontab so if you are correct it'll be /root not /home/pi
The confusion that results in people asserting this FRN is that the PATH in cronjobs is minimal compared to what it usually is (when one is running interactively). This leads people to the (often correct) assumption that they need to supply full paths on the programs they run (e.g., if you are running something that is stored in, say, /usr/games, you will need to specify /usr/games/whatever, since /usr/games in not in the default [minimal] PATH). This leads them to the incorrect assumption that *everything* needs a full path.
As already said, when you're not sure, use the full path to a file.
Note: I think (but am not certain, that is why I say "think") that fonts are looked up via a PATH sort of mechanism that, like the executable PATH mechanism, doesn't look in the current directory by default.
Unikely, there's no font path related environment variable set in any shell I'm using.
This is probably why OP's problem occurred in the first place and why it went away when he full-path'd the font file. It is likely that using :./whatever.font would have worked as well.
Nope. see above. Plus it's a python script accessing a font file directly not through the OS so any potential path mechanism wouldn't be used.
Note also: I have not personally tested the @reboot functionality of crontab; I assume it works the same as regular cron jobs. If this is not the case - if, indeed, when you run via @reboot, it does indeed place you in some randomly determined directory on startup, then please let me know. I will update my files accordingly...


(*) Frequently repeated nonsense.
As is much of your post.

Re: python file won't run on boot from crontab

Posted: Fri Jun 12, 2020 12:37 pm
by bjtheone
Biggest issues with cron are:

1) you get a stripped down environment. Often a different shell and much shorter path. You can address this by setting the shell and path to whatever you want and then running your script via cron.

2) using sudo. If you use the command "sudo crontab -e " you are editing root's crontab file. This will have a completely different environment that the user pi, and most certainly will not have a home directory of "/home/pi". If you want to run cron jobs as user "pi", the the command is "crontab -e" issued from a terminal logged in as user "pi".

Using fully qualified paths solves many issues with cron. It is not required, if you ensure the environment is correctly setup such that relative file references resolve as expected, and the correct programs are found, but it is a simple way to address the issue. The only downside is a bit more typing, and the potential that your crontab will not run the same way on another system if all the files you reference are not in the same places. However, for a novice user it is far and away the simplest solution.

Re: python file won't run on boot from crontab

Posted: Fri Jun 12, 2020 4:24 pm
by bjtheone
thagrol wrote:
Fri Jun 12, 2020 12:15 pm
GlowInTheDark wrote:
Thu Jun 11, 2020 10:21 pm
Note: I think (but am not certain, that is why I say "think") that fonts are looked up via a PATH sort of mechanism that, like the executable PATH mechanism, doesn't look in the current directory by default.
Unikely, there's no font path related environment variable set in any shell I'm using.
I suspect @GlowInTheDark is thinking about the FontPath used by X11 and by fontconfig. This allows you to define where it looks for font files. However, as noted, this would have nothing to do with how python finds a particular file.

Re: python file won't run on boot from crontab

Posted: Fri Jun 12, 2020 6:07 pm
by thagrol
bjtheone wrote:
Fri Jun 12, 2020 4:24 pm
thagrol wrote:
Fri Jun 12, 2020 12:15 pm
GlowInTheDark wrote:
Thu Jun 11, 2020 10:21 pm
Note: I think (but am not certain, that is why I say "think") that fonts are looked up via a PATH sort of mechanism that, like the executable PATH mechanism, doesn't look in the current directory by default.
Unikely, there's no font path related environment variable set in any shell I'm using.
I suspect @GlowInTheDark is thinking about the FontPath used by X11 and by fontconfig. This allows you to define where it looks for font files. However, as noted, this would have nothing to do with how python finds a particular file.
I did wonder. In which case it's irrelevant to cron too. Well unless you cronjob explictly needs it or X11 I guess.