I've spent the last 2 days all over forums trying to find the right answer to this question and I'm just having no luck with my script! Basically, I'm building a deployable scale for bats - the bats have been PIT tagged. The idea is that they will be scanned and then weighed while several photos are taken. The base of this script works if I set it to run through a few loops of waiting for a scan, then weighing and taking photos. However, I'd like this to run indefinitely until a power button is clicked which will safely close down the script and save the data before powering down the Pi. For the life of me, I cannot figure out how to program an external button to interrupt the while loop. I suspect part of the problem is that the scanner is constantly 'open' unless a bat is actively being weighed and photographed. If you can give me any help, I'd really appreciate it!!

from gpiozero import  LED
import RPi.GPIO as GPIO

import time
from datetime import datetime
from multiprocessing import Process

from hx711py.hx711 import HX711
import serial
from picamera2 import Picamera2

import csv

#Setup GPIO

#Setup load cell:
hx = HX711(5, 6)
referenceUnit = -1021

#Configure camera
picam = Picamera2()

#Setup button and led
button = 23
GPIO.setup(button, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
led = LED(4)

print('Everything has configured')

#Create weighing and scanning function:
def scanningbats():
    start = datetime.today()
    with open('/home/weighingbox/batweights_' + start.strftime("%d%m%Y") + '_' + start.strftime("%H%M%S") + '.csv', 'w', newline = '') as datalogger: 
        datawriter = csv.writer(datalogger)
        datawriter.writerow(['Date', 'Time', 'ID', 'Average Weight(g)'])

    while True:
        #Create temporary weight list
        tw = []
        #Specify and open serial port (stays open until
        print('Serial Port is Ready')
        ser = serial.Serial('/dev/serial0', baudrate = 9600)
        #Read tag:
        tagreading = ser.read(17)
        tag = tagreading.decode()
        tag = tag.strip()
        tagshort = tag[-4:]
        print('Current bat: ', tagshort)
        bat = 1 #where 1 means the bat is in the box
        #When tag is read...
        if len(tag) > 0:
        #Take date and time stamp
            now = datetime.today()
            d = now.strftime("%d%m%Y")
            t = now.strftime("%H%M%S")
            filename = d + "_" + t + "_" + tagshort
            for i in range(3):
                for i in range (5):
                    val = hx.get_weight(5)
                pic = picam.capture_request()
                pic.save('main', f'{filename}.jpg')
            av = round(sum(tw) / len(tw), 2)
            print('Average weight is: ', av)
                    #Add data to weight list
            datawriter.writerow([d, t, tag, av])

#Create exit button
def onbuttonpress(channel):

print('All new functions defined')


if __name__ == '__main__':
    process = Process(target = scanningbats)
    while process.is_alive:
        GPIO.add_event_detect(23, GPIO.RISING, callback = onbuttonpress, bouncetime = 500)

#except GPIO.add_event_detect(23, GPIO.RISING, callback = onbuttonpress, bouncetime = 500)
  • 1
    while keepLooping == True:
    – jsotola
    Commented Jul 9 at 17:19
  • 2
    This is a general programming question. The Pi is irrelevant.
    – joan
    Commented Jul 9 at 21:04
  • 2
    This question is off topic BUT WHY are you using multiprocessing? Mixing incompatible GPIO libraries is a recipe for disaster.
    – Milliways
    Commented Jul 10 at 0:42

1 Answer 1


As Joan said it's more of a Python or general programming problem. However it deserves an answer anyway.

So the general idea is that you will have a global variable, run for instance, that you will declare global and then set to True:

global run run = True

Then you will in your main while loop, loop while run is True:

while run:

In a periodic job (or in a thread and within a while) you will then check whether the button is pressed (I'll let you handle that) and switch run accordingly:

def button_routine():
  global run
  if button_is_trigged():
    run = False

Or you can do a little better with an interruption (you need to set the interruption so that it fires on_button_interruption()):

def on_button_interruption():
  global run
  run = False

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.