Chapter 40: Using VS Code for Python Development with Remote RPi5 Access

Chapter Objectives

By the end of this chapter, you will be able to:

  • Understand the architecture and benefits of using a remote development environment with Visual Studio Code and the Raspberry Pi 5.
  • Configure a Raspberry Pi 5 for secure, passwordless remote access using the Secure Shell (SSH) protocol.
  • Establish a remote development session from a host computer to a Raspberry Pi 5 using the VS Code Remote – SSH extension.
  • Develop, execute, and debug Python applications directly on the Raspberry Pi 5’s filesystem from the comfort of the VS Code IDE.
  • Manage project files, dependencies, and use the integrated terminal for a seamless remote workflow.
  • Troubleshoot common connectivity and configuration issues encountered during remote development.

Introduction

it is common to rely on simple command-line text editors like Nano or Vim directly on the target device in the initial stages of embedded development. While effective for minor edits, this approach quickly reveals its limitations as projects grow in complexity. Modern software development thrives on the rich features of Integrated Development Environments (IDEs)—tools that provide syntax highlighting, intelligent code completion (IntelliSense), integrated debugging, and version control management. For a long time, the embedded world felt disconnected from these powerful tools, forcing developers into a cumbersome cycle of writing code on a host machine, cross-compiling, transferring the binary, and then attempting to debug remotely with limited visibility.

This chapter introduces a paradigm shift in embedded development workflow, leveraging the power of Visual Studio Code (VS Code) and its Remote Development capabilities. We will demonstrate how to transform your powerful desktop or laptop into a sophisticated development console for the Raspberry Pi 5. By using the Remote – SSH extension, you can connect VS Code on your host machine directly to the environment of your Raspberry Pi. This is not merely a remote file editor; it establishes a full-featured development experience where VS Code runs its UI locally, but executes commands for editing, debugging, and terminal sessions on the remote Pi. This “thin client” model gives you the best of both worlds: the responsive, feature-rich interface of a native IDE and direct access to the hardware, libraries, and runtime environment of your embedded target. This chapter will guide you through setting up this powerful workflow, from initial SSH configuration to writing and debugging Python applications that interact with the Raspberry Pi’s GPIO pins, bridging the gap between professional software practices and hands-on embedded engineering.

Technical Background

To fully appreciate the seamless experience of remote development with VS Code, it is essential to understand the foundational technologies that make it possible. The entire workflow is built upon a clever client-server architecture, with the Secure Shell (SSH) protocol serving as the secure backbone for all communication.

The VS Code Remote Development Architecture

At its core, the VS Code Remote Development model is a sophisticated separation of concerns. When you initiate a remote session, you are not simply streaming the screen of a remote desktop. Instead, VS Code partitions itself into two distinct components. The UI Client, which is the standard VS Code application you run on your host machine (Windows, macOS, or Linux), is responsible for rendering the user interface—the editor windows, panels, and buttons. This ensures a fluid, responsive, and native user experience.

The second component is the VS Code Server, a small, headless application that is automatically installed and run on the remote machine—in our case, the Raspberry Pi 5—the first time you connect. This server is the workhorse of the operation. It handles the heavy lifting: reading and writing files directly on the Pi’s filesystem, managing installed extensions (which are also installed on the remote server), providing language-specific features like code completion and analysis, and running the debugger. The local VS Code client communicates with this remote server over a secure channel, sending user actions (like typing or clicking a button) to the server and receiving information to display in the UI.

graph TD
    subgraph Host Computer
        A["VS Code Client <br><i>(UI, Input Handling)</i>"]
    end

    subgraph Raspberry Pi 5
        B["VS Code Server <br><i>(File System, Terminal, Debugger, Extensions)</i>"]
    end

    A -- "SSH Tunnel<br><b>(Commands, UI Events, File Data)</b>" --> B

    style A fill:#1e3a8a,stroke:#1e3a8a,stroke-width:2px,color:#ffffff
    style B fill:#8b5cf6,stroke:#8b5cf6,stroke-width:1px,color:#ffffff

This architecture is profoundly efficient. It avoids the latency and graphical overhead of traditional remote desktop solutions. Only the necessary data—primarily text and control signals—is transmitted over the network. This means you can have a full-fidelity development experience even over connections with modest bandwidth. Furthermore, because the extensions and language services run on the Pi itself, they have direct access to the target’s toolchains, compilers, interpreters, and hardware, eliminating the complexities of setting up a cross-compilation environment on the host machine for many development scenarios.

The Secure Shell (SSH) Protocol

The indispensable transport layer for this architecture is the Secure Shell (SSH) protocol. SSH is a cryptographic network protocol designed for operating network services securely over an unsecured network. Its most well-known application is for remote command-line login and execution, but its capabilities extend to tunneling arbitrary network connections and transferring files, which is precisely what VS Code leverages.

SSH was created in the mid-1990s as a secure replacement for insecure protocols like Telnet, which transmitted all data, including passwords, in plaintext, leaving them vulnerable to interception. SSH, by contrast, establishes a heavily encrypted channel between the client and the server. When you connect from your host machine to the Raspberry Pi, SSH negotiates a secure session using a combination of symmetric encryption, asymmetric encryption, and hashing algorithms. This ensures the confidentiality (data cannot be read by eavesdroppers), integrity (data cannot be modified in transit), and authenticity (you are certain you are connecting to the correct server) of your entire development session.

Authentication is a critical part of the SSH handshake. The most common method, especially for initial setup, is password-based authentication. The server prompts the user for a password, which is sent over the encrypted channel for verification. While secure from eavesdropping, this method can be susceptible to brute-force attacks if weak passwords are used and can become tedious if you connect frequently.

A far more secure and convenient method is public-key authentication. This mechanism uses a pair of cryptographic keys: a private key and a public key. The private key is kept secret and secure on your host machine and is typically protected by a passphrase. The corresponding public key is copied to the remote server (the Raspberry Pi) and stored in a special file within the user’s home directory (~/.ssh/authorized_keys).

When you attempt to connect, the SSH client tells the server it wants to authenticate using a key. The server finds the public key, encrypts a random challenge message with it, and sends it to the client. Only the holder of the corresponding private key can decrypt this message. The client decrypts the challenge with its private key, processes it as requested by the server, and sends the result back. If the response is correct, the server grants access. This entire exchange happens without the private key ever leaving your host machine, making it immune to password-sniffing and highly resistant to brute-force attacks. For professional development, public-key authentication is the industry standard. It provides robust security while enabling automated, password-free logins, which is a cornerstone of the seamless VS Code remote experience.

sequenceDiagram
    participant Client as Host Computer
    participant Server as Raspberry Pi 5

    Client->>Server: Initiate Connection (user, pubkey_id)
    activate Server
    Note over Server: Server looks up user's<br>authorized_keys file for public key.
    Server-->>Client: Encrypt(Challenge, PublicKey)
    deactivate Server
    activate Client
    Note over Client: Client uses its private key<br>to decrypt the challenge.
    Client->>Server: Decrypted Challenge Response
    deactivate Client
    activate Server
    Note over Server: Server verifies the response.
    alt Correct Response
        Server-->>Client: Access Granted
    else Incorrect Response
        Server-->>Client: Access Denied
    end
    deactivate Server

When VS Code establishes its connection, it first uses SSH to authenticate and then to install its server component. Subsequently, all communication between the VS Code client and server is tunneled through this secure SSH connection, protecting your source code, terminal commands, and debugging information from any potential snooping on the network.

Practical Examples

Now, let’s transition from theory to practice. This section provides a step-by-step guide to configuring your environment and launching your first remote Python development session on the Raspberry Pi 5.

Preparing the Raspberry Pi 5 for SSH Access

Before we can connect from a remote machine, we must first enable the SSH server on the Raspberry Pi. By default, for security reasons, it is disabled.

  1. Boot your Raspberry Pi 5 with Raspberry Pi OS and ensure it is connected to your local network via Wi-Fi or Ethernet.
  2. Open a terminal window on the Raspberry Pi’s desktop.
  3. Run the Raspberry Pi configuration tool:
    sudo raspi-config
  4. Navigate to Interface Options using the arrow keys and press Enter.
  5. Select SSH and press Enter.
  6. You will be asked if you would like the SSH server to be enabled. Select <Yes> and press Enter.
  7. A confirmation dialog will appear. Press Enter to acknowledge it.
  8. Select <Finish> to exit the configuration tool.
  9. Finally, we need to find the IP address of your Raspberry Pi. In the terminal, type:
    hostname -I
    This command will print the IP address (e.g., 192.168.1.105). Make a note of this address, as you will need it to connect from your host machine.

Tip: For a more stable connection, consider configuring a static IP address for your Raspberry Pi on your router. This prevents the IP address from changing after a reboot.

Setting Up the Host Machine with VS Code

Now, on your main development computer (Windows, macOS, or Linux), we will install and configure VS Code.

1. Install Visual Studio Code: If you haven’t already, download and install VS Code from the official website: https://code.visualstudio.com/.

2. Install the Remote – SSH Extension:

  • Launch VS Code.Click on the Extensions icon in the Activity Bar on the side of the window (it looks like four squares).In the search bar, type Remote - SSH.The top result should be the extension by Microsoft. Click the Install button.

  • Configure the SSH Connection:
    • Once installed, a new Remote Explorer icon (it looks like a computer monitor with a >< symbol) will appear in the Activity Bar. Click it.
    • Ensure that “SSH” is selected in the dropdown at the top of the Remote Explorer panel.
    • Click the “+” (New Remote) button.
    • An input box will appear. Enter the SSH connection command using the username and IP address of your Raspberry Pi. The default username for Raspberry Pi OS is pi.
      ssh pi@192.168.1.105
      (Replace 192.168.1.105 with your Pi’s actual IP address). Press Enter.
    • VS Code will then ask you which SSH configuration file to update. Select the default one, which is usually located in your user’s home directory.
    • A notification will appear in the bottom-right corner confirming the host has been added. You can now connect.

Establishing Your First Remote Session

With the configuration complete, connecting is straightforward.

  1. In the Remote Explorer panel, you should now see your Raspberry Pi listed under “SSH”.
  2. Hover over the host entry and click the Connect to Host in New Window icon (a folder with a plus sign).
  3. A new VS Code window will open. The first time you connect, you may be prompted to confirm the fingerprint of the remote host. Type yes and press Enter.
  4. Next, you will be prompted for the password for the pi user. Enter the password you set for your Raspberry Pi.
  5. VS Code will now connect and automatically install the VS Code Server on the Pi. You can monitor the progress in a pop-up notification. This only happens on the first connection.
  6. Once connected, look at the green indicator in the bottom-left corner of the VS Code window. It should say SSH: 192.168.1.105, confirming you are in a remote session.

Creating a “Hello, World!” Python Application

Let’s create and run a simple Python script to verify our setup.

1. Open a Folder: In the remote VS Code window, go to the Explorer panel. Click on Open Folder. An input box will appear, defaulting to the home directory of the pi user (/home/pi). Let’s create a new project folder. Type python_projects and click OK. This folder will be created on your Raspberry Pi’s filesystem.

2. Create a New File: Once the folder is open, click the “New File” icon in the Explorer panel and name the file hello.py.

3. Write the Code: Enter the following Python code into the editor. Notice that you get full syntax highlighting.

Python
# hello.py
# A simple script to verify the remote development environment.

import platform

def main():
    """Prints a welcome message and system information."""
    print("Hello from a Raspberry Pi 5!")
    print(f"Running on architecture: {platform.machine()}")
    print(f"Operating System: {platform.system()} {platform.release()}")

if __name__ == "__main__":
    main()

4. Run the Script:

Open an integrated terminal in VS Code (Terminal -> New Terminal). This terminal is not running on your host machine; it’s a shell session directly on your Raspberry Pi.

In the terminal, execute the script:

Bash
python3 hello.py

5. Expected Output: You should see the following output in the terminal, confirming the code ran on the Pi:

Plaintext
Hello from a Raspberry Pi 5!
Running on architecture: aarch64
Operating System: Linux 6.6.20+rpt-rpi-2712

Hardware Integration: Reading a Temperature Sensor

A key advantage of this setup is the ability to interact directly with hardware. Let’s write a Python script to read data from a DHT22 temperature and humidity sensor.

Warning: Always shut down your Raspberry Pi before connecting or disconnecting any components on the GPIO header to avoid accidental shorts and damage.

1. Hardware Required:

  • Raspberry Pi 5
  • Breadboard
  • DHT22 (or DHT11) temperature and humidity sensor
  • Jumper wires

2. Wiring:

  • Shut down your Raspberry Pi.Connect the components as follows:
    • DHT22 VCC (Pin 1) -> Raspberry Pi 3.3V (Pin 1)DHT22 Data (Pin 2) -> Raspberry Pi GPIO 4 (Pin 7)DHT22 GND (Pin 4) -> Raspberry Pi Ground (Pin 9)

3. Install the Required Library:

  • Power on your Pi and connect to it using your remote VS Code session.
  • Open an integrated terminal.
  • We need to install the Adafruit CircuitPython DHT library. Run the following command:
Bash
pip install adafruit-circuitpython-dht

4. Create the Python Script:

  • In your python_projects folder in VS Code, create a new file named read_sensor.py.Enter the following code. Notice how VS Code can provide autocompletion for the libraries you’ve just installed on the Pi.

Python
# read_sensor.py
# Reads temperature and humidity from a DHT22 sensor.

import time
import board
import adafruit_dht

# --- Configuration ---
# The DHT sensor data pin is connected to GPIO 4
# board.D4 is the board-agnostic way to refer to GPIO 4
DHT_SENSOR = adafruit_dht.DHT22(board.D4)

def main():
    """
    Main loop to continuously read from the sensor.
    Handles potential errors during reading.
    """
    print("Starting sensor reading. Press Ctrl+C to exit.")
    while True:
        try:
            # Read the temperature and humidity from the sensor
            temperature_c = DHT_SENSOR.temperature
            humidity = DHT_SENSOR.humidity

            # The sensor can sometimes return None, especially on startup.
            if humidity is not None and temperature_c is not None:
                # Convert temperature to Fahrenheit for demonstration
                temperature_f = temperature_c * (9 / 5) + 32

                # Print the readings to the console
                print(f"Temp: {temperature_c:.1f} C / {temperature_f:.1f} F | Humidity: {humidity:.1f}%")
            else:
                print("Sensor failed to return data. Retrying...")

        except RuntimeError as error:
            # Errors happen, especially with DHT sensors.
            # This catches them and allows the script to continue.
            print(f"Error reading sensor: {error.args[0]}")
        except Exception as e:
            # Handle other potential exceptions and ensure the sensor is cleaned up
            DHT_SENSOR.exit()
            raise e

        # Wait 2 seconds between readings
        time.sleep(2.0)

if __name__ == "__main__":
    main()

5. Run and Verify:

In the integrated terminal, run the script. Note that interacting with GPIO often requires root privileges.

Bash
sudo python3 read_sensor.py

You should see the temperature and humidity readings printed to the console every two seconds, live from the sensor connected to your Raspberry Pi.

Common Mistakes & Troubleshooting

Even with a streamlined workflow, you may encounter issues. Here are some common pitfalls and how to resolve them.

Mistake / Issue Symptom(s) Troubleshooting / Solution
Connection Refused / Timeout VS Code shows an error like Could not establish connection… Connection timed out or Connection refused.
  1. Check IP Address: Verify the Pi’s IP with hostname -I on the Pi itself.
  2. Check Network Reachability: From your host PC’s terminal, run ping <pi_ip_address>. If it fails, there’s a network issue.
  3. Check SSH Service: On the Pi, run sudo raspi-config and ensure SSH is enabled under “Interface Options”.
  4. Check Firewall: Ensure your host PC’s firewall isn’t blocking outbound traffic on port 22.
Permission Denied The terminal or VS Code prompts for a password repeatedly, then fails with an error like Permission denied (publickey,password). For Password Auth: You are simply typing the wrong password. Double-check it.

For Public Key Auth: This usually means file permissions are wrong on the Pi. SSH requires strict permissions.
  1. SSH into the Pi using a password.
  2. Run chmod 700 ~/.ssh
  3. Run chmod 600 ~/.ssh/authorized_keys
Python ImportError Your script fails with ImportError: No module named ‘some_library’, even though you’re sure you installed it. This is a Python environment mismatch.
  • User vs. Sudo Install: If you installed with pip3 install … but run with sudo python3 …, the sudo environment can’t see user packages.
    Solution: Install the package system-wide with sudo pip3 install <package>.
  • Best Practice: Use Python virtual environments (venv) to isolate project dependencies and avoid these conflicts entirely.
VS Code Can’t Find Interpreter A VS Code popup says “Python interpreter not found” or your code doesn’t get proper IntelliSense. You need to tell VS Code which Python executable to use on the remote machine.
  1. Press Ctrl+Shift+P to open the Command Palette.
  2. Type and select Python: Select Interpreter.
  3. Choose the correct path from the list (e.g., /usr/bin/python3 or the path to your virtual environment’s Python).

Exercises

These exercises will help reinforce the concepts learned in this chapter.

  1. Enhanced Hello World:
    • Objective: Modify the hello.py script to also retrieve and print the Raspberry Pi’s network IP address.
    • Guidance: You will need to research a Python library or a command-line tool that can be called from Python to get the local IP address. The socket library is a good starting point.
    • Verification: When you run the script, it should print the “Hello” message, the architecture, and the IP address you use for SSH.
  2. Interactive LED Control:
    • Objective: Write a Python script that blinks an LED connected to a GPIO pin but allows the user to control the blinking.
    • Guidance: Connect an LED and a current-limiting resistor to a GPIO pin. Write a script that repeatedly prompts the user for input (e.g., “on”, “off”, “exit”) using the input() function. The script should turn the LED on or off based on the command.
    • Verification: Running the script should allow you to type commands in the VS Code terminal to control the physical LED connected to your Pi.
  3. File System Watcher:
    • Objective: Create a Python script that monitors a specific directory on the Raspberry Pi and prints a message whenever a new file is created in it.
    • Guidance: Research the watchdog Python library (pip install watchdog). Write a script that sets up an observer on a new directory (e.g., /home/pi/watched_folder). The script should print the name of any file that is created in that directory.
    • Verification: Run the script. In a second VS Code terminal, use the touch /home/pi/watched_folder/newfile.txt command. The first terminal should immediately print a message about the new file.
  4. Remote Debugging Session:
    • Objective: Use the VS Code debugger to step through the read_sensor.py script.
    • Guidance: Open the read_sensor.py file. Go to the “Run and Debug” panel in VS Code. Click “create a launch.json file” and select “Python”. This will create a default debugging configuration. Place a breakpoint on the line that reads temperature_c = DHT_SENSOR.temperature. Start the debugger by pressing F5.
    • Verification: The script execution should pause at your breakpoint. You can inspect the values of variables, step over lines of code, and see the program’s state, all while it executes on the remote Raspberry Pi.
graph TD
    subgraph "Host Computer (VS Code Client)"
        A(1- User sets breakpoint in<br><b>read_sensor.py</b>) --> B(2- User presses F5<br> Start Debugging);
        B --> C{3- VS Code sends debug<br>command over SSH};
        F -- "UI Update (Paused State,<br>Variable Values)" --> G(7- UI shows script paused<br>at breakpoint. User can<br>inspect vars, step code, etc.);
    end

    subgraph "Raspberry Pi 5 (VS Code Server)"
        C --> D[4- VS Code Server starts<br>Python script with<br>debugpy attached];
        D --> E{5- Script executes until<br>it hits the breakpoint};
        E --> F[6- debugpy pauses execution<br>and sends state to Server];
    end

    style A fill:#1e3a8a,stroke:#1e3a8a,stroke-width:2px,color:#ffffff
    style B fill:#1e3a8a,stroke:#1e3a8a,stroke-width:2px,color:#ffffff
    style C fill:#0d9488,stroke:#0d9488,stroke-width:1px,color:#ffffff
    style D fill:#8b5cf6,stroke:#8b5cf6,stroke-width:1px,color:#ffffff
    style E fill:#ef4444,stroke:#ef4444,stroke-width:1px,color:#ffffff
    style F fill:#0d9488,stroke:#0d9488,stroke-width:1px,color:#ffffff
    style G fill:#10b981,stroke:#10b981,stroke-width:2px,color:#ffffff

Summary

This chapter provided a comprehensive guide to establishing a modern, efficient development workflow for the Raspberry Pi 5 using VS Code’s remote capabilities. By moving beyond basic on-device text editors, you can significantly enhance your productivity and adopt professional software engineering practices for your embedded projects.

  • Remote Development Architecture: You learned that VS Code uses a client-server model, where the UI runs on your host machine while a server on the Pi handles file operations, debugging, and terminal commands.
  • SSH is the Foundation: The Secure Shell (SSH) protocol provides the encrypted, authenticated channel that makes this entire workflow secure and possible. Public-key authentication is the preferred method for secure, password-free access.
  • Seamless Workflow: The integration is nearly transparent. You can open folders, edit code with IntelliSense, use an integrated terminal, and manage source control as if the files were on your local machine.
  • Direct Hardware Access: A key benefit is the ability to write and debug code that directly interacts with the Raspberry Pi’s GPIO pins and connected hardware, closing the loop between software and the physical world.
  • Debugging Power: You can leverage the full power of the VS Code debugger on code running remotely, setting breakpoints and inspecting variables to quickly find and fix issues in your embedded applications.

By mastering this workflow, you are now equipped to tackle more complex embedded Linux projects with the same powerful tools used by software developers worldwide.

Further Reading

  1. Visual Studio Code Docs: Remote Development using SSH: The official and most authoritative guide on the topic.
  2. Raspberry Pi Documentation: SSH (Secure Shell): Official documentation from the Raspberry Pi Foundation on enabling and using SSH.
  3. OpenSSH Project: The official website for the most widely used implementation of the SSH protocol.
  4. DigitalOcean Tutorials: SSH Essentials: A well-written, practical guide to the concepts behind SSH and public-key authentication.
  5. Python socket Module Documentation: For exploring network programming in the exercises.
  6. Adafruit CircuitPython DHT Library: Documentation for the sensor library used in the practical example.
  7. Real Python: An Introduction to Python’s venv: An in-depth tutorial on using virtual environments, a crucial best practice.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top