I am working on a python-based shiny app that serves to drive a fluid pump over a serial transmission line. After configuring a flow profile with set amplitudes and runtime, the serial transmission can be started by pressing an action button "p1".
The issue I am facing is the lack of reactivity inside the reactive.event(input.p1) associated with the button "p1": I want to ensure that the transmission started by clicking "p1" thus triggering the reactive.event(input.p1) can be terminated anytime by clicking "p2".
However, the current implementation causes the stop message in reactive.event(input.p2) to queue up and be sent after the transmission in reactive.event(input.p1) has ended.
How can I fix this? Is there any way to make sure my program is still reactive to other inputs? I want the transmission to stop immediately as soon as "p2" is clicked. Implementation of both buttons are dropped below.
@reactive.Effect
@reactive.event(input.p1)
def _():
y = yg.get() # fetch np.array y from reactive value yg, numbers in y correspond to driving voltages
for e in y: # iterate over array
msg = "1:1:"+str(e)+":100" # formatted string containing the driving voltage
#print(msg) # print to console in debug mode
ser.write(bytes(msg,'utf-8')) # send the formatted string
t0 = time.time() # time stamp
while(((time.time()-t0)<=2)): # next driving voltage should be transmitted after 2 seconds
pass
ser.write(bytes("0:1",'utf-8')) # stops the pump after transmission has ended
@reactive.Effect
@reactive.event(input.p2)
def _():
#print("1:0")
ser.write(bytes("0:1",'utf-8')) # Stop the pump
Alright, I managed to solve the problem by creating a timer through threading. Personally, I think that the answer is that in and of itself it is not possible to preserve reactivitiy inside a loop. I tried various implementations including the ones that @phili_b suggested. But nothing really forced the program out of the while loop that was called in a reactive event related to button p1 by clicking button p2.
This is the solution that worked for me:
I know this is a workaround rather than a fix for the implementation I suggested in the OP. Although the code now does what I want it to do, I am still curious if there is a way to make the original code work. I am interested to know if it is intrinsically possible to deal with the limitations a loop seemingly has on the program.
Edit
Added entire code per request: Note that the buttons are found on the bottom left. GUI is in a very rough state and looks hideous. This is just for reproduction purposes.