1

I have not been able to find a solution to an issue affecting one of my Python programs only when it runs from rc.local.

Update added to the end with additional information.

A brief description of what I am trying to do:

A Raspberry Pi 3, when started, starts a slideshow using feh, and also drives a counter made of 7-segment digits. A small interface panel with some pushbuttons will be provided to adjust the counter. One button is intended to kill the slideshow, then open a PyGame window to adjust the counter, which is right now split to 2 buttons for troubleshooting. Exiting from the PyGame window updates the counter and starts the slideshow back up. /etc/rc.local calls a python program called main.py.

/etc/rc.local (commented lines removed for brevity):

#!/bin/sh -e
#
# rc.local
#
sleep 30
sudo python /home/pi/Scripts/main.py &
exit 0

This program monitors the buttons for the interface.

~/Scripts/main.py:

#!/usr/bin/env python

import RPi.GPIO as GPIO
import time
import os

time.sleep(30)

GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(23, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(24, GPIO.IN, pull_up_down = GPIO.PUD_UP)

def Shutdown(channel):
         os.system("sudo shutdown -h now")

def StopSlideshow(channel):
         os.system("sudo pkill feh")

def StartAdjust(channel):
         os.system('sudo python /home/pi/Scripts/StartAdjust.py &')

os.system("sudo bash /home/pi/Scripts/slideshow.sh &")
os.system("sudo python /home/pi/Scripts/ShiftTest.py &")

GPIO.add_event_detect(18, GPIO.FALLING, callback = Shutdown, bouncetime = 2000)
GPIO.add_event_detect(23, GPIO.FALLING, callback = StopSlideshow, bouncetime = 2000)
GPIO.add_event_detect(24, GPIO.FALLING, callback = StartAdjust, bouncetime = 2000)

while 1:
        time.sleep(1)

The problem I have is that StartAdjust.py does not start on GPIO24. If I change StartAdjust for another simple program, it works fine. Also, if I kill the process main.py started by rc.local, then start it from command line, it works as intended.

~/Scripts/StartAdjust.py:

#!/usr/bin/env python

import pygame
import os
import time
import RPi.GPIO as GPIO
import datetime

up = 25
left = 12
right = 16
down = 26
enter = 13

buttons = {up,left,right,down,enter}

GPIO.setmode(GPIO.BCM)
for x in buttons:
        GPIO.setup(x, GPIO.IN, pull_up_down=GPIO.PUD_UP)
def UpdateDT():
        text_surface = font_big.render('%i'%year, True, BLACK)
        rect = text_surface.get_rect(center=(120,150))
        window.blit(text_surface, rect)
        text_surface = font_big.render('%i'%month, True, BLACK)
        rect = text_surface.get_rect(center=(240,150))
        window.blit(text_surface, rect)
        text_surface = font_big.render('%i'%date, True, BLACK)
        rect = text_surface.get_rect(center=(360,150))
        window.blit(text_surface, rect)
        text_surface = font_big.render('%i'%hour, True, BLACK)
        rect = text_surface.get_rect(center=(480,150))
        window.blit(text_surface, rect)

def UpdateEdit(EditPosition):
        pygame.draw.rect(window, WHITE, PosYear, 2)
        pygame.draw.rect(window, WHITE, PosMonth, 2)
        pygame.draw.rect(window, WHITE, PosDate, 2)
        pygame.draw.rect(window, WHITE, PosHour, 2)
        pygame.draw.rect(window, WHITE, PosExit, 2)
        if EditPosition == 1:
                pygame.draw.rect(window, RED, PosYear, 2)
        if EditPosition == 2:
                pygame.draw.rect(window, RED, PosMonth, 2)
        if EditPosition == 3:
                pygame.draw.rect(window, RED, PosDate, 2)
        if EditPosition == 4:
                pygame.draw.rect(window, RED, PosHour, 2)
        if EditPosition == 5:
                pygame.draw.rect(window, RED, PosExit, 2)

#set tuples for later use
WHITE = (255,255,255)
RED = (255,0,0)
GREEN = (0,255,0)
BLUE = (0,0,255)
BLACK = (0,0,0)
PosYear = (60, 130, 120, 40)
EditYear = (62, 132, 116, 36)
PosMonth = (180, 130, 120, 40)
EditMonth = (182, 132, 116, 36)
PosDate = (300, 130, 120, 40)
EditDate = (302, 132, 116, 36)
PosHour = (420, 130, 120, 40)
EditHour = (422, 132, 116, 36)
PosExit = (540, 130, 120, 40)

#get last reset time from file and set variables
file = open('/home/pi/Scripts/Date.txt', 'r')
ResetTime = int(file.read())
file.close()
year = int(datetime.datetime.fromtimestamp(ResetTime).strftime('%Y'))
month = int(datetime.datetime.fromtimestamp(ResetTime).strftime('%m'))
date = int(datetime.datetime.fromtimestamp(ResetTime).strftime('%d'))
hour = int(datetime.datetime.fromtimestamp(ResetTime).strftime('%H'))

#set up PyGame window
os.putenv('SDL_FBDEV', '/dev/fb1')
os.environ['SDL_VIDEO_WINDOW_POS'] = "100,100"
pygame.init()
pygame.mouse.set_visible(False)
window = pygame.display.set_mode((750,250))
window.fill(WHITE)
font_big = pygame.font.Font(None, 50)
#set up static text
text_surface = font_big.render('Enter start time', True, BLACK)
rect = text_surface.get_rect(center=(300,50))
window.blit(text_surface, rect)
text_surface = font_big.render('Year', True, BLACK)
rect = text_surface.get_rect(center=(120,100))
window.blit(text_surface, rect)
text_surface = font_big.render('Month', True, BLACK)
rect = text_surface.get_rect(center=(240,100))
window.blit(text_surface, rect)
text_surface = font_big.render('Date', True, BLACK)
rect = text_surface.get_rect(center=(360,100))
window.blit(text_surface, rect)
text_surface = font_big.render('Hour', True, BLACK)
rect = text_surface.get_rect(center=(480,100))
window.blit(text_surface, rect)
text_surface = font_big.render('Exit', True, BLACK)
rect = text_surface.get_rect(center=(600,150))
window.blit(text_surface, rect)

#draw editing marker
EditPos = 1
pygame.draw.rect(window, RED, PosYear, 2)
UpdateDT()
pygame.display.update()

#main editing routine

while 1:
        os.system('sudo python /home/pi/Scripts/Dummy.py &')
        if GPIO.input(right) == False:
                if EditPos < 5:
                        EditPos += 1
                        UpdateEdit(EditPos)
                        pygame.display.update()
                time.sleep(0.25)
        if GPIO.input(left) == False:
                if EditPos > 1:
                         EditPos -= 1
                         UpdateEdit(EditPos)
                         pygame.display.update()
                time.sleep(0.25)
        if GPIO.input(up) == False:
                if EditPos == 1:
                        if year < 2037:
                                pygame.draw.rect(window, WHITE, EditYear, 0)
                                year += 1
                                UpdateDT()
                                pygame.display.update()
                elif EditPos == 2:
                        if month < 12:
                                pygame.draw.rect(window, WHITE, EditMonth, 0)
                                month += 1
                                UpdateDT()
                                pygame.display.update()
                 elif EditPos == 3:
                        if date < 31:
                                pygame.draw.rect(window, WHITE, EditDate, 0)
                                date += 1
                                UpdateDT()
                                pygame.display.update()
                elif EditPos == 4:
                        if hour < 23:
                                pygame.draw.rect(window, WHITE, EditHour, 0)
                                hour += 1
                                UpdateDT()
                                pygame.display.update()
                time.sleep(0.25)
        if GPIO.input(down) == False:
                if EditPos == 1:
                        if year > 1970:
                                pygame.draw.rect(window, WHITE, EditYear, 0)
                                year -= 1
                                UpdateDT()
                                pygame.display.update()
                elif EditPos == 2:
                        if month > 1:
                                pygame.draw.rect(window, WHITE, EditMonth, 0)
                                month -= 1
                                UpdateDT()
                                pygame.display.update()
                elif EditPos == 3:
                        if date > 1:
                                pygame.draw.rect(window, WHITE, EditDate, 0)
                                date -= 1
                                UpdateDT()
                                pygame.display.update()
                elif EditPos == 4:
                       if hour > 0:
                                pygame.draw.rect(window, WHITE, EditHour, 0)
                                hour -= 1
                                UpdateDT()
                                pygame.display.update()
                time.sleep(0.25)
        if GPIO.input(enter) == False:
                if EditPos == 5:
                        TimeTuple = datetime.datetime(year, month, date, hour, 0, 0, 0)
                        ResetTime = time.mktime(TimeTuple.timetuple())
                        file = open('/home/pi/Scripts/Date.txt', 'w')
                        file.write(str(int(ResetTime)))
                        file.close()
                        os.system("sudo python /home/pi/Scripts/ShiftTest.py &")
                        os.system("sudo bash /home/pi/Scripts/slideshow.sh &")
                        exit()

A few other notes:

  • Date.txt is a file that holds the Unix time.

  • ShiftTest.py reads Date.txt and compares it to actual time the calculate the number to display (currently minutes difference). It is also run by a cron job to periodically update.

  • slideshow.sh starts the slideshow.

EDIT

The PyGame window does not open. I ran ps -ef and StartAdjust.py does not show to be running. I originally had:

def StopSlideshow(channel):
     os.system("sudo pkill feh")
     os.system('sudo python /home/pi/Scripts/StartAdjust.py &') 

and the first command would run but the second would not.

UPDATE: I had a little time to spend on it today, and checked a few more things:

  • On startup, the process /bin/sh -e /etc/rc.local start is running as root with a TTY of ?
  • When this starts /usr/bin/python /home/pi/Scripts/main.py, it is also running as root with a TTY of ?. This is when I have the noted issue.
  • If I kill the process /usr/bin/python /home/pi/Scripts/main.py, and run /bin/sh/ -e /etc/rc.local start &, the process bash /etc/rc.local runs as pi with a TTY of pts/0.
  • /usr/bin/python /home/pi/Scripts/main.py is then started by rc.local, with a user of pi and a TTY of pts/0, and this works as intended.
  • If I run sudo /bin/sh/ -e /etc/rc.local start &, it runs as root and TTY of pts/0, as does main.py, and the program works as intended.

The only difference I see is TTY, but I do not know yet how to proceed. Is it possibly a combination of the wrong console, and using PyGame? I am pretty new to this in general, and have never had to manipulate consoles, if that is the right term.

Thank you

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.