0

Background

I am using my Raspberry Pi B+ to control a 32x32 LED matrix and I am trying to send commands from an Android app to my Pi over bluetooth to display text on the LED matrix. I am using Xamarin Android for the Android app and I am using the PyBluez library to handle the Bluetooth

The Issue

Since what I'm making here is essentially a smart LED sign. I need to process of the Pi starting up and running the Python script PyPipe.py (Below) as stream lined as possible. In essence, I don't want to have to ssh into the Pi and start the script manually every time it the Pi shuts down.

I have been able to get the script to run on start up by putting this command to run the script in etc/rc.local

sudo ./PyPipe.py &

When I manually run the PyPipe.py script in the terminal the entire process works perfectly and executes without error, however, when the PyPipe.py script is run on startup the script errors out. For debugging purposes I made a test file that write out a few strings to a log file that tells me where the script gets in executing. The log file tells me that it throws an exception 111 Connection Refused when it tries to execute the advertise_service() method. this only happens when it runs from startup. Any Ideas on what im doing wrong?

PyPipe.py

from bluetooth import *

server_sock=BluetoothSocket( RFCOMM )
server_sock.bind(("",PORT_ANY))
server_sock.listen(1)

port = server_sock.getsockname()[1]

uuid = "94f39d29-7d6d-437d-973b-fba39e49d4ee"

advertise_service( server_sock, "NicksPiServer",
                   service_id = uuid,
                   service_classes = [ uuid, SERIAL_PORT_CLASS ],
                   profiles = [ SERIAL_PORT_PROFILE ], 
#                  protocols = [ OBEX_UUID ] 
                )

print("Waiting for connection on RFCOMM channel %d" % port)

client_sock, client_info = server_sock.accept()
print("Accepted connection from ", client_info)

try:
    while True:
        data = client_sock.recv(1024)
        if len(data) == 0: break
        print("received [%s]" % data)
except IOError:
    pass

print("disconnected")

client_sock.close()
server_sock.close()
print("all done")
  • 2
    its possible your script is trying to run before the bluetooth service has been brought up. you could try implementing a try/retry mechanism for a set period of time in the script or the better solution would be to start it with an init script (systemd service file or an init.d shell script) that only trys to bring it up after the service is available – James Kent Aug 2 '17 at 15:28
  • You were correct the PyPipe.py was getting called before the Bluetooth service had started completely. I was able to side step the issue by changing the line in rc.local to (sleep 30; ./PyPipe.py) & – Jnick020804 Aug 3 '17 at 17:59
0

James Kent Was correct. The issue was caused by the PyPipe.py script getting called before the Bluetooth service has completely started. I was able to side step this issue by changing the line in the rc.local file to

(sleep 30; ./PyPipe.py) &

Which allowed the Bluetooth service enough time to start completely before running the PyPipe.py.

This is most likely a clumsy solution to this issue and a more proper solution would be making an init.d script to handle this process

0

a proper solution to this would be to write a script to tell the init system when to start this (ie after the bluetooth service has started) however an alternative would to be wrap your call to advertise_service in a while/try/catch loop:

import time
starttime = time.time()
while True:
    try:
        advertise_service(...)
        break
    except:
        time.sleep(1)
    if (time.time() > (starttime+30)):
        sys.exit(1)

this way you keep trying at one second intervals until it succeeds or 30 seconds has passed, if it fails after 30 seconds the script would exit. this way everything needed to give your script a chance to work is in the script itself rather than some of it being in your rc.local file.

0

Answers and comments suggest to use an init.d script to start your script. I don't know what operating system you are using but since Raspbian Jessie systemd replaces old style SysV init process and only emulate that for compatibility reasons. Using a systemd unit is quite simple to start your script after bluetooth.target. Create a new unit with:

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

In the editor insert these statements, save it and quit the editor:

[Unit]
Description=running PyPipe script
Requires=bluetooth.target
After=bluetooth.target

[Service]
User=pi     # or must it run as root? Then omit this line
ExecStart=/home/pi/PyPipe.py   # or where your program is

[Install]
WantedBy=multi-user.target

Enable the new service:

rpi ~$ sudo systemctl enable PyPipe.service

reboot.

Check with:

rpi ~$ systemctl status PyPipe.service
rpi ~$ systemctl cat PyPipe.service

Edit again with:

rpi ~$ sudo systemctl --full edit PyPipe.service

I don't know if it runs on the first attempt. There may be some edge conditions I don't know, something like user rights, environment etc. It is no problem to configure these dependencies. The problem is to find them ;-) Give me a comment under this answer if it doesn't run at first go.

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.