1

I have a python script running with an RFID reader. The script runs fine when ran from terminal. When I add python /home/pi/script.py & to /etc/profile and reboot the Raspberry Pi, the scripts launches fine but gets stuck in this except:

while True:
#Setting up the RFID reader
    try:
        reader = mercury.Reader("tmr:///dev/ttyUSB0")
    break
except TypeError:
    print('Error, manual reset. Retrying')

Why can't I access the USB port when running the python script on boot in /etc/profile?

EDIT

  1. attempt to fix the issue. Instead of adding it to /etc/profile, add it to /etc/rc.local. The script won't run when doing this.

EDIT

I needed to sudo raspi-config and set the RPi to auto boot in desktop mode logged in as user pi. It now works!

Daniel
  • 113
  • 6
  • 1
    the /dev/ttyUSB0 does not exist at the time when you run your code ... run the code later in the boot sequesnce – jsotola Apr 20 '18 at 21:51
  • 1
    Review: I'd like to see more of the Python code, starting from the shebang and including the import(s). Also, perhaps information about the Mercury wrapper ( https://github.com/gotthardp/python-mercuryapi ) and why it is being used instead of serial. In the end, I see an answer in comments that is probably correct. If the port does not yet exist then there would be no way to open it. However, if that is really the answer then it would be best posted as such, with instructions about how to "run the code later in the boot sequence." – SDsolar Apr 20 '18 at 23:56
  • @SDsolar, i have no idea, off the top of my head, how to run the code later in the sequence. i only have a general idea of how linux behaves during the boot process ....... lol, i see that i misspelled sequence – jsotola Apr 21 '18 at 03:55

3 Answers3

2

There is no relation between /etc/profile and the boot process. Add your script to the init process.

Gerard H. Pille
  • 461
  • 2
  • 5
  • 1
    Better add a sleep to your script too, so that other processes get a chance in between retries. – Gerard H. Pille Apr 21 '18 at 02:26
  • @GerardH.Pille I have tried to find a guide to "Add your script to the init process". Do you agree with the process done here(in method 3): https://www.dexterindustries.com/howto/run-a-program-on-your-raspberry-pi-at-startup/ – Daniel Apr 21 '18 at 09:15
  • I would say yes if I was sure your system is using sysvinit, but nowadays most distributions have switched to the systemd moloch, and then you'd need solution 4 or the answer given here by Ingo. – Gerard H. Pille Apr 21 '18 at 12:13
1

As @jsotola adviced, you could run it later in the boot process.... or you can write your script to keep on trying to open the port over and over again till it's available (with a certain delay of a few seconds between attempts so that you don't go into a tight loop).

Addendum: Apparently the tip that was followed was to start the script from rc.local... this is my full comment, just in case:

Another would be to add it to /etc/rc.local which is run at the end of the boot sequence, if I'm not mistaken. Just make sure that the process actually goes in the background so that the script doesn't hang (run it with &, for example). There might be other details to take care but it should take care of running it veery late on the boot process.

Hope that's good enough to anyone looking for an answer later on.

eftshift0
  • 750
  • 1
  • 7
  • 12
  • How would you run it later in the boot process? – Daniel Apr 21 '18 at 09:24
  • 1
    One way would be to add it to systemd (which has already been adviced). Another would be to add it to /etc/rc.local which is run at the end of the boot sequence, if I'm not mistaken. Just make sure that the process actually goes in the background so that the script doesn't hang (run it with &, for example). There might be other details to take care but it should take care of running it veery late on the boot process. But the simplest thing is just to make your script attempt to open the port every so often (say, every second.... or every 2 or 5 seconds) until it does open. – eftshift0 Apr 21 '18 at 14:27
  • The information you placed in the comment about /etc/rc.local should be added to this answer. This solved the problem, and I therefore accept this answer. – Daniel Apr 22 '18 at 19:20
1

Start your script as service. First create a new service with:

rpi3 ~$ sudo systemctl edit --force --full rfid-reader.service

Insert this statements, save them and quit the editor:

[Unit]
Description=Setting up the RFID reader
Wants=sockets.target
After=sockets.target

[Service]
Type=simple
User=pi
WorkingDirectory=/home/pi
ExecStart=/home/pi/script.py

[Install]
WantedBy=multi-user.target

Check the new service:

rpi3 ~$ systemctl status rfid-reader.service
● rfid-reader.service - Setting up the RFID reader
   Loaded: loaded (/etc/systemd/system/rfid-reader.service; disabled; vendor preset: enabled)
   Active: inactive (dead)

Now you can enable and test your service:

rpi3 ~$ sudo systemctl enable rfid-reader.service
rpi3 ~$ sudo systemctl start rfid-reader.service

I cannot test it because I have no RFID reader. You are alone with this. Here are some commands that may help:

rpi3 ~$ systemctl status rfid-reader.service
rpi3 ~$ systemctl cat rfid-reader.service
rpi3 ~$ sudo systemctl restart rfid-reader.service
rpi3 ~$ sudo systemctl edit --full rfid-reader.service

One problem is that I cannot check out for you the target after that /dev/ttyUSB0 is available. In the example above I use sockets.target. Don't know if this already initialised /dev/ttyUSB0. With

rpi3 ~$ systemctl

you will find what services and targets are active. Only look at the targets. Other candidates for Wants= and After= seem to be:

local-fs.target   Local File Systems
sysinit.target    System Initialization
basic.target      Basic System

If sockets.target does not work I would try other targets in this order.

Ingo
  • 42,107
  • 20
  • 85
  • 197
  • When starting it as a service, would it than run on every time /dev/ttyUSB0 is available? – Daniel Apr 21 '18 at 09:56
  • 1
    @DanielRobotics It is a service like any other service and can run as daemon. This simple example has by default Type=simple. You didn't said that you want to monitor the status of /dev/ttyUSB0. This is a bit more complicated. You have to modify your script to work as a daemon and maybe start it with an other Type=, maybe forking or dbus. Have a look at man systemd.service option Type=. – Ingo Apr 21 '18 at 10:31
  • @DanielRobotics Or maybe you can use udev with a proper rule instead of running a service. – Ingo Apr 21 '18 at 10:43