Python Thread that cannot be called again - python-3.x

I am trying to implement an alarm trigger functionality for an IoT device using Python thread, but have a problem understanding the logic for it.
My scenario:
I have a sensor that can send me triggers for motion and tamper. So if there is any motion or tamper detected by the sensor, it should trigger the siren.
The Siren is on a GPIO port that I have configured in a separate class. There is only one siren.
Now my code:
def siren(self):
print("Turning on the siren")
setGPIOvalue(<port>, <value>)
def triggeralarms(self,):
siren_trigger = threading.Thread(target=self.siren)
if (alarmed == True):
# Check for all the sensors if there is any alarms to be triggered
for i in range(len(a.senList)):
# Motion alarm
if (motion == True):
print("-----------------> Setting the motion alarm")
if not siren_trigger.is_alive():
siren_trigger.start()
motion == False
# Tamper alarm
if (tamper == True):
print("-----------------> Setting the tamper alarm")
if not siren_trigger.is_alive():
siren_trigger.start()
tamper == False
In the siren, there is a delay of 10 sec.
The triggeralarms() function keeps on checking the status in loop.
Issue:
Now the problem is that the code triggers the GPIO for both motion and tamper sometimes. So both motion and tamper create a thread to trigger the siren.
What I am looking is for to somehow to check if the siren thread is already running, then it should now be started again.
For example, if the motion sensor triggers the siren, and I also receive the trigger for tamper, then if the siren thread is already running, tamper should not start the siren thread again.
I tried to by checking siren_trigger.is_alive() but it seems to be not working.
I am missing the logic here.

Related

GPIO.add_event_detect() is detecting a false button press continuously

My question is: GPIO.add_event_detect() is detecting a false Rising edge continuously in an infinite loop and running the call_back function() infinitely even though I do not press the push-button connected to GPIO 25 even once But the call_back function() keeps executing.
Here is my code, where I want to call the call_back function x1() which contains the function WhatsApp(lat_o,long_o) only when the button is pressed but WhatsApp(lat_o,long_o) keeps executing without me pressing the button. Also, I put WhatsApp(lat_o,long_o) inside x1() to remove the problem of passing arguments to the call_back function.
# INTERRUPTS (NOT WORKING)
# Sample Coordinates
lat_o=33
long_o=72
# Import Libraries
import RPi.GPIO as GPIO
from time import sleep
def x1(channel):
WhatsApp(lat_o,long_o)
# Configure GPIO of Rpi
GPIO.setwarnings(False) # Ignore warning for now
GPIO.setmode(GPIO.BCM) # Use GPIO pin numbering
button1 = 25 # For WhatsApp
# Setup GPIO for Whatsapp
GPIO.setup(button1, GPIO.IN, pull_up_down = GPIO.PUD_DOWN) # Set GPIO 25 (pin 22) to be an input pin for WhatsApp
# Detect button1-press
GPIO.add_event_detect(button1 ,GPIO.RISING, callback = x1)
try:
while True : pass
except:
GPIO.cleanup()
Please help!
I don't want to execute WhatsApp(lat_o,long_o) using Polling (i.e., using if-else in a while loop) in my Final Code for my Final Year Project because I want GPIO to detect button press continuously and using Polling here will drain a lot of power of my Raspberry Pi 4.
According to this discussion on the raspsberrypi discussion
A rising edge will be detected at approx. 1.25V. However, when the
voltage lowers again and the input voltage drops below the 1.16V
level, a stream of interrupts will start, and continue until the level
is below 1.12V.
This is most dramatic when slower rising or falling edges are present,
as an example, when excessive anti-debounce measures have been taken.
This is the given solutuion
In software, I use two other techniques to get rid of the false hits.
First, after the edge has been recognized by the system, we don't know
if it is the one we expect. By waiting for 5mSec, and then reading the
input again but now with a Logic Level command, we can determine if
the edge is indeed what we expect and we then avoid and discard all
other (false) edges.
And finally the code for rising edge
import RPi.GPIO as GPIO
from time import sleep
GPIO.setmode(GPIO.BCM)
Input_Sig = 23 # any plain GPIO pin
# if there is no external pull, use the internal one (pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(Input_Sig, GPIO.IN)
def interrupt_service_routine(Input_Sig):
sleep(0.005) # edge debounce of 5mSec
# only deal with valid edges
if GPIO.input(Input_Sig) == 1:
print("RISING")
return
# define the event; bountime of 5mSec means that subsequent edges will be ignored for 5mSec
GPIO.add_event_detect(Input_Sig, GPIO.RISING, callback=interrupt_service_routine, bouncetime=5)
def main():
try:
while True:
pass # your code
except KeyboardInterrupt:
pass
finally:
print("\nRelease the used pin(s)")
GPIO.cleanup([Input_Sig])
if __name__ == '__main__':
main()

How can i pause a thread until another thread has stopped its action in python?

I have two threads concurrently running, speechRecognition and speakBack. Both of these threads are run in while loops (while True: #do something).
Speech recognition is constantly waiting for microphone input. Then, once it is received, it saves the text version of the verbal input to a file, which is loaded by my second thread, speakBack, and spoken through the speakers.
My issue is that when the phrase is spoken through the speakers, it is picked up by the microphone and then translated and once again saved to this file to be processed, resulting in an endless loop.
How can i make the speechRecognition thread suspend itself, wait for the speakBack thread to stop outputting sound through the speakers, and then continue listening for the next verbal input?
Im using the speechRecognition library and the pyttsx3 library for speech recognition and verbal ouput respectively.
The way to do this is to have shared state between the threads (either with global variables that the threads can store into and read from to indicate their progress, or with a mutable reference that is passed into each thread). The solution I’ll give below involves a global variable that stores a mutable reference, but you could just as easily pass the queue into both threads instead of storing it globally.
Using queues is a very standard way to pass messages between threads in python, because queues are already written in a thread-safe way that makes it so you don’t have to think about synchronization and locking. Furthermore, the blocking call to queue.get is implemented in a way that doesn’t involve repeatedly and wastefully checking a condition variable in a while loop.
Here’s how some code might look:
import queue
START_SPEAK_BACK = 0
START_SPEECH_RECOGNITION = 1
messageQueue = queue.Queue()
# thread 1
def speechRecognition():
while True:
# wait for input like you were doing before
# write to file as before
# put message on the queue for other thread to get
messageQueue.put(START_SPEAK_BACK)
# Calling `get` with no arguments makes the call be
# "blocking" in the sense that it won't return until
# there is an element on the queue to get.
messageFromOtherThread = messageQueue.get()
# logically, messageFromOtherThread can only ever be
# START_SPEECH_RECOGNITION, but you could still
# check that this is true and raise an exception if not.
# thread 2
def speakBack():
while True:
messageFromOtherThread = messageQueue.get()
# likewise, this message will only be START_SPEAK_BACK
# but you could still check.
# Here, fill in the code that speaks through the speakers.
# When that's done:
messageQueue.put(START_SPEECH_RECOGNITION)
Some comments:
This solution uses a single queue. It could just have easily used two queues, one for speakBack —> speechRecognition communication and the other for speechRecognition —> communication. This might make more sense if the two threads were generating messages concurrently.
This solution doesn’t actually involve inspecting the contents of the messages. However, if you need to pass additional information between threads, you could very easily pass objects or data as messages (instead of just constant values)
Finally, it’s not clear to me why you don’t just run all code in the same thread. It seems like there’s a very clear (serial) series of steps you want your program to follow: get audio input, write it to file, speak it back, start over. It might make more sense to write everything as a normal, serial, threadless python program.

PyQt5: How to set a priority to a pyqtSignal?

1. Background info
I'm working in Python 3.7. The python Qt version Pyqt5 enables you to fire custom pyqt signals. For example:
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class MyClass(QObject):
mysignal = pyqtSignal(str)
def __init__(self):
super().__init__()
self.mysignal.connect(self.bar)
return
def foo(self):
self.mysignal.emit("foobar")
return
#pyqtSlot
def bar(self, mystr):
print("signal received: {0}".format(mystr))
return
2. The problem
PyQt starts an event listener loop in the main thread: it waits for incoming events on a queue and processes them one-by-one. Most of these events are user-invoked things like pushing a button, clicking something, ...
If you fire pyqt signals programatically, as in the foo() function above, you also push events onto this queue (I think). That shouldn't be a big deal, unless you fire too many pyqt signals in a short burst. The queue is overwhelmed and user events don't get processed in time. The user sees a freezed GUI. Yikes!
3. Solution
One way to tackle this problem could be assigning low priorities to programatically fired pyqt signal. Is this possible? How?
If not - do you know other ways to solve the problem?
In the case of direct connections (sender and receiver in the same thread), the slot will be directly called when you emit your signal.
So, in your example, you can replace your emit by a direct call to self.bar.
But, if your slot is too long, the event loop has to wait before it will be able to process the user events.
If your UI is freezing when you call your slot, that means you should use another thread to let the event loop process user events.

sync threads to read different resources at exactly the same time

I have two cameras and this is important to read the frames with OpenCV exactly at the same time, I thought something like Lock but I cannot figure out the way I can implement this.
I need some trigger to push and enable the threads to read frames, and then wait for another trigger hit, something like below :
def get_frame(queue, cap):
while running:
if(read_frame):
queue.put(cap.read());
else:
# without this sleep this function just consumes unnecessary CPU time
time.sleep(some_time);
q = Queue.Queue()
# for every camera
for u in xrange(2):
t = threading.Thread(target=get_frame, args = (q, caps[u]))
t.daemon = True
t.start()
The problems with the above implementation are :
I need the sleep time to be defined since I don't know the delay in between every frame read (i.e. it might be long or short, depending on the calculation)
This does not enable me to read once for every trigger hit.
So this approach won't work, Any suggestions?
Consider getting FPS from VideoCapture. Also, note the difference between VideoCapture.grab and VideoCapture.retrieve frame. This is used for camera synchronization.
First call VideoCapture#grab for both cameras and then retrieve the frames. See docs.

Frequent Updating of GUI WxPYTHON

I have a piece of code which has to get executed every 100ms and update the GUI. When I am updating the GUI - I am pressing a button, which calls a thread and in turn it calls a target function. The target function gives back the message to the GUI thread using pub sub as follows.
wx.CallAfter(pub.sendMessage, "READ EVENT", arg1=data, arg2=status_read) # This command line is in my target function
pub.subscribe(self.ReadEvent, "READ EVENT") # This is in my GUI file - whihc calls the following function
def ReadEvent(self, arg1, arg2):
if arg2 == 0:
self.MessageBox('The program did not properly read data from MCU \n Contact the Program Developer')
return
else:
self.data = arg1
self.firmware_version_text_control.Clear()
#fwversion = '0x' + ''.join('{:02X}'.format(j) for j in reversed(fwversion))
self.firmware_version_text_control.AppendText(str(SortAndDecode(self.data, 'FwVersion')))
# Pump Model
self.pump_model_text_control.Clear()
self.pump_model_text_control.AppendText(str(SortAndDecode(self.data, 'ModelName')))
# Pump Serial Number
self.pump_serial_number_text_control.Clear()
self.pump_serial_number_text_control.AppendText(str(SortAndDecode(self.data, 'SerialNum'))[:10]) # Personal Hack to not to display the AA , AB and A0
# Pressure GAIN
self.gain_text_control.Clear()
self.gain_text_control.AppendText(str(SortAndDecode(self.data, 'PresGain')))
# Pressure OFFSET Offset
self.offset_text_control.Clear()
self.offset_text_control.AppendText(str(SortAndDecode(self.data, 'PresOffset')))
#Wagner Message:
#self.status_text.SetLabel(str(SortAndDecode(self.data, 'WelcomeMsg')))
# PUMP RUNNING OR STOPPED
if PumpState(SortAndDecode(self.data, 'PumpState')) == 1:
self.led6.SetBackgroundColour('GREEN')
elif PumpState(SortAndDecode(self.data, 'PumpState')) == 0:
self.led6.SetBackgroundColour('RED')
else:
self.status_text.SetLabel(PumpState(SortAndDecode(self.data, 'PumpState')))
# PUMP RPM
self.pump_rpm_text_control.Clear()
if not self.new_model_value.GetValue():
self.pump_rpm_text_control.AppendText("000")
else:
self.pump_rpm_text_control.AppendText(str(self.sheet_num.cell_value(self.sel+1,10)*(SortAndDecode(self.data, 'FrqQ5'))/65536))
# PUMP PRESSURE
self.pressure_text_control.Clear()
self.pressure_text_control.AppendText(str(SortAndDecode(self.data, 'PresPsi')))
# ON TIME -- HOURS AND MINUTES --- EDITING IF YOU WANT
self.on_time_text_control.Clear()
self.on_time_text_control.AppendText(str(SortAndDecode(self.data, 'OnTime')))
# JOB ON TIME - HOURS AND MINUTES - EDITING IF YOU WANT
self.job_on_time_text_control.Clear()
self.job_on_time_text_control.AppendText(str(SortAndDecode(self.data, 'JobOnTime')))
# LAST ERROR ----- RECHECK THIS AGAIN
self.last_error_text_control.Clear()
self.last_error_text_control.AppendText(str(SortAndDecode(self.data, 'LastErr')))
# LAST ERROR COUNT --- RECHECK THIS AGAIN
self.error_count_text_control.Clear()
self.error_count_text_control.AppendText("CHECK THIS")
As you can see my READEVENT is very big and it takes a while for the GUI to take enough time to successfully do all these things. My problem here is, when my GUI is updating the values of TEXTCTRL it is going unresponsive - I cannot do anything else. I cant press a button or enter data or anything else. My question is if there is a better way for me to do this, so my GUI wont go unresponsive. I dont know how I can put this in a different thread as all widgets are in the main GUI. But that also requires keep creating threads every 100ms - which is horrible. Any suggestions would be greatly helpful.
Some suggestions:
How long does SortAndDecode take? What about the str() of the result? Those may be good candidates for keeping that processing in the worker thread instead of the UI thread, and passing the values to the UI thread pre-sorted-and-decoded.
You can save a little time in each iteration by calling ChangeValue instead of Clear and AppendText. Why do two function calls for each text widget instead of just one? Function calls are relatively expensive in Python compared to other Python code.
If it's possible that the same value will be sent that was sent on the last iteration then adding checks for the new value matching the old value and skipping the update of the widget could potentially save lots of time. Updating widget values is very expensive compared to leaving them alone.
Unless there is a hard requirement for 100ms updates you may want to try 150 or 200. Fewer updates per second may be fast enough for most people, especially since it's mostly textual. How much text can you read in 100ms?
If you are still having troubles with having more updates than the UI thread can keep up with, then you may want to use a different approach than pubsub and wx.CallAfter. For example you could have the worker thread receive and process the data and then add an object to a Queue.Queue and then call wx.WakeUpIdle(). In the UI thread you can have an EVT_IDLE event handler that checks the queue and pulls the first item out of the queue, if there are any, and then updates the widgets with that data. This will give the benefit of not flooding the pending events list with events from too many wx.CallAfter calls, and you can also do things like remove items from your data queue if there are too many items in it.

Resources