Tutorial for creating a custom component

I started a tutorial series on creating custom components: https://aarongodfrey.dev/home%20automation/building_a_home_assistant_custom_component_part_1/

Would love to get feedback if any of the content is useful or if I missed anything obvious.

49 Likes

Hi Aaron
This is extremely usefully and I look forward to part 2.
/B

1 Like

Here’s the 2nd part of the tutorial, covering unit testing, continuous integration and pre-commit: https://aarongodfrey.dev/home%20automation/building_a_home_assistant_custom_component_part_2/

5 Likes

Hi,
I tried to implement the pre-commit but keep getting the below error on many of the imports. I do the development in a Dev Container, so I don’t know if that has any influence:

custom_components/meteobridge/__init__.py:6: error: Cannot find implementation
or library stub for module named 'homeassistant.helpers.device_registry' 
[import]
    import homeassistant.helpers.device_registry as dr

I get several of these message, both for Home Assistant imports and for Local imports from const.py file.

I must surely do something wrong, but I am not sure what is it. I have a .pre-commit-config.yaml file in my root directory that looks like this:

repos:
  - repo: https://github.com/asottile/pyupgrade
    rev: v2.3.0
    hooks:
      - id: pyupgrade
        args: [--py37-plus]
  - repo: https://github.com/psf/black
    rev: 19.10b0
    hooks:
      - id: black
        args:
          - --safe
          - --quiet
        files: ^((homeassistant|script|tests)/.+)?[^/]+\.py$
  - repo: https://github.com/codespell-project/codespell
    rev: v1.16.0
    hooks:
      - id: codespell
        args:
          - --ignore-words-list=hass,alot,datas,dof,dur,farenheit,hist,iff,ines,ist,lightsensor,mut,nd,pres,referer,ser,serie,te,technik,ue,uint,visability,wan,wanna,withing
          - --skip="./.*,*.csv,*.json"
          - --quiet-level=2
        exclude_types: [csv, json]
  - repo: https://gitlab.com/pycqa/flake8
    rev: 3.8.1
    hooks:
      - id: flake8
        additional_dependencies:
          - flake8-docstrings==1.5.0
          - pydocstyle==5.0.2
        files: ^(homeassistant|script|tests)/.+\.py$
  - repo: https://github.com/PyCQA/bandit
    rev: 1.6.2
    hooks:
      - id: bandit
        args:
          - --quiet
          - --format=custom
          - --configfile=tests/bandit.yaml
        files: ^(homeassistant|script|tests)/.+\.py$
  - repo: https://github.com/pre-commit/mirrors-isort
    rev: v4.3.21
    hooks:
      - id: isort
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v2.4.0
    hooks:
      - id: check-executables-have-shebangs
        stages: [manual]
      - id: check-json
  - repo: https://github.com/pre-commit/mirrors-mypy
    rev: v0.770
    hooks:
      - id: mypy
        args:
          - --pretty
          - --show-error-codes
          - --show-error-context

And I installed pre-commit as per instructions.

What I would suggest to do in this instance is add an additional argument to the mypy pre-commit check to ignore missing imports.

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 9931e3a..5f58332 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -56,3 +56,4 @@ repos:
           - --pretty
           - --show-error-codes
           - --show-error-context
+          - --ignore-missing-imports

See Running mypy and managing imports - mypy 1.9.0 documentation for more information on the cause of that error.

Thanks, that worked. Now on to reading why it shows up, and see if I can fix it :sweat_smile:

It’s been quite some time, but I finally got around to adding the 3rd part of the tutorial series. This post documents adding a config flow to the custom component. https://aarongodfrey.dev/home%20automation/building_a_home_assistant_custom_component_part_3/

3 Likes

Finally wrapped up this series of posts (only took nearly a year :smile:):

6 Likes

Hi. Thanks for this. How up to date is this tutorial? I just upgraded HA by pulling latest and a custom_component broke because HA seems now to want to look for setup.py and not init.py?

Still working on the latest, 2021.11.5, on my install. Could you provide some more information about what you are seeing in regards to setup.py? As far as I know that isn’t something used in custom components.

1 Like

All good, on traceback the problem was the custom component updates required a “version” parameter and the component I was using was behind in that requirement. I added the “version” parameter to the config and everything sorted itself out. The setup.py function just failed with an uninformative error report, the setup.py function likely was baulking at the missing “version” parameter.

Thank you so much for this wonderful tutorial. It fills quite a few gaps from the official documentation and adds some context where I was lost as a beginner.

Looking at the code of quite a few integrations, I noticed many integrations using a coordinator but I have to admit that I don’t fully understand how that works. Could you maybe point me in the direction of some explanation or - even better - add another chapter to your wonderful tutorial?

All the best and happy new year!

I think the official developer documentation has a pretty good description and example: Fetching Data | Home Assistant Developer Docs

Here’s a snippet from a somewhat related blog post that describes when you would use it (Use CoordinatorEntity when using the DataUpdateCoordinator - Automate The Things) :

Home Assistant’s DataUpdateCoordinator which drastically reduces network calls by fetching all of the data needed by the entities just once. The entities then use the data stored by the coordinator to update their state. The other way to do this is to have each entity (think 10 games on your wish list) and each one individually hits the api to see if it’s on sale. Since all the data comes from the same endpoint we only need to make that call once and the DataUpdateCoordinator helps us manage that.

Thanks for the suggestion, I think it would be a good idea to write up a little post about it since it’s a little bit buried in the documentation.

Thanks for considering. I had found your blog post and that helped me quite a bit. However, while the documentation is great for looking up stuff, your tutorials take this to another level for a beginner like me.

There are also other things that at least to me weren’t obvious, like how to list several entities as part of one device. In the documentation, the terms of devices and entities seem to be mixed at teams - or I just didn’t get it.

I guess a lot of stuff is obvious for the seasoned Python dev and wide-spread convention, but not so obvious if you move over from another language and try to get your head around HA.

Devices vs entities can be confusing at first, but is an HA concept and not anything related to python. Consider a device to be a physical thing (like a sonos speaker) or an api. Each device can have entities, so the Sonos speaker has a media_player entity and a few switches. In order to let HA know each device you must define a unique_id when setting it up in your component. This will ensure all entities related to that device are grouped together.

It gets a little tricky when there is no physical device, like the github tutorial example component. I don’t actually define a device and I’m not entirely sure what should be considered a device (each repository added?). One day I wouldn’t mind revisiting this to see if I can make improvements there for this tutorial.

It’s helpful to browse the core code and checkout how core platinum integrations handle this for one that uses an API and not a physical device. I learned most of what I know by browsing existing code, but I still don’t consider myself to be an expert.

Thank you so much. I browsed your code and quite some other integrations and just finished my first custom integration. It still lacks good tests and probably is not very robust if something goes wrong on the way, but it works and even uses devices.

Your tutorials definitely helped a lot.

1 Like

Awesome, glad to hear it!

Thanks for the tutorial. I started with your tutorial before I even found the official documentation - I probably would have been pretty confused without it! And I’m so glad to see the devcontainer thing, I was dying before I read that, as every time I made a little change I would copy it to Home Assistant and wait 1-2 mins for it to restart!

Anyway, I may be totally missing it in the documentation, but I can’t find anything that talks about how to create a device. Can you give an example of this?

You can find the documentation for devices here:

Essentially, you define a device by setting a number of properties in entities. All entities with the same properties will be bundled as a device. There is no separate class for devices.

Thanks, I guess I had trouble navigating the docs! :smiley: Looks like it’s much easier than I thought!