2

For context, I am using a Raspberry Pi 2 model B, and I am trying to run a continuous python script when the pi boots up. The script uses the GPIO Pins, and with the data it recieves, it changes values of key variables that I am using for my project. I have tried using cron and rc.local, but nothing works for me. It seemed that all of my problems stemmed from the $DISPLAY environment variable, but I couldn't find a way around it. I tried to wait until the variable was set, but still had issues with it, saying that it couldn't connect to the display. But now I am starting to think it may be irrelevant. I am not sure what to do here.

Edit: Some more info was requested and here it is. The way the script changes the values of the variables is through a website link which is hosted by the pi. When it is accessed, the variable state will change. I have put try and except statements into my script so that if it cant access the website, it will try again every 10 secs until it does. This script also isn't a GUI script. This script is meant to run in the background and perform logic with GPIO inputs. I thought I might include this even though I don't think the error has anything to do with it. I am using crontab at the moment to try and run it. The code I am using in crontab is this:

@reboot (sudo idle -r /home/pi/Documents/StatUpdate.py > /home/pi/Documents/logs/logFile.txt 2>&1)

This command can also be run in the command line manually to start the script without error, and the script will work when manually started. The error is this:

Traceback (most recent call last):
  File "/usr/bin/idle", line 5, in <module>
    main()
  File "/usr/lib/python3.7/idlelib/pyshell.py", line 1488, in main
    root = Tk(className="Idle")
  File "/usr/lib/python3.7/tkinter/__init__.py", line 2023, in __init__
    self.tk = _tkinter.create(screenName, baseName, className, interactive, wantobjects, useTk, sync, use)
_tkinter.TclError: no display name and no $DISPLAY environment variable

I have also tried to get the pi to wait until the display variable is set using this command: until [ -n "${DISPLAY}" ]; do :; done; before the sudo idle command. When I do, the error goes away in the log, but it seems that the script still doesn't run. I hope this info helps.

5
  • Can you put the aactual error up here so we stand a chance? A link to the script (if on github / pastebin) or the relevant lines would help...
    – user115418
    Commented Jun 14, 2020 at 15:58
  • Can you start the script from the commandline? If so, what exactly is the command? Please don't answer with a comment, add the information to the question.
    – Ingo
    Commented Jun 14, 2020 at 16:29
  • @Ingo I have updated the question again and have added more details.
    – SwampyX
    Commented Jun 15, 2020 at 18:45
  • I have voted to reopen. The error message is a bit unclear. Does it comes up when executing from the command line?
    – Ingo
    Commented Jun 15, 2020 at 21:00
  • @Ingo: idle is a GUI program that depends upon tcl/tk. This Q&A may explain more.
    – Seamus
    Commented Jun 16, 2020 at 1:07

2 Answers 2

4

Because the script is running from the command line without error, you can create a systemd Unit file with the same environment of the command line. You do not need to wait with a sleep because it has complete control about dependencies to other services. Thanks to @Seamus, telling that idle needs a graphical environment. Create a new service with:

rpi ~$ sudo systemctl --force --full edit StatUpdate.service

In the empty editor insert these statements, save them and quit the editor:

[Unit]
Description=My StatUpdate script
After=graphical.target

[Service]
User=pi
WorkingDirectory=/home/pi
Environment=DISPLAY=:0
ExecStart=/full/path/to/idle -r /home/pi/Documents/StatUpdate.py

[Install]
WantedBy=graphical.target

Enable the new service and reboot:

rpi ~$ sudo systemctl enable StatUpdate.service
rpi ~$ sudo systemctl reboot

The output of the script you will find in the journal:

rpi ~$ journalctl --boot=0 --unit=StatUpdate.service

If you get an error message saying that it cant connect to display :0, then look at the command line with echo $DISPLAY, what environment variable is set before starting idle.

5
  • Now it produces another error saying that it cant connect to display :0.
    – SwampyX
    Commented Jun 17, 2020 at 13:52
  • @SwampyX I have updated the answer at the end. Please follow the answer for further changes. I will not notify again with a comment.
    – Ingo
    Commented Jun 17, 2020 at 15:49
  • 1
    the problem lied with the WantedBy=graphical.target line. When I moved it under Unit, and changed the command to After=graphical.target, it worked with no errors. Other than that, I am satisfied with your answer.
    – SwampyX
    Commented Jun 17, 2020 at 22:15
  • @SwampyX Thanks for the hint. No problem with DISPLAY=:0 anymore?
    – Ingo
    Commented Jun 17, 2020 at 23:33
  • no. Everything works without error.
    – SwampyX
    Commented Jun 18, 2020 at 1:19
3

I don't know what you are trying to do - starting idle at boot?? You have your Pi connected to a monitor? The website involvement is also confusing. Pretty fuzzy question, IMHO.

Nevertheless:

As it usually happens if a script/command/program runs successfully from the command line (as you said this one did), then the solution is usually sleep:

@reboot (sleep 30; sudo idle -r /home/pi/Documents/StatUpdate.py) > /home/pi/Documents/logs/logFile.txt 2>&1
3
  • My goal was to avoid sleep, but I guess I will use it if it works. The website involvement I guess was pointless but I wanted to give enough information to answer the question that I had. I wanted to run idle at boot, that was what I wanted to do. But thank you for the answer.
    – SwampyX
    Commented Jun 16, 2020 at 1:39
  • @SwampyX: Did that work - did it fix your problem? Wrt sleep - yeah, it's a bit of a kludge. Using systemd would allow you to avoid sleep, but not necessarily the delay. Problem is cron only knows when it started - it has no visibility of other resources you may need. And there's nothing "magic" about 30 seconds... 2 seconds might also work - it's trial-and-error though.
    – Seamus
    Commented Jun 16, 2020 at 3:50
  • Yes, it does work.
    – SwampyX
    Commented Jun 17, 2020 at 13:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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