Stay connected to peripherals when program ends#459
Stay connected to peripherals when program ends#459laurensvalk wants to merge 13 commits intomasterfrom
Conversation
Do it on shutdown instead, and simplify shutdown logic more generally.
Release user claim if it is not connected and not currently busy connecting. This allows reconnecting if disconnected due to the peripheral powering off.
Multiple peripherals of the same kind may have a different config. This was still in its singleton form after adding support for multiple peripherals earlier. With a singleton instance, there would be a conflict for e.g. a Powered Up remote and a Mario Hub.
This allows testing behaviors such as remaning connected to peripherals between program runs.
|
Still need some cleanup and testing. This has only been tested on Prime Hub so far. City/Move/Technic support only one peripheral, but auto re-connection has been added (not yet tested). |
|
Never too soon you said ;-) Short:
Details 1 from pybricks.iodevices import XboxController
xbox = XboxController(connect=False)Should this disconnect the controller of not? With this firmware it disconnects: Details 2 from pybricks.iodevices import XboxController
from pybricks.tools import wait
print("pre simple connect")
xbox = XboxController()
wait(250)
print("pre connect=False")
xbox = XboxController(connect=False)
wait(250)
print("post connect=False")
xbox = XboxController(connect=True)
wait(250)
print("post connect=True")
for i in range(5):
print(xbox.dpad())
wait(500)
print("Done")Results in: The xbox ctrl thinks it is connected the whole time the program runs. |
If your goal is to interactively connect and disconnect, you can use the connect and disconnect methods now. They were introduced so you don't have to keep making new objects. Could you also try the intended scenario? 😄 So just create your usual programs with a remote. You should be able to stop and start programs without hassle of restarting the controller. |
Will do
Did that and that works fine, both for xbox and remote. |
|
Good to hear that it works! |
Reduce the number of partially parsed arguments that we pass around. This makes everything simpler, reduces code size, and we can keep the address out of the filters. This way we can re-use them outside of the scan-and-connect procedure.
Parse arguments only during init and reset the appropriate state only on reconnect. This is working towards a real and virtual reconnect.
We want to re-use these for every connect call.
Allow instantiating without connecting, letting the user (asynchronously) connect later. Fixes pybricks/support#1800
If the timeout was long, resetting it in between the scan and scan response makes it shorter, which is not intended. Keep it simple by extending only for connect and pairing. Also refactor the waiting loops to make them easier to follow with a scan timeout shorthand.
Makes it consistent with the LWP3Device. Fixes pybricks/support#1800
This lets you stay connected and use your regular code. If you do Remote(args) and a matching device is connected and not already in use, you get this device.
When re-using an existing connection, this lets us make sure all filters match as if making a new connection.
When we skip discovery, we'll still need the handle. There is only one handle for LWP3 devices, so we can reuse it. We might revisit this to skip only the connection but redo the discovery phase for generality.
53e3b67 to
7ff2e5a
Compare
|
Now tested and fixed for Move/City/Technic Hub. |
Fixes:
Ever since we supported the Powered Up remote, peripherals would disconnect when the program ends. This wasn't quite so bad for the Powered Up remote since it generally just stays on while you load a new program.
Other peripherals like the Xbox Controller turn off entirely, and need to stay off a little while before you can turn them back on. This makes iterating code quite annoying.
This was initially due to driver limitations, but the Bluetooth drivers have had a lot of improvements since then.
This PR leverages these changes to allow staying connected, in a way that doesn't change the overal user code or user experience. Users will still initiate their device as
my_remote = Remote(). But the second time you connect, this will just pass instantly since it is already connected.This works for multiple peripherals too. It remembers the advertisement and response that it originally matched to, so a new class can be initiated and re-use an existing connection if the filters match. In the following demo (admittedly a bit silly), you can see this in action. Towards the end, the program is stopped and restarted, and everything just stays connected.
signal-2026-02-03-194159_002.mp4
This PR also added async-compatible
connect()anddisconnect()and aconnect=Truekwarg to the class initializer so you can optionally skip connecting right at the beginning.