diff --git a/esphome/__main__.py b/esphome/__main__.py index 72f0ff34e2..d0a1811bd4 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -281,14 +281,11 @@ def choose_upload_log_host( if has_mqtt_ip_lookup(): options.append(("Over The Air (MQTT IP lookup)", "MQTTIP")) - # Show helpful BOOTSEL instructions for RP2040 when no USB device is found + # Show helpful BOOTSEL instructions for RP2040 when no BOOTSEL device is found if ( purpose == Purpose.UPLOADING and CORE.data.get(KEY_CORE, {}).get(KEY_TARGET_PLATFORM) == PLATFORM_RP2040 - and not any( - get_port_type(opt[1]) in (PortType.SERIAL, PortType.BOOTSEL) - for opt in options - ) + and not any(get_port_type(opt[1]) == PortType.BOOTSEL for opt in options) ): if not options: raise EsphomeError( diff --git a/tests/unit_tests/test_main.py b/tests/unit_tests/test_main.py index 32ebeaacf2..31d5225914 100644 --- a/tests/unit_tests/test_main.py +++ b/tests/unit_tests/test_main.py @@ -934,6 +934,31 @@ def test_choose_upload_log_host_rp2040_bootsel_tip_with_ota( assert "BOOTSEL" in caplog.text +def test_choose_upload_log_host_rp2040_bootsel_tip_with_serial_ports( + caplog: pytest.LogCaptureFixture, + mock_choose_prompt: Mock, +) -> None: + """Test BOOTSEL tip shown when serial ports exist but no BOOTSEL device.""" + setup_core(platform=PLATFORM_RP2040) + + mock_ports = [MockSerialPort("/dev/ttyACM0", "RP2040 Serial")] + with ( + patch("esphome.__main__.get_serial_ports", return_value=mock_ports), + patch( + "esphome.__main__._find_picotool", + return_value=Path("/usr/bin/picotool"), + ), + patch("esphome.__main__.detect_rp2040_bootsel", return_value=0), + caplog.at_level(logging.INFO, logger="esphome.__main__"), + ): + choose_upload_log_host( + default=None, + check_default=None, + purpose=Purpose.UPLOADING, + ) + assert "BOOTSEL" in caplog.text + + def test_choose_upload_log_host_no_bootsel_for_non_rp2040( mock_no_serial_ports: Mock, ) -> None: