Developing Home Assistant Core in a VSCode Devcontainer

Amazing thread, thank you so much @MizterB!

Iā€™m trying to return to frontend development after some time, Iā€™ve cloned the frontend repo, opened it in VS Code, then I was asked to reopen it in dev container, after a second Iā€™ve tried following the steps (GitHub - home-assistant/frontend: Frontend for Home Assistant), but the first one gives me an error:

vscode āžœ /workspaces/frontend (fix-selector āœ—) $ script/setup
āž¤ YN0000: ā”Œ Resolution step
āž¤ YN0002: ā”‚ @formatjs/intl-locale@npm:2.4.40 doesn't provide @types/node (p4040e), requested by @formatjs/intl-getcanonicallocales
āž¤ YN0002: ā”‚ @web/dev-server@npm:0.0.24 doesn't provide rollup (p8cfb8), requested by @rollup/plugin-node-resolve
āž¤ YN0002: ā”‚ home-assistant-frontend@workspace:. doesn't provide @egjs/hammerjs (pc1ec5), requested by vis-network
āž¤ YN0002: ā”‚ home-assistant-frontend@workspace:. doesn't provide @types/node (p7c56b), requested by @formatjs/intl-getcanonicallocales
āž¤ YN0002: ā”‚ home-assistant-frontend@workspace:. doesn't provide component-emitter (pe6728), requested by vis-network
āž¤ YN0002: ā”‚ home-assistant-frontend@workspace:. doesn't provide keycharm (p71c12), requested by vis-network
āž¤ YN0002: ā”‚ home-assistant-frontend@workspace:. doesn't provide timsort (pc0292), requested by vis-network
āž¤ YN0002: ā”‚ home-assistant-frontend@workspace:. doesn't provide uuid (p3a84b), requested by vis-data
āž¤ YN0002: ā”‚ home-assistant-frontend@workspace:. doesn't provide uuid (p9d383), requested by vis-network
āž¤ YN0002: ā”‚ home-assistant-frontend@workspace:. doesn't provide vis-util (p2581d), requested by vis-data
āž¤ YN0002: ā”‚ home-assistant-frontend@workspace:. doesn't provide vis-util (p014f8), requested by vis-network
āž¤ YN0000: ā”‚ Some peer dependencies are incorrectly met; run yarn explain peer-requirements <hash> for details, where <hash> is the six-letter p-prefixed code
āž¤ YN0000: ā”” Completed in 0s 834ms
āž¤ YN0000: ā”Œ Fetch step
āž¤ YN0000: ā”” Completed in 15s 792ms
āž¤ YN0000: ā”Œ Link step
āž¤ YN0001: ā”‚ Error: EPERM: operation not permitted, chmod '/workspaces/frontend/node_modules/@babel/core/node_modules/json5/lib/cli.js'
āž¤ YN0000: ā”” Completed in 7m 30s
āž¤ YN0000: Failed with errors in 7m 47s
vscode āžœ /workspaces/frontend (fix-selector āœ—) $

especially this one:
Error: EPERM: operation not permitted, chmod '/workspaces/frontend/node_modules/@babel/core/node_modules/json5/lib/cli.js'

when I try to develop gallery and run cd gallery && script/develop_gallery I get this errors:

./node_modules/.bin/gulp: 1: XSym: not found
./node_modules/.bin/gulp: 2: 0023: not found
./node_modules/.bin/gulp: 3: 687149e66e3e6360895d0ac20c73b31a: not found
./node_modules/.bin/gulp: 4: ../gulp-cli/bin/gulp.js: not found

Iā€™m using Windows 10, VS Code 1.72.0 and Docker 4.7.0

Any ideas what might be wrong?

this is a great post, thanks a lot

I have updated the original post, as many steps (especially for debugging) were extremely out of date.

2 Likes

Hello,
when I debug my custom componentvin dev container if I made a mistake, after fixing it, I have to close VScode and reopen it for my fix to take effect.
Is there a way to make it faster
Thankā€™s

Great post, clear and concise :+1:

I created a mount folder for one of my custom components adding something like:

    // Custom component
    "source=${localEnv:HOME}/dev/ha-netro-watering/custom_components/netro_watering,target=${containerWorkspaceFolder}/config/custom_components/netro_watering,type=bind"

It works as expected - in terms of folder sync - but I cannot ignore it with github in despite the following configuration in .gitignore file

config

Did i miss something ?

Was getting access errors when building the devcontainer using Docker Desktop. Running the container with the privileged flag seemed to solve the issue. Added the following line to devcontainer.json:

  "privileged": true,

When mounting folders in custom_components, I had to make sure the config directory already existed in the repo or vscode would get access errors writing the configuration files.

Also git in wsl seems to block the repo as an unsafe repository in the latest versions. Ive seen mention of using the below json entry to fix this but i couldnt get it to work. I currently have to manually mark it safe using the vscode git tab during build.

"postStartCommand": "git config --global --add safe.directory ${containerWorkspaceFolder}",

Also found a way to add Bluetooth support when running the devcontainer on linux. Using this method i was able to run the devcontainer on my HA production server and SHARE the bluetooth adapter with the existing HA instance. Add the following mounts:

  "mounts": [
    "source=/var/run/dbus,target=/var/run/dbus,type=bind",
    "source=/dev,target=/dev,type=bind"
  ]

I struggle a lot to get it working these days - even though all was great a year ago.

To overcome the git problem, Iā€™ve modified .devcontainer.json with:

  "postCreateCommand": "git config --global --add safe.directory ${containerWorkspaceFolder} && script/setup",

But the mounts wouldnā€™t work. The whole config directory seems to be automatically mounted back to my local clone of core on my Windows machine, but I donā€™t know how to link my custom components into the right place. If I try this in Windows, it only results in .lnk links that donā€™t work in VSCode or the container.

Iā€™m also struggling to get custom_components working. I was able to get the main core devcontainer up and running just fine.

I suspect it might be that Iā€™m running on MacOS, and Docker does some different things there. Every local path I try to mount gets /host_mnt prepended to it, and of course that means it canā€™t find the rest of it. Is /host_mnt is the root of the my git clone of core? Is there no way on MacOS to mount things outside that fs root? Thanks for any help, I am scarcely a VSCode or Docker expert.

1 Like

Iā€™ve started on custom component development for a side project and I could not get the custom component to work without logs saying it couldnā€™t be found when I was directly creating the files in the dev container in vs code. As the same files worked on my production server this was infuriating.

Using the mapping example above to map my custom component git repo to the custom_component directory fixed it, I was nearly out of ideas, this also improves the development workflow considerably.

Thanks for the great article.

1 Like

Hi @MizterB ,
Google pointed me here when searching ā€œhow to develop homeassistant inside a devcontainerā€.

Iā€™m trying to develop a new feature into a custom component. I managed to mount it inside the devcontainerā€¦ so far so good, itā€™s working well !!

My question is: do you have any experience simulating a binary sensor inside the devcontainer?
To test my changes on my custom integration I need to have some binary sensor and toggle the status as I wish to check the behavior of my codeā€¦

thanks in advance!

Go into Settings and create a Toggle helper entity.

1 Like

thanks @MizterB but my problem is that I really need the sensor to be a binary_sensor. Thatā€™s because Iā€™m testing a change to the Alarmo custom integration which works only with binary sensors.
I ended up solving my issue by creating an MQTT binary_sensor that I can flip using MQTT explorer or mosquitto_pub utility from commandlineā€¦

Can you give some hints on using Devcontainer for custom component development only?

For example, do you clone the custom component repo manually inside the HA container (using the terminal) or you do mount the physical folder by using the mounts in the devcontainer.json file? With the latter option, I suspect youā€™re not on Windows, as it slows down the performance?

How do you run the HA task and also keep your git repository synced in VS Code? I would like to only focus on my git repo of the custom component, without the whole HA core fork, if possible. And have access to the linting, of course.

Windows Subsystem for Linux (wsl)

If the code for your custom integration or library is inside of the WSL filesystem, you need to mount that WSL path.

The mount option in the devcontainers.json file uses your windows filesystem.

Use this path in the source section of the mount to get the directory from WSL:
\\\\wsl.localhost\\Ubuntu\\home...
NOTE: The 4 backslahes at the beginning and the 2 backslashes everywhere else ARE REQUIRED. One backslash escapes the other, and windows requires backslashes or it wonā€™t work.

1 Like

Providing some updated steps for June 2024 :slight_smile:

Mostly the same but a few hints to help get others started. With the introduction of uv the process has become much quicker - but make sure you remember to use uv pip install and not pip install within the dev environment now

If you are working on a HACS component, or require external libraries then you should start with pulling those components down to your file system somewhere. Note where as you will need to input below.

To get the DEV container working the simplest way to get thing is to follow steps 1-5 from: Set up development environment | Home Assistant Developer Docs

Once the container is build open devcontainer.json and replace

"postCreateCommand": "script/setup",

with

"postCreateCommand": "git config --global --add safe.directory ${containerWorkspaceFolder} && script/setup",

You then want to add a mounts section to the json. Where doesnt matter, as long as it is at the top level of the json. You do not require all the configurations below, delete the ones you dont need. ${localEnv:HOME} should be your home directory C:\Users\%UserName% but you can also manually enter any path on your file system

"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",
  ],

Rebuild the container
If you dont rebuild none of the above will make any difference.

Once rebuilt you should now be able to see the libraries within your VSCode session in the path you defined under mounts

The next thing that is common is utilising custom libraries. I get this working by adding tasks to the tasks.json located within the .vscode directory

You might also get some info here on how to target remote libraries, but i prefer to map locally Integration manifest | Home Assistant Developer Docs

I use variations of the below and run this Task instead of Run Home Assistant Core

    {
      "label": "Run Home Assistant Core (custom)",
      "type": "shell",
      "command": "uv pip uninstall <libraryname> && uv pip install -e ./config/custom_libraries/<libraryname> && hass -c ./config",
      "group": "test",
      "presentation": {
        "reveal": "always",
        "panel": "new"
      },
      "problemMatcher": [],
      "dependsOn": ["Compile English translations"]
    },
1 Like

What Iā€™m trying to avoid is to download and handle the whole HA core devcontainer to just run and troubleshoot my custom component.
My repo is in ā€œHACS styleā€ with a requirements.txt on the root and then a custom_component/domain subfolder with all the required files of the integration.

I would like, if possible, to have a devcontainer.json file in the same repo, so I can keep my git commits in VS Code but, at the same time, run a task to launch an HA instance with the integration loaded, installing the requirements and displaying its logs only. Iā€™m not interested in the whole HA core debugging. And, of course, the Python linting with Ruff during save.

Do you think this is something possible?

EDIT: Thereā€™s something similar here, but it seems not updated to the latest versions (for example Python is old and the linting tools are not the suggested ones).

Not sure how to achieve what you are requesting.

But I would suggest strongly sticking with their provided devcontainer.json, it really is easier once you have your head around the way they want things to run. Understand the linting can be annoying, but the dev experience is much simpler

As a plus, since moving to uv the container only takes minutes to build.

Yes, but only as long as youā€™re ā€œoperatingā€ on the HA Core development in my opinion.
If youā€™re creating a custom component (integration), if I understand well, you have to:

  • Clone the custom component inside a folder on WSL2
  • Mount that folder as you suggested with the mounts: part of the devcontainer.json
  • After doing that, where do you edit and commit your integration source code? If inside the devcontainer, you wonā€™t have the git commit details, because thatā€™s the Home Assistant Core repo I forked previously. Isnā€™t it? So how can I see the commits of my custom component, create branches, etc.?

Maybe I should open another VS Code window with the custom component git folder as root, but there I wonā€™t have neither the linting nor the task to run Home Assistant to troubleshoot. So should I keep two VS Code windows, one with the HA Core git root (and the mounts) and another non-devcontainer with the custom component sources?

Probably Iā€™m missing something, hence I would like some tips on what might be the best experience (or how others do that). This one doesnā€™t seem like the best, IMHO.

In the linked French blog article, it seems that they create a custom devcontainer that just runs HA and inherit the linting tools and tasks to just run the instance with the custom component loaded. But it is outdatedā€¦

2 VSCode windows can address your concern - just develop and debug in the HA Core one, then open the custom component in another window and do the git management from there.

I understand what you are trying to do - and there are certainly other approaches. If you donā€™t want to piggyback on the HA Core dev container, my suggestion is look at what other popular custom integrations are doing. For example, check out HACS itself (GitHub - hacs/integration: HACS gives you a powerful UI to handle downloads of all your custom needs.).

1 Like