Skip to content

CityHub Remote Control 'Out-of-Range' fails to reconnect #2776

Description

@toyotafj40

Describe the bug
When a train fitted with a CityHub drives Out-of-Range, the Remote Controller light blinks white and eventually turns off.
The hub has been programmed to 'continue' when out of range and continues moving and eventually returns and is now back in range. Pressing the green 'power' button on the remote control occasionally recovers and communication is restored. This is a vast improvement on the earlier hub.ble library and firmware from June last year, but still very problematic.

To reproduce
Steps to reproduce the behavior:
I created a simple program to connect to the remote, with logging to the serial monitor.
Then I just walk with the remote , from the study to the kitchen. The remote controller led flashes and goes out.
I then press the power button and walk back to the study.
Sometimes the remote connects. Other times not.
Occasionally the hub locks up while printing "Please power on the Remote" -> missing 'he Remote'
Reboot requires occasional removal of batteries

Expected behavior
The remote should reconnect

Screenshots
LOG FILE and SAMPLE CODE attached

RemoteController-OutOfRange-Bug.py

RemoteController-OutOfRange-Bug.log

Activity

  1. BertLindeman commented on Jul 28, 2026

    @BertLindeman

    Helo,

    For ease of reading I paste your program and the log here:

    from pybricks.hubs import CityHub
    from pybricks.pupdevices import Remote
    from pybricks.parameters import Color
    from pybricks.tools import wait
    
    
    hub = CityHub()
    
    remote = None
    connection = 0
    disconnect = 0
    
    
    print("\n===== Remote Reconnect Test =====")
    
    
    def connect_remote():
    
        global connection
    
        while True:
    
            print("\nPlease power on the Remote...")
    
            remote = None
    
            try:
    
                remote = Remote(timeout=5000)
    
                name = remote.name()
    
                print("--------------------------------")
                print("Remote    :", repr(name))
                print("--------------------------------")
    
                wait(1000)
    
                # Force a real BLE transaction
                remote.light.off()
    
                connection += 1
    
                print("Remote READY")
                print("Connection :", connection)
    
                return remote
    
    
            except Exception as e:
    
                print("Invalid Remote object")
                print(type(e), e.args)
    
                if remote is not None:
                    try:
                        remote.disconnect()
                    except Exception:
                        pass
    
                wait(3000)
    
    
    
    while True:
    
        remote = connect_remote()
    
    
        led_on = False
    
    
        while True:
    
            try:
    
                if led_on:
                    remote.light.on(Color.RED)
                else:
                    remote.light.off()
    
                led_on = not led_on
    
                wait(500)
    
    
            except Exception as e:
    
                disconnect += 1
    
                print("\n================================")
                print("Connection LOST :", disconnect)
                print("Exception Type  :", type(e))
                print("Exception Args  :", e.args)
                print("================================")
    
    #            try:
    #                remote.disconnect()
    #            except Exception as e:
    #                print("Disconnect cleanup:", e.args)
    
                remote = None
    
                print("Waiting for BLE cleanup...")
                wait(10000)
    
                break
    The annotated log
    ===== Remote Reconnect Test =====
    
    Please power on the Remote...
    --------------------------------
    Remote    : 'Handset'
    --------------------------------
    Remote READY
    Connection : 1
    
    ================================
    Connection LOST : 1						*** Walked to the kitchen and signal lost and remote control powered down. Unsure as to why error 19 generated? *** 
    Exception Type  : <class 'OSError'>
    Exception Args  : (19, "\n\nA sensor or motor is not connected to the specified port:\n--> Check the cables to each motor and sensor.\n--> Check the port settings in your script.\n--> Check the line in your script that matches\n    the line number given in the 'Traceback' above.\n\n")
    ================================
    Waiting for BLE cleanup...
    
    Please power on t						*** The HUB now locked up having NOT completed the error message "Please power on the Remote"
    
    ReBoot
    ===== Remote Reconnect Test =====
    
    Please power on the Remote...
    --------------------------------
    Remote    : 'Handset'
    --------------------------------
    Remote READY
    Connection : 1
    
    ================================
    Connection LOST : 1
    Exception Type  : <class 'OSError'>
    Exception Args  : (19, "\n\nA sensor or motor is not connected to the specified port:\n--> Check the cables to each motor and sensor.\n--> Check the port settings in your script.\n--> Check the line in your script that matches\n    the line number given in the 'Traceback' above.\n\n")
    ================================
    Waiting for BLE cleanup...
    
    Please power on the Remote...
    --------------------------------
    Remote    : 'Handset'
    --------------------------------
    Remote READY
    Connection : 2
    
    ================================
    Connection LOST : 2
    Exception Type  : <class 'OSError'>
    Exception Args  : (19, "\n\nA sensor or motor is not connected to the specified port:\n--> Check the cables to each motor and sensor.\n--> Check the port settings in your script.\n--> Check the line in your script that matches\n    the line number given in the 'Traceback' above.\n\n")
    ================================
    Waiting for BLE cleanup...
    
    Please power on the Remote...
    --------------------------------
    Remote    : 'Handset'
    --------------------------------
    Remote READY
    Connection : 3
    
    ================================
    Connection LOST : 3
    Exception Type  : <class 'OSError'>
    Exception Args  : (19, "\n\nA sensor or motor is not connected to the specified port:\n--> Check the cables to each motor and sensor.\n--> Check the port settings in your script.\n--> Check the line in your script that matches\n    the line number given in the 'Traceback' above.\n\n")
    ================================
    Waiting for BLE cleanup...
    
    Please power on the Remote...
    Invalid Remote object
    <class 'OSError'> (116, 'Timed out')
    
    Please power on t						*** The HUB now locked up having NOT completed the error message "Please power on the Remote"
    
    
    ===== Remote Reconnect Test =====
    
    Please power on the Remote...
    --------------------------------
    Remote    : 'Handset'
    --------------------------------
    Remote READY
    Connection : 1
    
    ================================
    Connection LOST : 1
    Exception Type  : <class 'OSError'>
    Exception Args  : (19, "\n\nA sensor or motor is not connected to the specified port:\n--> Check the cables to each motor and sensor.\n--> Check the port settings in your script.\n--> Check the line in your script that matches\n    the line number given in the 'Traceback' above.\n\n")
    ================================
    Waiting for BLE cleanup...
    
    Please power on t						*** The HUB now locked up having NOT completed the error message "Please power on the Remote" 
    
    Time to log a bug!
    

    What firmware are you running?

    Bert

  2. BertLindeman commented on Jul 28, 2026

    @BertLindeman

    Running Firmware v4.1.0b2 the current firmware on beta.pybricks.com.
    Ran your program.
    Walked away until the remote no longer blinked red.
    Walked back and pressed the center button of the remote.
    Both times the connection came up fine.

    My log
    
    ===== Remote Reconnect Test =====
    
    Please power on the Remote...
    --------------------------------
    Remote    : 'Handset left'
    --------------------------------
    Remote READY
    Connection : 1
    
    ================================
    Connection LOST : 1
    Exception Type  : <class 'OSError'>
    Exception Args  : (19, "\n\nA sensor or motor is not connected to the specified port:\n--> Check the cables to each motor and sensor.\n--> Check the port settings in your script.\n--> Check the line in your script that matches\n    the line number given in the 'Traceback' above.\n\n")
    ================================
    Waiting for BLE cleanup...
    
    Please power on the Remote...
    --------------------------------
    Remote    : 'Handset left'
    --------------------------------
    Remote READY
    Connection : 2
    
    ================================
    Connection LOST : 2
    Exception Type  : <class 'OSError'>
    Exception Args  : (19, "\n\nA sensor or motor is not connected to the specified port:\n--> Check the cables to each motor and sensor.\n--> Check the port settings in your script.\n--> Check the line in your script that matches\n    the line number given in the 'Traceback' above.\n\n")
    ================================
    Waiting for BLE cleanup...
    
    Please power on the Remote...
    Invalid Remote object
    <class 'OSError'> (116, 'Timed out')
    
    Please power on the Remote...
    Invalid Remote object
    <class 'OSError'> (116, 'Timed out')
    
    Please power on the Remote...
    --------------------------------
    Remote    : 'Handset left'
    --------------------------------
    Remote READY
    Connection : 3
    

    The error 19 means "no device" as the remote connection failed and dropped out :

    Traceback (most recent call last):
      File "issue_2776_remote_connect_debug.py", line 32, in <module>
    OSError: [Errno 19] ENODEV: 
    
  3. toyotafj40 commented on Jul 29, 2026

    @toyotafj40
    Author

    Hi Bert,

    Hub programmed with Pybricks Code v3.0.1 with firmware v4.0.1

    Also, as per the previous log, I also had numerous test cycles that achieved 3-5 Out-of-Range events successfully recover.
    Then on numerous other occasions where it did not recover at all with only one OOR event.
    I also tried this on 4 separate hubs and 2 remotes, with a variety of fresh and not-so-fresh batteries. Could not pin down a specific pattern.

    NOW Tested with v4.1.0b2. and it's much better - the first test ran 5 passes before failure = Invalid Remote object.
    Seems the Bluetooth stopped as the error message was truncated <class 'Runtime

    The hub needed a reboot to recover.

    Log is attached
    RemoteOutOfRange-v4.1.0b2.log

    Regards
    Peter

  4. BertLindeman commented on Jul 29, 2026

    @BertLindeman

    Hi Peter,

    Pasting the text of the log is easier for the reader and the relevant part is:

    Please power on the Remote...
    --------------------------------
    Remote    : ''
    --------------------------------
    Remote READY
    Connection : 5
    
    ================================
    Connection LOST : 5
    Exception Type  : <class 'OSError'>
    Exception Args  : (19, "\n\nA sensor or motor is not connected to the specified port:\n--> Check the cables to each motor and sensor.\n--> Check the port settings in your script.\n--> Check the line in your script that matches\n    the line number given in the 'Traceback' above.\n\n")
    ================================
    Waiting for BLE cleanup...
    
    Please power on the Remote...
    Invalid Remote object
    <class 'OSError'> (116, 'Timed out')
    
    Please power on the Remote...
    --------------------------------
    Remote    : ''
    --------------------------------
    Invalid Remote object
    <class 'Runtime
    

    This shows the timeout as error.

    How about if you change this line:

    remote = Remote(timeout=5000)

    into:

    remote = Remote(timeout=None)

    So the timeout is prevented?

    Have changed:

    • changed the timeout to None

    and cosmetic:

    • removed some blank lines to make the program more compact to show here
    • a wait(10) after the print to show the complete printline
    • set the connected remote color to green to be able to see the connection is there.

    The complete issue_2776_remote_connect_v2.py:

    from pybricks.hubs import CityHub
    from pybricks.pupdevices import Remote
    from pybricks.parameters import Color
    from pybricks.tools import wait
    
    hub = CityHub()
    
    remote = None
    connection = 0
    disconnect = 0
    print("\n===== Remote Reconnect Test =====")
    
    
    def connect_remote():
        global connection
        while True:
            print("\nPlease power on the Remote...")
            remote = None
            wait(10)  # to give BLE the time to completely print the line
            try:
                remote = Remote(timeout=None)
                name = remote.name()
                print("--------------------------------")
                print("Remote    :", repr(name))
                print("--------------------------------")
                wait(1000)
                # Force a real BLE transaction
                remote.light.on(Color.GREEN)
                connection += 1
                print("Remote READY")
                print("Connection :", connection)
                return remote
    
            except Exception as e:
                print("Invalid Remote object")
                print(type(e), e.args)
    
                if remote is not None:
                    try:
                        remote.disconnect()
                    except Exception:
                        pass
    
                wait(3000)
    
    while True:
        remote = connect_remote()
        led_on = False
    
        while True:
            try:
                if led_on:
                    remote.light.on(Color.RED)
                else:
                    remote.light.off()
                led_on = not led_on
                wait(500)
    
            except Exception as e:
                disconnect += 1
                print("\n================================")
                print("Connection LOST :", disconnect)
                print("Exception Type  :", type(e))
                print("Exception Args  :", e.args)
                print("================================")
    
    #            try:
    #                remote.disconnect()
    #            except Exception as e:
    #                print("Disconnect cleanup:", e.args)
    
                remote = None
                print("Waiting for BLE cleanup...")
                wait(10000)
                break

    Part of the log:

    --------------------------------
    Remote    : 'Handset left'
    --------------------------------
    Remote READY
    Connection : 10
    
    ================================
    Connection LOST : 10
    Exception Type  : <class 'OSError'>
    Exception Args  : (19, "\n\nA sensor or motor is not connected to the specified port:\n--> Check the cables to each motor and sensor.\n--> Check the port settings in your script.\n--> Check the line in your script that matches\n    the line number given in the 'Traceback' above.\n\n")
    ================================
    Waiting for BLE cleanup...
    
    Please power on the Remote...
    --------------------------------
    Remote    : 'Handset left'
    --------------------------------
    Remote READY
    Connection : 11
    
    ================================
    Connection LOST : 11
    Exception Type  : <class 'OSError'>
    Exception Args  : (19, "\n\nA sensor or motor is not connected to the specified port:\n--> Check the cables to each motor and sensor.\n--> Check the port settings in your script.\n--> Check the line in your script that matches\n    the line number given in the 'Traceback' above.\n\n")
    ================================
    Waiting for BLE cleanup...
    

    Did not have a failure at all in 11 attempts.
    Even tried to takeover the remote connection to another remote and that also succeeds.

    How about a test in your setup?

    Bert

  5. toyotafj40 commented on Jul 29, 2026

    @toyotafj40
    Author

    Hi Bert,

    Thanks for the reply!

    I ran the attached 'cleaned up' program and got these results.
    Attempt 1 = failed at reconnect #1
    Attempt 2 = failed at reconnect #9
    Attempt 3 = failed at reconnect #6

    I will do more testing tomorrow using 4 hubs and 4 remotes with the latest firmware and software.

    one more point before I sign off...
    I usually test connectivity in the kitchen. it is far enough away for the BLE signal to be marginal.
    If I step in front of the fridge the signal is lost.
    When I step away from the fridge, sometimes the signal recovers, sometime the remote turns off.
    With the remote off, I take a step towards to study (hub location) and press the power button on the remote, to recover the signal.
    I know that is testing at the limits and probably more frequent than in a real train scenario, but it should still recover...

    Regards
    Peter

  6. BertLindeman commented on Jul 29, 2026

    @BertLindeman

    Thanks for the response Peter.

    More hubs cause more noise and make communication more difficult.
    But reliability is high upon the ladder, sure.

    Bert

  7. added
    hub: handsetIssues related to the LEGO Powered Up Handset (remote control)
    and removed
    triageIssues that have not been triaged yet
    on Sep 9, 2026
  8. added theissue type on Sep 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    hub: handsetIssues related to the LEGO Powered Up Handset (remote control)software: pybricks-micropythonIssues with Pybricks MicroPython firmware (or EV3 runtime)topic: bluetoothIssues involving bluetooth

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions