{"id":3908,"date":"2024-01-28T18:41:16","date_gmt":"2024-01-28T16:41:16","guid":{"rendered":"https:\/\/mummila.net\/nuudelisoppa\/?p=3908"},"modified":"2024-01-28T18:41:16","modified_gmt":"2024-01-28T16:41:16","slug":"notes-as-i-go-my-attempt-to-develop-a-home-assistant-integration-part-1","status":"publish","type":"post","link":"https:\/\/mummila.net\/nuudelisoppa\/2024\/01\/28\/notes-as-i-go-my-attempt-to-develop-a-home-assistant-integration-part-1\/","title":{"rendered":"Notes as I go: my attempt to develop a Home Assistant integration, part 1"},"content":{"rendered":"<p><a href=\"https:\/\/developers.home-assistant.io\/docs\/development_environment\">Set up Development Environment<\/a> says the &#8220;easiest way to get started with development is to use Visual Studio Code with devcontainers&#8221;, but I dislike both those things, so I go with <a href=\"https:\/\/developers.home-assistant.io\/docs\/development_environment#manual-environment\">Manual Environment<\/a> instead.<\/p>\n<p>I&#8217;m not doing core development or even integration PRs for now, so I don&#8217;t need a fork; instead I just <code>git clone --depth 1 https:\/\/github.com\/home-assistant\/core.git<\/code>.<\/p>\n<p>For the <a href=\"https:\/\/developers.home-assistant.io\/docs\/development_environment\/#developing-on-linux\">dependencies<\/a>, <code>sudo apt install python3-pip python3-dev python3-venv autoconf libssl-dev libxml2-dev libxslt1-dev libjpeg-dev libffi-dev libudev-dev zlib1g-dev pkg-config libavformat-dev libavcodec-dev libavdevice-dev libavutil-dev libswscale-dev libswresample-dev libavfilter-dev ffmpeg<\/code><\/p>\n<hr>\n<p>I then try to run <code>script\/setup<\/code>, except that&#8217;s not going to work, because it&#8217;s not in my path; to call it from the <code>core<\/code> root directory using a relative path, it has to be <code>.\/script\/setup<\/code><\/p>\n<p>Some python packages get installed, and in the end it craps out with &#8220;no such option: &#8211;config-settings&#8221;. Apparently Python 3.10, which my Ubuntu 22.04 desktop has, <a href=\"https:\/\/github.com\/home-assistant\/core\/issues\/93584#issuecomment-1665580149\">is no longer supported<\/a>, so I need to redo all of the above on my laptop (which is running Ubuntu 23.10 with Python 3.11).<\/p>\n<hr>\n<p>I then try <code>python3 -m script.scaffold integration<\/code>, which is what I&#8217;m here for, but it fails with &#8220;ModuleNotFoundError: No module named &#8216;attr'&#8221;. Nothing useful comes up on Google, but then I realize I need to <code>source venv\/bin\/activate<\/code> first.<\/p>\n<p>After I answer the scaffolding questions, the script begins building the scaffold, but that also craps out, this time with &#8220;ModuleNotFoundError: No module named &#8216;numpy'&#8221;. <code>pip3 list<\/code> reveals this to be true, so I <code>pip3 install numpy<\/code>.<\/p>\n<p>I restart <code>python3 -m script.scaffold integration<\/code>, which this time only asks the first question, then (correctly) assumes my previous answers to the others are still valid, and finally generates the scaffolding. Doesn&#8217;t tell me where it is, but <code>git status<\/code> shows theres new stuff in <code>homeassistant\/components\/<\/code> and in <code>tests\/components\/<\/code>.<\/p>\n<blockquote><p>&#8220;The next step is to look at the files and deal with all areas marked as TODO.&#8221;<\/p><\/blockquote>\n<hr>\n<p>I rsync the scaffolding back to my desktop and open <code>__init__.py<\/code> in <a href=\"https:\/\/vscodium.com\/\">VSCodium<\/a>. The first TODO says &#8220;List the platforms that you want to support.&#8221; By default it&#8217;s set to <code>LIGHT<\/code>, but my thing is a button, so I go looking for the <a href=\"https:\/\/developers.home-assistant.io\/docs\/creating_platform_index\">platform alternatives<\/a>. &#8220;There are <a href=\"https:\/\/developers.home-assistant.io\/docs\/core\/entity\/light\">lights<\/a>, <a href=\"https:\/\/developers.home-assistant.io\/docs\/core\/entity\/switch\">switches<\/a>, <a href=\"https:\/\/developers.home-assistant.io\/docs\/core\/entity\/cover\">covers<\/a>, <a href=\"https:\/\/developers.home-assistant.io\/docs\/core\/entity\/climate\">climate devices<\/a>, and <a href=\"https:\/\/developers.home-assistant.io\/docs\/core\/entity\">many more<\/a>.&#8221;<\/p>\n<p>The &#8220;many more&#8221; link goes to an entities introduction page, so I assume the side menu listing of Entities is what I have to choose from. As I said, I&#8217;m developing a button, so you&#8217;d think, a <a href=\"https:\/\/developers.home-assistant.io\/docs\/core\/entity\/button\">Button<\/a>, right?<\/p>\n<p>Of course not:<\/p>\n<blockquote><p>&#8220;not suitable for implementing actual physical buttons; the sole purpose of a button entity is to provide a virtual button inside Home Assistant.&#8221;<\/p>\n<p>&#8220;If you want to represent something that can be turned on and off (and thus have an actual state), you should use a switch entity instead.&#8221;<\/p><\/blockquote>\n<p>I don&#8217;t, because mine doesn&#8217;t, so no.<\/p>\n<blockquote><p>&#8220;If you want to integrate a real, physical, stateless button device in Home Assistant, you can do so by firing custom events. The entity button entity isn&#8217;t suitable for these cases.&#8221;<\/p><\/blockquote>\n<p>Well, I&#8217;d like to fire events, but this only seems to draw further away from what &#8220;platform&#8221; I need to use for my integration.<\/p>\n<p>The scaffolding imports Platform from <code>homeassistant.const<\/code>, so I find <a href=\"https:\/\/github.com\/home-assistant\/core\/blob\/9bff039d17bc1c2ebbd8cec6bac6865726a270a9\/homeassistant\/const.py#L31\">the <code>Platform<\/code> enumeration in <code>const.py<\/code><\/a>, but it just lists the same entities as the documentation side panel, so I&#8217;m out of luck.<\/p>\n<p>No, wait, <a href=\"https:\/\/developers.home-assistant.io\/docs\/core\/entity\/event\">Event<\/a> is also listed. So I&#8217;ll go with <code>Platform.EVENT<\/code> for now. That means I&#8217;ll need to &#8220;create a file with the domain name of the integration that you are building a platform for&#8221; \u2014 so in this case, <code>event.py<\/code>.<\/p>\n<p>Actually, <a href=\"https:\/\/developers.home-assistant.io\/docs\/creating_integration_file_structure\">Integration File Structure<\/a> says<\/p>\n<blockquote><p>&#8220;If the integration only offers a platform, you can keep [<code>__init__.py<\/code>] limited to a docstring introducing the integration&#8221;.<\/p><\/blockquote>\n<p>So that means I don&#8217;t need any of the <code>__init__.py<\/code> scaffolding?<\/p>\n<hr>\n<p>Whatever, I&#8217;ll take a look at <a href=\"https:\/\/developers.home-assistant.io\/docs\/creating_integration_manifest\">the manifest<\/a> instead.<\/p>\n<p><a href=\"https:\/\/developers.home-assistant.io\/docs\/creating_integration_manifest#integration-type\">Integration type<\/a> was not set up by the scaffolding script (despite the documentation saying it should be set, and becoming mandatory in the future). I&#8217;m going to pick <code>device<\/code>, which seems unambiguous, for once.<\/p>\n<p><a href=\"https:\/\/developers.home-assistant.io\/docs\/creating_integration_manifest\/#version\">Version<\/a> is mandatory, I&#8217;ll go with 0.1.<\/p>\n<p>My button communicates via Bluetooth, and <a href=\"https:\/\/developers.home-assistant.io\/docs\/bluetooth\/\">Best practices for this<\/a> says I need <code>bluetooth_adapters<\/code> in my <a href=\"https:\/\/developers.home-assistant.io\/docs\/creating_integration_manifest\/#dependencies\"><code>dependencies<\/code><\/a>.<\/p>\n<p>I&#8217;ve used <code>bluetoothctl<\/code> to sniff out what name the device uses, so I&#8217;m also defining a <code>local_name<\/code> matcher in a <a href=\"https:\/\/developers.home-assistant.io\/docs\/creating_integration_manifest\/#bluetooth\">Bluetooth section<\/a>. There&#8217;s also <a href=\"https:\/\/developers.home-assistant.io\/docs\/bluetooth\/#connectable-and-non-connectable-bluetooth-controllers\"><code>connectable<\/code><\/a>, but it defaults to true, which is what it should be for my button.<\/p>\n<p>In the scaffolding, I&#8217;d previously set <a href=\"https:\/\/developers.home-assistant.io\/docs\/creating_integration_manifest\/#iot-class\"><code>iot_class<\/code><\/a> to <code>local_polling<\/code>, and I&#8217;m going to leave it as such, although for now, I&#8217;m treating the button as if didn&#8217;t have any state.<\/p>\n<hr>\n<p>Next, <a href=\"https:\/\/developers.home-assistant.io\/docs\/config_entries_config_flow_handler\"><code>config_flow.py<\/code><\/a>.<\/p>\n<p>&#8220;<a href=\"https:\/\/developers.home-assistant.io\/docs\/config_entries_config_flow_handler#discoverable-integrations-that-require-no-authentication\">Discoverable integrations that require no authentication<\/a>&#8221; looks useful, so I go back to my laptop, <code>source venv\/bin\/activate<\/code> again, then <code>python3 -m script.scaffold config_flow_discovery<\/code>, and finally rsync the new files (now named <code>EXAMPLE_*<\/code>) back again. The only changed file was <code>config_flow.py<\/code>, which is now substantially smaller, defining mostly just <code>_async_has_devices()<\/code>.<\/p>\n<p>The only TODO there is &#8220;Check if there are any devices that can be discovered in the network.&#8221; Spying from <a href=\"https:\/\/github.com\/home-assistant\/core\/blob\/f2100f80c4fa42db0accd6bb93e28d06d03cd052\/homeassistant\/components\/fjaraskupan\/config_flow.py#L13\">one core integration<\/a>, my guess is that <code>_async_has_devices()<\/code> receives a bunch of discovered devices, and should return true only if any of those devices are ones that my integration is actually able to configure.<\/p>\n<p>Why\/whether this isn&#8217;t already handled by the matcher definition in the manifest, I don&#8217;t know; I found at least <a href=\"https:\/\/github.com\/home-assistant\/core\/blob\/f2100f80c4fa42db0accd6bb93e28d06d03cd052\/homeassistant\/components\/dsmr_reader\/config_flow.py#L14\">one integration that always returns true<\/a>, with a comment &#8220;MQTT is set as dependency, so that should be sufficient.&#8221;<\/p>\n<hr>\n<p>I minimally tweak the <a href=\"https:\/\/developers.home-assistant.io\/docs\/core\/entity\/event#firing-events\"><code>MyEvent<\/code> example<\/a> and save it as <code>event.py<\/code>. I think it&#8217;s missing at least imports of <code>EventEntity<\/code> and <code>EventDeviceClass<\/code>. Also, there&#8217;s a tip about being &#8220;sure to deregister any callbacks when the entity is removed from Home Assistant&#8221;, so why isn&#8217;t that incorporated into the example?<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Set up Development Environment says the &#8220;easiest way to get started with development is to use Visual Studio Code with devcontainers&#8221;, but I dislike both those things, so I go with Manual Environment instead. I&#8217;m not doing core development or even integration PRs for now, so I don&#8217;t need a fork; instead I just git [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-3908","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/mummila.net\/nuudelisoppa\/wp-json\/wp\/v2\/posts\/3908","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mummila.net\/nuudelisoppa\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mummila.net\/nuudelisoppa\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mummila.net\/nuudelisoppa\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/mummila.net\/nuudelisoppa\/wp-json\/wp\/v2\/comments?post=3908"}],"version-history":[{"count":32,"href":"https:\/\/mummila.net\/nuudelisoppa\/wp-json\/wp\/v2\/posts\/3908\/revisions"}],"predecessor-version":[{"id":3940,"href":"https:\/\/mummila.net\/nuudelisoppa\/wp-json\/wp\/v2\/posts\/3908\/revisions\/3940"}],"wp:attachment":[{"href":"https:\/\/mummila.net\/nuudelisoppa\/wp-json\/wp\/v2\/media?parent=3908"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mummila.net\/nuudelisoppa\/wp-json\/wp\/v2\/categories?post=3908"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mummila.net\/nuudelisoppa\/wp-json\/wp\/v2\/tags?post=3908"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}