Daveolw1
Posts: 77
Joined: Thu May 16, 2019 10:24 am

Function going through twice

Fri Jun 14, 2019 6:36 pm

Why does it go through this function twice, I thought it was button bounce but increased the value to 1000 but it still happened. I then added the sleep 50 at the end and it waits there and then goes through again. There is nothing in the function that refers to any other part of the programme it is just taking values from lists and saving them to files. Going through a second time it is adding more items to the list and then saving it to file.

Code: Select all

def my_callbackp18(channel):
    global all_play_list
    global playlist_tmp
    global playlist_files
    total_playlist = len(playlist_files)
    digit8_value = total_playlist
    dig6 = str(digit6_value)
    dig7 = str(digit7_value)
    dig8 = str(digit8_value)
    play_list_file_string = dig6 + dig7 + dig8 + '.txt'
    play_list_file = play_list_file_string
    list_num = total_playlist + 1
    playlist_files.insert(list_num, play_list_file)
    f = open("/media/pi/PI_STORAGE/play_list/all_play_list.txt", 'w')
    for item in playlist_files:
        print('item = ', item)
        f.write(item + ',')
       
    f.close()
    
    f = open("/media/pi/PI_STORAGE/play_list/" + play_list_file, 'w')
    for item in playlist_tmp:
        f.write(item + ',')
       
    f.close()
    
    time.sleep(50)

Code: Select all

GPIO.add_event_detect(18, GPIO.FALLING, callback=my_callbackp18, bouncetime=1000)
Last edited by Daveolw1 on Sat Jun 15, 2019 6:20 am, edited 1 time in total.

pcmanbob
Posts: 13753
Joined: Fri May 31, 2013 9:28 pm
Location: Mansfield UK

Re: Funtion going through twice

Fri Jun 14, 2019 10:35 pm

I can't see anything that would make the function run twice, so may be its some thing in the rest of your code , but as you have not posted that we can't say what it might be.
We want information… information… information........................no information no help
The use of crystal balls & mind reading are not supported

ghp
Posts: 3756
Joined: Wed Jun 12, 2013 12:41 pm
Location: Stuttgart Germany

Re: Funtion going through twice

Sat Jun 15, 2019 6:44 am

For checking the behavior, you could add a print-statement just at the beginning of my_callbackp18.
Your full code could possibly help to help.
Most possibly you checked the connection to your button (?) many times. Is it the only code running on this pi ?

User avatar
B.Goode
Posts: 16322
Joined: Mon Sep 01, 2014 4:03 pm
Location: UK

Re: Funtion going through twice

Sat Jun 15, 2019 9:17 am

It doesn't directly help, but there are reports of this behaviour in this forum dating back to 2012.

My suggestion would be to try reimplementing your code with a different gpio library, perhaps gpiozero. Although gpiozero can use RPi.GPIO as its 'backend', there are alternatives you can specify instead.

https://gpiozero.readthedocs.io/en/stab ... igpio.html
Beware of the Leopard

Daveolw1
Posts: 77
Joined: Thu May 16, 2019 10:24 am

Re: Funtion going through twice

Sat Jun 15, 2019 3:30 pm

Thanks for the replies.
I have worked out it is the "open file/For" section of code that is causing it, if I remove this part of code it only goes through the once.

Code: Select all

 f = open("/media/pi/PI_STORAGE/play_list/all_play_list.txt", 'w')
    for item in playlist_files:
        print('item = ', item)
        f.write(item + ',')
       
 f.close()

Code: Select all

 
 f = open("/media/pi/PI_STORAGE/play_list/" + play_list_file, 'w')
    for item in playlist_tmp:
        f.write(item + ',')
       
 f.close()
This code is taking List data and saving to a file and at the start of the programme it reads these files back into list. There is something strange with the way it presents these because it keeps adding them like ['002.txt'] and when I try to access List[0] I get [ instead of 0 as expected. I search to try and find an example of writing a list to file and reading back into a list.

Thanks David

pcmanbob
Posts: 13753
Joined: Fri May 31, 2013 9:28 pm
Location: Mansfield UK

Re: Funtion going through twice

Sat Jun 15, 2019 3:48 pm

I don't see how the file write is causing the function to run twice.

the first file write.

Code: Select all

 f = open("/media/pi/PI_STORAGE/play_list/all_play_list.txt", 'w')
    for item in playlist_files:
        print('item = ', item)
        f.write(item + ',')
       
 f.close()
will simply open a file called "all_play_list.txt" and over write what ever is in it with the new data as specified in the for loop before closing the file.

the second file write

Code: Select all

 
 f = open("/media/pi/PI_STORAGE/play_list/" + play_list_file, 'w')
    for item in playlist_tmp:
        f.write(item + ',')
       
 f.close()
is slightly different because you have a variable as the file name " play_list_file " which is set by these lines in your code

Code: Select all

    play_list_file_string = dig6 + dig7 + dig8 + '.txt'
    play_list_file = play_list_file_string
    
so what ever " dig6 + dig7 + dig8 " equals is what your file name will be.

so for example if dig6= 3, dig7= 5, dig8= 9, your file would be called 379.txt

again the file is opened for writing so all data will be over written as specified in the for loop before closing the file.

again nothing there to make your function run twice.
We want information… information… information........................no information no help
The use of crystal balls & mind reading are not supported

Daveolw1
Posts: 77
Joined: Thu May 16, 2019 10:24 am

Re: Funtion going through twice

Sat Jun 15, 2019 4:01 pm

So when I remove those two sections of code, does it only go through once, with either of them in it goes through twice?

pcmanbob
Posts: 13753
Joined: Fri May 31, 2013 9:28 pm
Location: Mansfield UK

Re: Funtion going through twice

Sat Jun 15, 2019 4:16 pm

To make the function run twice you would need to have it called again , if one of your file writes was doing this then it would never exit because on each call it would call the function again and so enter an endless loop.

like this

function called by gpio.
function runs and calls it self again
function runs and calls it self again
function runs and calls it self again
and so on.

have you tried adding some print statements to your function so you can watch it being executed , if you run your program from the command line.

Code: Select all

def my_callbackp18(channel):
    print ("function run")
    global all_play_list
    global playlist_tmp
    global playlist_files
    total_playlist = len(playlist_files)
    digit8_value = total_playlist
    dig6 = str(digit6_value)
    dig7 = str(digit7_value)
    dig8 = str(digit8_value)
    play_list_file_string = dig6 + dig7 + dig8 + '.txt'
    play_list_file = play_list_file_string
    list_num = total_playlist + 1
    playlist_files.insert(list_num, play_list_file)
    print ("write date to all_play_list.txt")
    f = open("/media/pi/PI_STORAGE/play_list/all_play_list.txt", 'w')
    for item in playlist_files:
        print('item = ', item)
        f.write(item + ',')
       
    f.close()
    print ("write date to ",play_list_file)
    f = open("/media/pi/PI_STORAGE/play_list/" + play_list_file, 'w')
    for item in playlist_tmp:
        f.write(item + ',')
       
    f.close()
    print (" file writes completed")
    time.sleep(50)
We want information… information… information........................no information no help
The use of crystal balls & mind reading are not supported

Daveolw1
Posts: 77
Joined: Thu May 16, 2019 10:24 am

Re: Funtion going through twice

Sat Jun 15, 2019 5:43 pm

Yes, I have already got a lot of print statements in it but I removed them before posting so the code could be read easier.
Below code and output, I have a workaround at the moment with the If statement " if not digit5_value == 0:" but have commented out the line at the bottom " #digit5_value = 0" to show the function goes through twice.

Code: Select all

def my_callbackp18(channel):
    print('write file callback18')
    global digit5_value
    global all_play_list
    global playlist_tmp
    global playlist_files
    global play_list_file
    if not digit5_value == 0:
        total_playlist = len(playlist_files)
        digit8_value = total_playlist
        dig6 = str(digit6_value)
        dig7 = str(digit7_value)
        dig8 = str(digit8_value)
        play_list_file_string = dig6 + dig7 + dig8 + '.txt'
        print(play_list_file_string)
        play_list_file = play_list_file_string
        print("TPlen = ", total_playlist)
        list_num = total_playlist + 1
        print(list_num)
        playlist_files.insert(list_num, play_list_file)
        print('PLF = ', playlist_files)
        f = open("/media/pi/PI_STORAGE/play_list/all_play_list.txt", 'w')
        for item in playlist_files:
            print('item = ', item)
            f.write(str(item) + ',')
        f.close()
        print('all play list file saved')
        f = open("/media/pi/PI_STORAGE/play_list/" + play_list_file, 'w')
        for item in playlist_tmp:
            print('item = ', item)
            f.write(str(item) + ',')
        f.close()
        del playlist_tmp[:]
        print('play list file saved')
        seg.text[4:5] = '0'
        #digit5_value = 0
      
OUTPUT:-

[["['000.txt']"], ["['001.txt']"], ["['002.txt']"], ["['003.txt']"], ['004.txt']]
['0519.txt']
['0519.txt', '1213.txt']

write file callback18 "first time through adds item ['005.txt'] "
005.txt
TPlen = 5
6
PLF = [["['000.txt']"], ["['001.txt']"], ["['002.txt']"], ["['003.txt']"], ['004.txt'], '005.txt']
item = ["['000.txt']"]
item = ["['001.txt']"]
item = ["['002.txt']"]
item = ["['003.txt']"]
item = ['004.txt']
item = 005.txt
all play list file saved
item = 0519.txt
item = 1213.txt
play list file saved

write file callback18 "second time through adds item ['006.txt'] but file is empty because songs were selected "
006.txt
TPlen = 6
7
PLF = [["['000.txt']"], ["['001.txt']"], ["['002.txt']"], ["['003.txt']"], ['004.txt'], '005.txt', '006.txt']
item = ["['000.txt']"]
item = ["['001.txt']"]
item = ["['002.txt']"]
item = ["['003.txt']"]
item = ['004.txt']
item = 005.txt
item = 006.txt
all play list file saved
play list file saved

ghp
Posts: 3756
Joined: Wed Jun 12, 2013 12:41 pm
Location: Stuttgart Germany

Re: Funtion going through twice

Sun Jun 16, 2019 7:31 am

I was curious to see how these callback work. Especially in case the runtime in the callback is longer than the event input.
The setup is: use a microcontroller (arduino zero) and produce a square wave with 3 sec low and 3 sec high. At each edge, I added some jitter (50 times, 2 ms period).

Code in RPi:

Code: Select all

import  RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM)
GPIO.setup(21, GPIO.IN)

def f(channel):
    print("f start", time.time() )
    time.sleep(0)
    print("f end  ", time.time() )

GPIO.add_event_detect(21, GPIO.RISING, callback=f, bouncetime=50)

time.sleep(60) # just to leave code running some time
When code is having time.sleep(0), then result is

Code: Select all

f start 1560668382.7183247
f end   1560668382.7185113

f start 1560668388.7176194
f end   1560668388.7178047

f start 1560668394.716907
f end   1560668394.7170556

f start 1560668400.7163208
f end   1560668400.7165692
The printout shows that each 6 sec the "f start" is printed. This is as expected.

When a delay of 8 sec is added inside the f-function, things change and look like 'function called twice'

Code: Select all

f start 1560668232.7351942
f end   1560668240.743672

f start 1560668240.7438862
f end   1560668248.751989

f start 1560668248.7522573
f end   1560668256.7589428

f start 1560668256.7592444
f end   1560668264.7669976

f start 1560668264.7672117
f end   1560668272.7753232
It is clearly visible that the next start after the processing ends is immediate after the function stops. Keep in mind that my controller places a signal still each 6 sec. So the intermediate pulse is 'queued' and processed immediately when the callback is terminated.

As a rule of thumb, keep the runtime inside the callback as short as possible.

If changing the code a bit, and using wait_for_edge in a loop, the result are different. Assuming the time needed in the function is 8 sec, trigger is still each 6 sec.

Code: Select all

f start 1560669912.5439527   
f end   1560669920.5523303 # trigger at 18 is skipped

f start 1560669924.5425208 
f end   1560669932.5507638 # trigger at 30 is skipped

f start 1560669936.541285
f end   1560669944.5497527

f start 1560669948.5398061
f end   1560669956.5480206
The code is

Code: Select all

import  RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM)
GPIO.setup(21, GPIO.IN)

def f(channel):
    print("f start", time.time() )
    time.sleep(8)
    print("f end  ", time.time() )

while True:
    GPIO.wait_for_edge(21, GPIO.RISING)
    f(21)
It is easy to have a thread in python which runs th eloop independent from other tasks.

Daveolw1
Posts: 77
Joined: Thu May 16, 2019 10:24 am

Re: Funtion going through twice

Sun Jun 16, 2019 12:37 pm

I gave my function a different name and just called that from the callback function but the result was the same it went through twice.

pcmanbob
Posts: 13753
Joined: Fri May 31, 2013 9:28 pm
Location: Mansfield UK

Re: Funtion going through twice

Sun Jun 16, 2019 2:34 pm

one other thing you could try is to remove the event detect as soon as your function is caled then once the function is completed you can add it back in.

like this

Code: Select all

def my_callbackp18(channel):
    GPIO.remove_event_detect(18)
    global all_play_list
    global playlist_tmp
    global playlist_files
    total_playlist = len(playlist_files)
    digit8_value = total_playlist
    dig6 = str(digit6_value)
    dig7 = str(digit7_value)
    dig8 = str(digit8_value)
    play_list_file_string = dig6 + dig7 + dig8 + '.txt'
    play_list_file = play_list_file_string
    list_num = total_playlist + 1
    playlist_files.insert(list_num, play_list_file)
    f = open("/media/pi/PI_STORAGE/play_list/all_play_list.txt", 'w')
    for item in playlist_files:
        print('item = ', item)
        f.write(item + ',')
       
    f.close()
    
    f = open("/media/pi/PI_STORAGE/play_list/" + play_list_file, 'w')
    for item in playlist_tmp:
        f.write(item + ',')
       
    f.close()
    
    time.sleep(2)
    GPIO.add_event_detect(18, GPIO.FALLING, callback=my_callbackp18, bouncetime=1000)
that way no other events can be called while the function is running, it should prove if its a true event ( ie gpio input ) that's calling the function a second time or some thing in your function that making it run twice.
We want information… information… information........................no information no help
The use of crystal balls & mind reading are not supported

Daveolw1
Posts: 77
Joined: Thu May 16, 2019 10:24 am

Re: Funtion going through twice

Sun Jun 16, 2019 6:06 pm

Thanks for the information, I tried as you suggested and it only goes through once so this prove it is a true GPIO input.

Thanks David

pcmanbob
Posts: 13753
Joined: Fri May 31, 2013 9:28 pm
Location: Mansfield UK

Re: Funtion going through twice

Sun Jun 16, 2019 7:49 pm

So we have finally proved it's an actual second input on the gpio causing the function to run twice.

So your a step closer to solving the problem or you could just leave the function as it is so it stops the calling of the function while it's running.

I would guess it's switch bounce causing the second input.
We want information… information… information........................no information no help
The use of crystal balls & mind reading are not supported

Daveolw1
Posts: 77
Joined: Thu May 16, 2019 10:24 am

Re: Funtion going through twice

Sun Jun 16, 2019 8:11 pm

Can not see it is switch bounce, as stated in my first post I suspected that and increased it to 1000.

pcmanbob
Posts: 13753
Joined: Fri May 31, 2013 9:28 pm
Location: Mansfield UK

Re: Function going through twice

Mon Jun 17, 2019 9:33 am

If its not switch bounce , have you check your wiring for a bad connection ?

I cant see it being interference or induced voltages at your function would be running randomly, could it be your power supply being loaded and dropping its voltage ?
We want information… information… information........................no information no help
The use of crystal balls & mind reading are not supported

Daveolw1
Posts: 77
Joined: Thu May 16, 2019 10:24 am

Re: Function going through twice

Mon Jun 17, 2019 9:42 am

Have checked wiring, originally I used internal pull ups but got spurious events so disabled them and have 10k connected to the 3.3 volts.
I used a different button which was working ok with other code and the same happened, it went through twice, I still think it is something to do with the open file/for section of code because removing that it does not happen.

pcmanbob
Posts: 13753
Joined: Fri May 31, 2013 9:28 pm
Location: Mansfield UK

Re: Function going through twice

Mon Jun 17, 2019 10:14 am

Well if you disabled the event and still had the file writes in place and then re enabled the event after the file writes , it has to ether be a button press or something causing your pi to think there has been a button press , as you still have not posted your complete program or a digram of how you have the switch/s connected we are working with limited information.
We want information… information… information........................no information no help
The use of crystal balls & mind reading are not supported

ghp
Posts: 3756
Joined: Wed Jun 12, 2013 12:41 pm
Location: Stuttgart Germany

Re: Function going through twice

Fri Jun 21, 2019 8:45 am

Think the callback method is not always working as expected. In case multiple callbacks are attached to one pin, the code is not working as expected.

What I did: connected an GPIO output(BCM 21) to another input(BCM 20) by using a wire. The code toggled the output in a slow rate in a thread.
Followed https://sourceforge.net/p/raspberry-gpi ... ki/Inputs/, "If you wanted more than one callback function" to setup the callbacks.
Added a small bouncetime to the event detect
GPIO.add_event_detect(20, GPIO.RISING, bouncetime=100 )
Result is same when bouncetime is not used. The GPIO output does not bounce.

TEST_0: Attached a single callback to the pin 20 "callback_with_file".

Code: Select all

0.6.5
TEST_0

toggle HIGH 1561105416.9977474
callback_with_file START 1561105416.9987712
callback_with_file END 1561105417.0036728

toggle HIGH 1561105421.0058208
callback_with_file START 1561105421.0060265
callback_with_file END 1561105421.0103037
Works as expected. The callback is called once on each low-high-edge, the callback is writing files.

TEST_1: Attached single different callback to pin20, no files written "callback".

Code: Select all

0.6.5
TEST_1

toggle HIGH 1561105550.2217839
callback START 1561105550.2221496
callback END 1561105550.2276273

toggle HIGH 1561105554.2293239
callback START 1561105554.2294986
callback END 1561105554.2343802
Same result as TEST_0. Obviously writing files in a callback does not add strange behavior.

TEST_2: Add two callback to one pin:

Code: Select all

if test == "TEST_2":
    GPIO.add_event_callback(20, callback  )
    GPIO.add_event_callback(20, callback2  )
Result:

Code: Select all

0.6.5
TEST_2

toggle HIGH 1561105664.1932065
callback START 1561105664.1945903
callback END 1561105664.199675
callback2 START 1561105664.199804
callback START 1561105664.1998546
callback END 1561105664.2134457
callback2 START 1561105664.2137964

toggle HIGH 1561105668.2016718
callback START 1561105668.202027
callback END 1561105668.2132208
callback2 START 1561105668.213486
callback START 1561105668.2136009
callback END 1561105668.2247682
callback2 START 1561105668.2250352
Both "callback" and "callback2" are called twice on each positive edge.

This result is strange.

Here the source of the test case. The different tests are selected by a variable. So the process was restarted each time.

Code: Select all

import RPi.GPIO as GPIO
import time
import threading

test = "TEST_0"
# test = "TEST_1"
# test = "TEST_2"

GPIO.setmode(GPIO.BCM)

GPIO.setup(20, GPIO.IN)
GPIO.setup(21, GPIO.OUT)
GPIO.output(21, GPIO.LOW)

print( GPIO.VERSION)
print(test)

run = True

def sleep(delay):
    """ delay function which can be stopped in small time interval"""
    
    tx = time.time() + delay
    
    while run:
        time.sleep(0.1)
        if tx < time.time():
            break
        
def toggle():
    """toggle output pin. Interval is 2 sec low, 2 sec high"""
    while run:
        GPIO.output(21, GPIO.LOW)
        sleep(2)

        if not run:
            break        
        print()
        print("toggle", "HIGH", time.time())
        GPIO.output(21, GPIO.HIGH)
        sleep(2)

tt = threading.Thread(target=toggle)
tt.start()

def callback2(channel):
    print("callback2", "START", time.time())
    
def callback_with_file(channel):
    print("callback_with_file", "START", time.time())
    
    with open("x.dat", "wt") as f:
        for _ in range(1000):
            f.write("hallo")
            
    with open("y.dat", "wt") as f:
        for _ in range(1000):
            f.write("hallo")
            
    print("callback_with_file", "END", time.time())
    
def callback(channel):
    print("callback", "START", time.time())
    
    with open("x.dat", "wt") as f:
        for _ in range(1000):
            f.write("hallo")
            
    with open("y.dat", "wt") as f:
        for _ in range(1000):
            f.write("hallo")
            
    print("callback", "END", time.time())

GPIO.add_event_detect(20, GPIO.RISING,  bouncetime=100 )

if test == "TEST_0":
    GPIO.add_event_callback(20, callback_with_file  )

if test == "TEST_1":
    GPIO.add_event_callback(20, callback  )
    
if test == "TEST_2":
    GPIO.add_event_callback(20, callback  )
    GPIO.add_event_callback(20, callback2  )

event = threading.Event()
try:
    event.wait()
except KeyboardInterrupt:
    pass
run = False

GPIO.cleanup()
print("finished")

Return to “Python”