Updated Answer
I have added some code for the barcode reader. I made it so that the barcode reader takes a variable amount of time, up to 5 seconds to take a reading and the flowmeter takes a constant 0.5 seconds so you can see that different threads are progressing at different rates independently of one another.
#!/usr/bin/env python3
from threading import Lock
import threading
import time
from random import seed
from random import random
# Dummy function to read SPI as I don't have anything attached
def readSPI():
# Take 0.5s to read
time.sleep(0.5)
readSPI.static += 1
return readSPI.static
readSPI.static=0
class FlowMeter(threading.Thread):
def __init__(self):
super(FlowMeter, self).__init__()
# Create a mutex
self.mutex = Lock()
self.currentReading = 0
def run(self):
# Continuously read flowmeter and safely update self.currentReading
while True:
value = readSPI()
self.mutex.acquire()
self.currentReading = value
self.mutex.release()
def read(self):
# Main calls this to get latest reading, we just grab it from internal variable
self.mutex.acquire()
value = self.currentReading
self.mutex.release()
return value
# Dummy function to read Barcode as I don't have anything attached
def readBarcode():
# Take variable time, 0..5 seconds, to read
time.sleep(random()*5)
result = "BC" + str(int(random()*1000))
return result
class BarcodeReader(threading.Thread):
def __init__(self):
super(BarcodeReader, self).__init__()
# Create a mutex
self.mutex = Lock()
self.currentReading = 0
def run(self):
# Continuously read barcode and safely update self.currentReading
while True:
value = readBarcode()
self.mutex.acquire()
self.currentReading = value
self.mutex.release()
def read(self):
# Main calls this to get latest reading, we just grab it from internal variable
self.mutex.acquire()
value = self.currentReading
self.mutex.release()
return value
if __name__ == '__main__':
# Generate repeatable random numbers
seed(42)
# Instantiate and start flow meter manager thread
fmThread = FlowMeter()
fmThread.daemon = True
fmThread.start()
# Instantiate and start barcode reader thread
bcThread = BarcodeReader()
bcThread.daemon = True
bcThread.start()
# Now you can do other things in main, but always get access to latest readings
for i in range(20):
fmReading = fmThread.read()
bcReading = bcThread.read()
print(f"Main: i = {i} FlowMeter reading = {fmReading}, Barcode={bcReading}")
time.sleep(1)
Sample Output
Main: i = 0 FlowMeter reading = 0, Barcode=0
Main: i = 1 FlowMeter reading = 1, Barcode=0
Main: i = 2 FlowMeter reading = 3, Barcode=0
Main: i = 3 FlowMeter reading = 5, Barcode=0
Main: i = 4 FlowMeter reading = 7, Barcode=BC25
Main: i = 5 FlowMeter reading = 9, Barcode=BC223
Main: i = 6 FlowMeter reading = 11, Barcode=BC223
Main: i = 7 FlowMeter reading = 13, Barcode=BC223
Main: i = 8 FlowMeter reading = 15, Barcode=BC223
Main: i = 9 FlowMeter reading = 17, Barcode=BC676
Main: i = 10 FlowMeter reading = 19, Barcode=BC676
Main: i = 11 FlowMeter reading = 21, Barcode=BC676
Main: i = 12 FlowMeter reading = 23, Barcode=BC676
Main: i = 13 FlowMeter reading = 25, Barcode=BC86
Main: i = 14 FlowMeter reading = 27, Barcode=BC86
Main: i = 15 FlowMeter reading = 29, Barcode=BC29
Main: i = 16 FlowMeter reading = 31, Barcode=BC505
Main: i = 17 FlowMeter reading = 33, Barcode=BC198
Main: i = 18 FlowMeter reading = 35, Barcode=BC198
Main: i = 19 FlowMeter reading = 37, Barcode=BC198
Original Answer
I would suggest you look at systemd
and systemctl
to get your application started at every system startup - example here.
As regards monitoring two things at once, I would suggest you use Python's threading module. Here is a quick example, I create an object subclassed from threading
that manages your flow meter by constantly reading it and holding the current value in a variable that the main program can read at any time. You could start another similar one that manages your bar code reader and run them I parallel. I didn't want to do that and confuse you with double the code.
#!/usr/bin/env python3
from threading import Lock
import threading
import time
# Dummy function to read SPI as I don't have anything attached
def readSPI():
readSPI.static += 1
return readSPI.static
readSPI.static=0
class FlowMeter(threading.Thread):
def __init__(self):
super(FlowMeter, self).__init__()
# Create a mutex
self.mutex = Lock()
self.currentReading = 0
def run(self):
# Continuously read flowmeter and safely update self.currentReading
while True:
value = readSPI()
self.mutex.acquire()
self.currentReading = value
self.mutex.release()
time.sleep(0.01)
def read(self):
# Main calls this to get latest reading, we just grab it from internal variable
self.mutex.acquire()
value = self.currentReading
self.mutex.release()
return value
if __name__ == '__main__':
# Instantiate and start flow meter manager thread
fmThread = FlowMeter()
fmThread.start()
# Now you can do other things in main, but always get access to latest reading
for i in range(100000):
fmReading = fmThread.read()
print(f"Main: i = {i} FlowMeter reading = {fmReading}")
time.sleep(1)
You could look at using logging
to coordinate and unify your debugging and logging messages - see here.
You could look at events
to let other threads know something needs doing when something reaches a critical level - example here.