RetroRevive
Posts: 10
Joined: Sat Nov 09, 2019 10:40 am

Python script stops after 1 minute after boot

Tue Dec 10, 2019 7:20 pm

Hello.
Long time since doing something in Python and I have an issue.

I have a python script that should imitate a work of an crude jukebox where every GPIO button plays its own mp3 file.
It should run all the time after Raspbian boots.
However, after pushing the button, mp3 file plays for 1 minute and than python script stops working.

Python script:

Code: Select all

#!/usr/bin/env python

import os
import subprocess
import time

import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM)
GPIO.setup(20, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(21, GPIO.IN, pull_up_down=GPIO.PUD_UP)

p = subprocess.Popen(["mpg123", "--remote"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
time.sleep(1.0)

while True:
    
    if(GPIO.input(20) == False):
        
        p.stdin.write(b"STOP")
        p.stdin.flush()
        time.sleep(1.0)
        p.stdin.write(b"LOAD hrvatski_def_lim_mono.mp3\n")
        p.stdin.flush()
        time.sleep(1.0)

    if(GPIO.input(21) == False):
        
        p.stdin.write(b"STOP")
        p.stdin.flush()
        time.sleep(1.0)
        p.stdin.write(b"LOAD eng-def_lim_mono.mp3\n")
        p.stdin.flush()
        time.sleep(1.0)

.sh file that runs via crontab:

Code: Select all

#!/bin/sh
#launcher.sh

cd /
cd home/pi/malik
sudo python malik.py
cd /
crontab:

Code: Select all

@reboot sh /home/pi/malik/launcher.sh >home/pi/logs/cronlog 2>&1
crontab shows nothing

EDIT: just noticed it stops even if I run it in terminal or via Thonny?!

So basically, I need this python script to be running all the time. Please help. :)

User avatar
paddyg
Posts: 2461
Joined: Sat Jan 28, 2012 11:57 am
Location: UK

Re: Python script stops after 1 minute after boot

Tue Dec 10, 2019 10:14 pm

I can't see why it would cause the program to stop but you should have a small sleep in you main while loop. Even time.sleep(0.1) will cut CPU from 100% to 1%. Does the program run indefinitely if you don't press either button to start the audio? Can you switch audio any number of times by pressing the buttons up to the 60s cut-off. Is it exactly 60s?

PS don't even think about getting it to work with crontab or other start at boot methods until you have it working completely reliably from the terminal (not via Thonny)
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d

User avatar
thagrol
Posts: 2108
Joined: Fri Jan 13, 2012 4:41 pm
Location: Darkest Somerset, UK
Contact: Website

Re: Python script stops after 1 minute after boot

Tue Dec 10, 2019 11:04 pm

The first thing to do is to find out what has stopped and why.

The reason you're getting nothing in your cronlog file is that you aren't capturing the output of your script but that of the launcher.

While I wouldn't advise trying to get things running under cron until you've got it working reliably from the shell your launcher script is odd and unnecessary.

It can be replace with the following entry in root's crontab (that's "sudo crontab -e"):

Code: Select all

@reboot cd /home/pi/malik && python malik.py >home/pi/logs/cronlog 2>&1
thoguh I don't know if that will capture stderr from your sub process.

As for your python code, it's difficult to make any suggestion without knowing why it's stopping though I do have a couple of general suggestion:
  • Whay are you importing os? You code doesn't appear to use it.
  • Is there a strong reasopn for using mpg123 in a subprocess? If not there are almost certainly python modules that can play .mp3 files. A web search for "play mp3 from python" or similar may be useful.
  • A polling loop like the one you have probably isn't the way to go. Without a delay build into each pass it'll use all available cpu time. With a delay it's easy to miss button presses though that is somewhat dependent on the duration of the delay.
    Given that RPi.GPIO appears to support interrupts and callbacks (see https://sourceforge.net/p/raspberry-gpi ... ki/Inputs/) I'd switch to that approach.
To get you started with callbacks here's a very rough outline:

Code: Select all

import RPi.GPIO as GPIO
import signal

def my_callback(channel):
    # button pres stuff goes here

# do your setup stuff here

# setup callback
GPIO.add_event_detect(channel, GPIO.FALLING)
GPIO.add_event_callback(channel, my_callback)

# pause main thread
signal.pause()
That's based on the docs. I use gpiozero rather than RPI.GPIO
Attempts to contact me outside of thes forums will be ignored unless signed in triplicate, sent in, sent back, queried, lost, found, subjected to public enquiry, lost again, and finally buried in soft peat for three months and recycled as firelighters

RetroRevive
Posts: 10
Joined: Sat Nov 09, 2019 10:40 am

Re: Python script stops after 1 minute after boot

Wed Dec 11, 2019 5:22 pm

paddyg wrote:
Tue Dec 10, 2019 10:14 pm
I can't see why it would cause the program to stop but you should have a small sleep in you main while loop. Even time.sleep(0.1) will cut CPU from 100% to 1%. Does the program run indefinitely if you don't press either button to start the audio? Can you switch audio any number of times by pressing the buttons up to the 60s cut-off. Is it exactly 60s?

PS don't even think about getting it to work with crontab or other start at boot methods until you have it working completely reliably from the terminal (not via Thonny)
As I have noticed, there are no issues with the script (tried keeping it running 5-10 minutes) while not pushing the buttons.
I can push and play mp3 with button push only inside 60 seconds interval.
After that script hangs, cause i can see mpg123 process in the background.

Actually it's exactly 70 seconds until script hangs.

time.sleep helped with keeping CPU at 1%-2%

User avatar
paddyg
Posts: 2461
Joined: Sat Jan 28, 2012 11:57 am
Location: UK

Re: Python script stops after 1 minute after boot

Wed Dec 11, 2019 6:50 pm

So it's quite an obvious problem - once you know what it is! I just tried your code on my RPi and (after I struggled to get the internal pull-up to work at all, not sure what that's about. More investigation needed) I had exactly your problem. Then when I tried typing the mpg123 etc on the command line I saw that it spewed a vast stream of info. So obviously the stdout.PIPE was getting stuffed. After exactly 70s!

The solution is either to set stdiout=None in Popen() and let the output scroll up your terminal window. Or if you want to catch the info for some reason you can p.stdout.read() it. But you have to do that in a Thread otherwise it will block the execution of your main loop.

Code: Select all

p = subprocess.Popen(["mpg123", "--remote"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)

def read_out():
    while True:
        _junk = p.stdout.read()
t = threading.Thread(target=read_out) #obviously need to have imported threading
t.start()

while True:
    if(GPIO.input(20) == False):
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d

RetroRevive
Posts: 10
Joined: Sat Nov 09, 2019 10:40 am

Re: Python script stops after 1 minute after boot

Wed Dec 11, 2019 7:00 pm

paddyg wrote:
Wed Dec 11, 2019 6:50 pm
So it's quite an obvious problem - once you know what it is! I just tried your code on my RPi and (after I struggled to get the internal pull-up to work at all, not sure what that's about. More investigation needed) I had exactly your problem. Then when I tried typing the mpg123 etc on the command line I saw that it spewed a vast stream of info. So obviously the stdout.PIPE was getting stuffed. After exactly 70s!

The solution is either to set stdiout=None in Popen() and let the output scroll up your terminal window. Or if you want to catch the info for some reason you can p.stdout.read() it. But you have to do that in a Thread otherwise it will block the execution of your main loop.

Code: Select all

p = subprocess.Popen(["mpg123", "--remote"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)

def read_out():
    while True:
        _junk = p.stdout.read()
t = threading.Thread(target=read_out) #obviously need to have imported threading
t.start()

while True:
    if(GPIO.input(20) == False):

Thank you very much!
Saved me for the second time now.

Obviouly I've got quite rusty since I haven't seriously programmed anything for a longer period of time. Especially in Python.

You got me interested again, tnx!

Return to “Python”