@@ -741,6 +741,46 @@ def handle_power_button_press(status: StatusFlag):
741741 )
742742 return awaitable_task .result ()
743743
744+ async def _wait_for_power_button_release (
745+ self , program_start_timeout = 1 , raise_error_on_timeout = False
746+ ):
747+ power_button_pressed : asyncio .Queue [bool ] = asyncio .Queue ()
748+
749+ with self .status_observable .pipe (
750+ op .map (lambda s : bool (s & StatusFlag .POWER_BUTTON_PRESSED )),
751+ op .distinct_until_changed (),
752+ ).subscribe (lambda s : power_button_pressed .put_nowait (s )):
753+ # The first item in the queue is the current status. The status
754+ # could change before or after the last checksum is received,
755+ # so this could be either true or false.
756+ is_pressed = await self .race_disconnect (power_button_pressed .get ())
757+
758+ if not is_pressed :
759+ # If the button isn't already pressed,
760+ # wait a short time for it to become pressed
761+ try :
762+ await asyncio .wait_for (
763+ self .race_disconnect (power_button_pressed .get ()),
764+ program_start_timeout ,
765+ )
766+ except asyncio .TimeoutError :
767+ if raise_error_on_timeout :
768+ raise
769+ # If the button never shows as pressed,
770+ # assume that we just missed the status flag
771+ logger .debug (
772+ "timed out waiting for power button press, assuming is was a short press"
773+ )
774+ return
775+
776+ # At this point, we know the button is pressed, so the
777+ # next item in the queue must indicate the button has
778+ # been released.
779+ is_pressed = await self .race_disconnect (power_button_pressed .get ())
780+
781+ # maybe catch mistake if the code is changed
782+ assert not is_pressed
783+
744784 async def _wait_for_user_program_stop (
745785 self , program_start_timeout = 1 , raise_error_on_timeout = False
746786 ):
0 commit comments