0

I'm trying to learn how to safely and reliably start and stop the pigipod DEOMON process from within a python script.

If pigpiod happens to be running already, then this script is always successful. It stops pigpiod and then starts it again.

But if pigpiod is NOT running when I run this, then MOST of the time it fails, and the standard message block that starts with "Can't connect to pigpio at localhost(8888)" appears when I try to instantiate pi = pigoio.pi()

This happens even though os.system('sudo pigpiod') returns 0, there are no exceptions, and a .sleep(1) was executed "just to make sure".

  • The FIRST time I run it after boot, it is always successful.
  • if pigpiod was already running, then it is always successful.
  • If I run a few seconds after a failure, it seems to always fail again.
  • It seems if I wait a LONG TIME after a failure, like several minutes, then run it again, it is more likely to be successful.

Question: What could cause os.system('sudo pigpiod') to fail to start pigpiod successfully some of the time, but still always return 0 and throw no exceptions?

edit: RPi 3, Python 2.7, Raspian 8.0 jessie

Failure looks like this:

START: trying os.system('sudo pigpiod')
    and the returned status is:  0
    sleeping for 1 second...
    pigpiod started successfully...
    ...because  status is Falsy
    ...and so I conclude that all is well.
START: I'm DONE
BOX: making a pi
MAKE_A_PI: I am going to try to instantiate a pi
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Can't connect to pigpio at localhost(8888)

Did you start the pigpio daemon? E.g. sudo pigpiod

Did you specify the correct Pi host/port in the environment
variables PIGPIO_ADDR/PIGPIO_PORT?
E.g. export PIGPIO_ADDR=soft, export PIGPIO_PORT=8888

Did you specify the correct Pi host/port in the
pigpio.pi() function? E.g. pigpio.pi('soft', 8888)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
MAKE_A_PI: I'm DONE
satus of pi.connected:  False
BOX: setting a GPIO pin to True:

Traceback (most recent call last):
  File "/home/pi/PiProblemo/PiProblem.py", line 25, in <module>
    BOX.pi.write(GPIO, 1)
  File "/usr/lib/python2.7/dist-packages/pigpio.py", line 1376, in write
    return _u2i(_pigpio_command(self.sl, _PI_CMD_WRITE, gpio, level))
  File "/usr/lib/python2.7/dist-packages/pigpio.py", line 977, in _pigpio_command
    sl.s.send(struct.pack('IIII', cmd, p1, p2, 0))
AttributeError: 'NoneType' object has no attribute 'send'

My main script:

#!/usr/bin/env python

if __name__ == "__main__":

    import time, pigpio
    from PiBox import PiBox

    # Instantiate the Box:
    BOX = PiBox.Box('my new Box')
    print "BOX instantiated with name: ", BOX.name

    print "BOX: starting pigpiod"
    BOX.start_pigpiod()

    print "BOX: making a pi"
    BOX.make_a_pi()

    print "satus of pi.connected: ", BOX.pi.connected

    GPIO = 27

    print "BOX: setting a GPIO pin to True:"
    BOX.pi.write(GPIO, 1)
    print "BOX: reading it gives: ", BOX.pi.read(GPIO)

    print "BOX: setting a GPIO pin to False:"
    BOX.pi.write(GPIO, 0)
    print "BOX: reading it back gives: ", BOX.pi.read(GPIO)

My PiBox module, I've left the verbose print statements in to help explain what I believe each step is doing. It's certainly safe to ignore or delete them:

class Box(object):

    def __init__(self, name):
        self.name = name

    def start_pigpiod(self):
        import os, time

        print "START: going to call STOP first."
        self.stop_pigpiod()
        print "START: STOP has been called ."

        print "START: try to START again."
        try:
            print "START: trying os.system('sudo pigpiod')"
            status = os.system('sudo pigpiod')
            print "    and the returned status is: ", status
            print "    sleeping for 1 second..."
            time.sleep(1)
            if not status:
                print "    pigpiod started successfully..."
                print "    ...because  status is Falsy"
                print "    ...and so I conclude that all is well."
            else:
                print "    pigpiod did not start successfully..."
                print "    ...because status is Truthy"
                print "    ...and so I conclude that there's been a problem"
        except Exception, e:
            print "START: There's been an exception"
            print "    and it is: ", str(e)
        print "START: I'm DONE"

    def stop_pigpiod(self):
        import os, time
        print "STOP: try to STOP."
        try:
            print "STOP: trying os.system('sudo killall pigpiod')"
            status = os.system('sudo killall pigpiod')  # stop it in case it's running
            print "    and the returned status is: ", status
            print "    sleeping for 1 second..."
            time.sleep(1)
            if not status:
                print "    pigpiod stopped successfully..."
                print "    ...because  status is Falsy"
                print "    ...and so I conclude that all is well."
            else:
                print "    pigpiod not stopped (probably wasn't started!)..."
                print "    ...because not status is Truthy"
                print "    ...but I still think that all is well."
        except:
            print "  OH NO! there was some exception while stopping pigpiod!"
        print "I AM STOP, and I'm DONE!"

    def make_a_pi(self):
        import time, pigpio
        print "MAKE_A_PI: I am going to try to instantiate a pi"
        try:
            self.pi = pigpio.pi()  # local GPIO only
            print "    I'm going to sleep for 1 sec..."
            time.sleep(1)
        except Exception, e:
            print "MAKE_A_PI: There's been an exception..."
            print "    message is: ", str(e)
        print "MAKE_A_PI: I'm DONE"
3
  • Another, slightly related question about trying to check on processes from within a Python script: Recommended way for a python script to check NTP update status, and initiate an update if necessary?
    – uhoh
    Commented Mar 14, 2018 at 7:52
  • 1
    Why not start the daemon at boot by sudo systemctl enable pigpiod?
    – Dribbler
    Commented Sep 15, 2018 at 12:21
  • @Dribbler I've posted an updated answer and accepted to make it easier to find. The idea was that just by running the script everything would be taken care of, so that users would not have to keep track of too many things nor remember what to type.
    – uhoh
    Commented Sep 15, 2018 at 13:49

2 Answers 2

0

This is a partial answer; I am going to try to understand further why this is so. If someone is able to explain further that would be wonderful.

The behavior described by the OP (in this case, me) is:

This happens even though os.system('sudo pigpiod') returns 0, there are no exceptions, and a .sleep(1) was executed "just to make sure".

  • The FIRST time I run it after boot, it is always successful.
  • if pigpiod was already running, then it is always successful.
  • If I run a few seconds after a failure, it seems to always fail again.
  • It seems if I wait a LONG TIME after a failure, like several minutes, then run it again, it is more likely to be successful.

It turns out that this sluggishness in the pigpiod DAEMON's status is real. It's not a problem in the script.

I saw this by accident while trying to stop and then restart pigpio while debugging a DHT22 script.

Here's some text from the Pi's terminal. After the killall, pigpiod can not be started between 21:25:07 and 21:25:54.

The message:

"bind to port 8888 failed (Address already in use) Can't initialise pigpio library"

appears when trying to start it, but

"no process found" 

appears when trying to kill it.

So for almost a minute, the DAEMON is a zombie (so to speak).

This means that the idea of quickly turning it off and then on again is a bad one. Instead, if the OP (me) really wants to do this with Python, the script has to honor this transient zombie status and not just start and stop it willy-nilly.

pi@raspberrypi:~ $ pidof pigpiod
2498
pi@raspberrypi:~ $ sudo killall pigpiod
pi@raspberrypi:~ $ pidof pigpiod
pi@raspberrypi:~ $ sudo pigpiod
pi@raspberrypi:~ $ sudo killall pigpiod
pi@raspberrypi:~ $ sudo pigpiod
pi@raspberrypi:~ $ 2018-03-12 21:25:07 initInitialise: bind to port 8888 failed (Address already in use)
Can't initialise pigpio library
pidof pigpiod
pi@raspberrypi:~ $ pidof pigpiod
pi@raspberrypi:~ $ sudo pigpiod
pi@raspberrypi:~ $ 2018-03-12 21:25:24 initInitialise: bind to port 8888 failed (Address already in use)
Can't initialise pigpio library
sudo pigpiod
pi@raspberrypi:~ $ 2018-03-12 21:25:37 initInitialise: bind to port 8888 failed (Address already in use)
Can't initialise pigpio library
sudo killall pigpiod
pigpiod: no process found
pi@raspberrypi:~ $ sudo killall pigpiod
pigpiod: no process found
pi@raspberrypi:~ $ sudo pigpiod
pi@raspberrypi:~ $ 2018-03-12 21:25:54 initInitialise: bind to port 8888 failed (Address already in use)
Can't initialise pigpio library
sudo killall pigpiod
pigpiod: no process found
pi@raspberrypi:~ $ pidof pigpiod
pi@raspberrypi:~ $ sudo pigpiod
pi@raspberrypi:~ $ pidof pigpiod
3030
pi@raspberrypi:~ $ ^C
pi@raspberrypi:~ $ 
0

Here is a short version of what I'd implemented a few months ago. I believe the problem was not as bad as I was seeing, there may have been a delay in reporting.

When I switch to using the commands module in Python e.g.

commands.getstatusoutput('sudo pigpiod')

then everything worked quite nicely.

Here's a simplified bit of script from the final program:

import commands, pigpio, time

# see if it is running already
status, process = commands.getstatusoutput('sudo pidof pigpiod')

if status:  #  it wasn't running, so start it
    print "pigpiod was not running"
    commands.getstatusoutput('sudo pigpiod')  # try to  start it
    time.sleep(0.5)
    # check it again        
    status, process = commands.getstatusoutput('sudo pidof pigpiod')

if not status:  # if it was started successfully (or was already running)...
    pigpiod_process = process
    print "pigpiod is running, process ID is {} ".format(pigpiod_process)

    try:
        self.pi = pigpio.pi()  # local GPIO only
        self.logger.info("pigpio's pi instantiated")
    except Exception, e:
        start_pigpiod_exception = str(e)
        print "problem instantiating pi: {}".format(start_pigpiod_exception))
else:
    print "start pigpiod was unsuccessful."

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.