Developing Home Assistant Core in a VSCode Devcontainer

Developing Home Assistant Core in a VSCode DevContainer

While the official developer documentation makes some references to VSCode devcontainers, there does not appear to be a comprehensive guide for setting it up to develop and debug HA core. I started documenting the steps that worked well for me, then realized it would be best to share back with the community in a place where it wouldn’t get lost.

I’m suspect that some (much?) of this isn’t best practice or 100% accurate. But I hope that by sharing this, it will encourage others to contribute information about their workflows and we can continue to grow the developer community.

Developing Home Assistant Core in a VSCode Devcontainer

Setting Up the Local Repository

  1. Ensure that git installed on your development wokstation
  2. Visit the Home Assistant Core repository and click Fork.
  3. Open a terminal and set up your local repository
git clone https://github.com/YOUR_GIT_USERNAME/core.git
cd core
git remote add upstream https://github.com/home-assistant/core.git
  1. Create a new feature branch that tracks the dev branch in
git checkout -b my_dev_branch --track origin/dev
  1. Open the local repository in VSCode

Configuring HomeAssistant

By default, the devcontainer will create the config directory inside the container if it doesn’t already exist. Optionally, you can override this by bind mounting a config directory from your local filesystem, which can be helpful for long-term persistence or swapping in/out different configurations to support development.

To do this, include a list of mounts inside /.devcontainer/devcontainer.json:

  "mounts": [
    // Custom configuration directory
    "source=${localEnv:HOME}/path/to/config,target=${containerWorkspaceFolder}/config,type=bind",
  ]

If these mounts are modified, then the devcontainer must to be rebuilt

  • Press F1, and enter Remote-Containers: Rebuild Container

See https://code.visualstudio.com/docs/remote/containers-advanced#_adding-another-local-file-mount for more information.

Running HomeAssistant

  1. Open the the local repository in VSCode

  2. Accept the prompt to “Reopen in Container”

  3. Start HA in the container via the menu options:

    Terminal | Run Task... | Preview

  4. Open HA in a web browser at http://localhost:8123

Keeping Code Up To Date

This is adapted from https://developers.home-assistant.io/docs/development_catching_up

The following commands will keep your local feature branch up-to-date with HomeAssistant’s official dev branch.
Reminder: upstream is the official HA repository, origin is your remote repository that was forked from it

  • Switch to a local feature branch
  • Pull the latest commits from a HA’s upstream/dev branch
  • Replay the upstream commits to the local branch, then re-apply local changes
  • Push the combined commits back to the forked repository on GitHub
git checkout my_dev_branch
git fetch upstream dev
git rebase upstream/dev
git push origin --force

Debugging HomeAssistant

Set up HomeAssistant’s Remote Python Debugger

Add the following to /config/configuration.yaml:

debugpy:
  start: true
  wait: true

See https://www.home-assistant.io/integrations/debugpy/ for more information.

Configure the VSCode Debugger

Insert the following debug configurations into /.vscode/launch.json:

{
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            // Example of attaching to local devcontainer
            "name": "HomeAssistant: Attach to Local Devcontainer",
            "type": "python",
            "request": "attach",
            "port": 5678,
            "host": "localhost",
            "pathMappings": [
                {
                    "localRoot": "${workspaceFolder}",
                    "remoteRoot": "/workspaces/${workspaceFolderBasename}"
                }
            ],
        },
        {
            // For attaching to a remote Production server
            // Update host as needed
            // HA code is located at /usr/src/homeassistant in a Supervised install
            "name": "HomeAssistant: Attach to Remote",
            "type": "python",
            "request": "attach",
            "port": 5678,
            "host": "homeassistant.local",
            "pathMappings": [
                {
                    "localRoot": "${workspaceFolder}",
                    "remoteRoot": "/usr/src/homeassistant"
                }
            ],
        }
    ]
}

Start Debugging

  1. Ensure that the HA devcontainer is running (Terminal | Run Task... | Preview)
  2. Switch to the VSCode Debugger view
  3. Select the appropriate debug configuration from the dropdown
  4. Start the debugger

Debugging Custom Components and Libraries

When developing custom components or libraries that exist in other local respoitories on your development machine, the easiest way to incorporate these into HomeAssistant is to bind mount those repositories into HA’s config directory.

To do this, include a list of mounts inside /.devcontainer/devcontainer.json, similar to this example:

  "mounts": [
    // Custom configuration directory
    "source=${localEnv:HOME}/path/to/config,target=${containerWorkspaceFolder}/config,type=bind",
    // Custom component
    "source=${localEnv:HOME}/path/to/custom_repo/custom_components/component_name,target=${containerWorkspaceFolder}/config/custom_components/component_name,type=bind",
    // Custom library
    "source=${localEnv:HOME}/path/to/custom_repo/custom_libraries/library_name,target=${containerWorkspaceFolder}/config/custom_libraries/library_name,type=bind",
  ]

Add more bind mounts as needed for your use case.

If these mounts are modified, then the devcontainer must to be rebuilt

  • Press F1, and enter Remote-Containers: Rebuild Container

Custom Components

Custom components are mounted in the container under config/custom_components, which is a HomeAssistant standard.

Custom Libraries

Custom libraries are mounted under config/custom_libraries. Note that custom_libraries is a personal naming preference, and is not prescribed in the HomeAssistant docs.

In order to develop a custom library, HA needs to be started with a custom variant of the Preview task, which invokes the --skip-pip argument as described here: https://developers.home-assistant.io/docs/api_lib_index

Add the following to .vscode/tasks.json

    // This task should be used when developing in custom_libraries.
    // Any time the container is rebuilt, first run the regular Preview task,
    // which installs all HA dependencies.  Then, swap in the custom_libraries
    // by running the following in the terminal:
    // `pip uninstall library_name
    // `pip install -e ./config/custom_libraries/library_name`
    {
      "label": "Preview with Custom Libraries",
      "type": "shell",
      "command": "hass --skip-pip -c ./config",
      "group": {
        "kind": "test",
        "isDefault": true
      },
      "presentation": {
        "reveal": "always",
        "panel": "new"
      },
      "problemMatcher": []
    },

Before starting HA with this modified Preview task, run the normal Preview task, which will install any libraries the via the normal HA boot process.

Terminal | Run Task... | Preview

If overriding a built-in library, go to the terminal and uninstall the built-in one:

pip uninstall library_name

To then enable a custom library, have pip install it from the filesystem. This should be accessible via the bind mount(s) created above.

pip install -e ./config/custom_libraries/library_name

Finally, to ensure that the custom library is used and not automatically overwritten by HomeAssistant at the next boot, stop the ‘normal’ Preview.

Terminal | Terminate Task... then select Preview

Now, to start HomeAssistant with custom libraries enabled, start the custom preview command created above:

Terminal | Run Task... | Preview with Custom Libraries

11 Likes

Useful tips!

One thing I haven’t figured out yet: How do you customize devcontainer.json to specify mounts, without having to ignore this file for git?

Not sure I completely understand…devcontainer.json is not ignored by default (best I can tell). Regardless, if it is ignored, you should be able to modify the .gitignore file to your preference.

I want to edit devcontainer.json to include mount points.
But I do not want to push those changes to GitHub (so I would gitignore).
However, I would like to pull any changes to devcontainer.json that come from upstream (which will not happen if I gitignore).

If you want hide/externalize the mount configuration outside of devcontainer.json, I think the solution might be to define mount points using environment variables in an .env file, which are documented at https://code.visualstudio.com/docs/remote/containers-advanced#_adding-environment-variables.

If you find a working solution, please report back, and we can improve the documentation.

When doing this on windows is the code in the windows partition or in WSL?

Thanks, you can help me please, config frondEnd enviroment ?

Unfortunately, I haven’t done any frontend development against the dev container. Hopefully someone else can contribute additional inputs.