Remote Python Debugger


The remote Python debugger integration allows you to use the Visual Studio Code Python debug tooling with a remote Home Assistant instance.

It uses Microsoft’s debugpy library which is the successor of ptvsd, and the default library used by Visual Studio Code.

This is useful in testing changes on a local development install, or connecting to a production server to debug issues. It is possible to load the integration without the activating the debugger, but injecting it with a service call. This is particularly useful on a developer’ production system as it does not impact performance when not injected.

Configuration

To enable the remote Python debugger integration add the following to your configuration.yaml file:

# Example configuration.yaml entry
debugpy:

By default this will listen on all local interfaces, on port 5678, will not wait for a connection and start when Home Assistant starts.

Configuration Variables

host string (Optional)

The local interface to listen on.

Default:

0.0.0.0 (all interfaces).

port integer (Optional, default: 5678)

Port to listen on.

start boolean (Optional, default: true)

If true, the debugger will be injected on start of Home Assistant. Set it to false to inject it on demand using the debugpy.start service call.

wait boolean (Optional, default: false)

If true, wait for the debugger to connect before starting up Home Assistant. This option is ignore when start is set to false.

Security

Ensure if this is a public-facing server, that the port is secured. Anyone who is able to access the debugger port can execute arbitrary code on the Home Assistant server, which is very unsafe.

If the Home Assistant server is behind your firewall with only the http(s) port exposed, then this is safe from outside connections.

Performance and Memory Use

Using the debugger (even when not attached), increases memory usage and decreases performance. It is not recommended to configure the debugger on a persistent (production) server, unless absolutely required.

Alternatively, the integration can be loaded by setting the start option to false. This will prevent the debugger from being injected, instead, it will be injected on-demand by calling the debugpy.start service.

Waiting at startup

If you want to debug something in the start-up sequence, configure the integration to wait for a connection first:

# Example configuration.yaml entry
debugpy:
  start: true
  wait: true

The debugger is loaded quite early on in the boot-up sequence, before any other integrations. This will allow you to set breakpoints in async_setup or similar and debug the loading of the integration.

Alternate host and port

You can also listen on a different server address or port:

# Example configuration.yaml entry
debugpy:
  host: localhost
  port: 6789

This is useful for multi-homed servers, or for localhost only access

Service debugpy.start

When the start option of the integration has been set to false, one can use the debugpy.start service call to inject and start the remote Python debugger at runtime.

Please note: There is no way to stop it once started, this would require a restart of Home Assistant.

Example Visual Studio Code configuration

This can be copied into your launch.json in the .vscode subdirectory in your Visual Studio Code project to connect to the debugger.

{
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            // Example of attaching to local debug server
            "name": "Python: Attach Local",
            "type": "python",
            "request": "attach",
            "port": 5678,
            "host": "localhost",
            "pathMappings": [
                {
                    "localRoot": "${workspaceFolder}",
                    "remoteRoot": "."
                }
            ],
        },
        {
            // Example of attaching to my production server
            "name": "Python: Attach Remote",
            "type": "python",
            "request": "attach",
            "port": 5678,
            "host": "homeassistant.local",
            "pathMappings": [
                {
                    "localRoot": "${workspaceFolder}",
                    "remoteRoot": "/usr/src/homeassistant"
                }
            ],
        }
    ]
}