[PoC] DSL for HA config – templating, static type check and more

there are multiple things about Home Assistant configuration I don’t like, so I’ve decided to create a DSL to fix it. Essentially, you write configuration in the DSL, which generates the final configuration.yaml. If you don’t want generate the whole configuration.yaml, you can generate just its parts.

  • HA’s variables are mostly stringly typed – when an entity has a numeric or date value, you need to convert it. When it has a boolean value, it also is string. This leads to some subtle mistakes. The DSL is aware of the types, so it can convert the string entity values to the correct types.
  • There is a limited check of configuration.yaml before you push it to Home Assistant. The DSL takes it further by a static type checking. (Static type checking is performed by scalac, as the DSL is based on Scala.)
  • I had config files and dashboards generated by Jinja2 templates (through Ansible) plus partially jq. This was quite limiting (plus a bit annoying, because HA also uses Jinja2, so I had to use some raw blocks), as it messes with indentation and I have to care about quotes etc. Scala is much more comfortable for me.
  • I didn’t have any autocompletion in configuration.yaml. This is theoretically doable, but I am not aware of any implementation, especially if you want templating. The IDE autocompletion works for this DSL.
  • Modules: In HA config, I’d like to write related parts together. For example, let’s have fridge sensors (regardless they are template-based, binary or numeric), automations and dashboard at one place, not mixed with dehumidifier’s sensors, automations and dashboard. In HA (or with Jinja2), you can achieve something like it by file inclusions, but I still like the DSL more.
  • Module communication and dependencies – each module can produce not only sensors, automations and other objects that are a part of configuration file, but they can also produce some other structures that are input for some other modules. The most noticable example are Highlightables and overview dashboard: Any module can produce a Highlightable (dehumidifier is running, fridge was too humid last 24h, automatic mode is off, …). Then, you can have a module that depends on all those values and produces a dashboard that shows those highlights. This is a real module (see HighlightableDashboard) and I use it as my home dashboard, as it shows any non-standard situation. You might also want to generate notifications for some Highlightables (not all; it would be annoying), see HighlightableNotifications module. The HighlightableNotifications can optionally clear the notifications when they are no longer valid.
  • Concise syntax – like Change(sun).to(SunState.AboveHorizon) or computerLight.turnOff().
  • Various macros – like switchableEntity.turnOnIfOff() or light.brightnessPercent.
  • While the DSL doesn’t cover full potential of HA, you can always use raw elements (RawAction, RawExpr etc.) that are just passed as-is.

Maybe you don’t want to get rid of whole configuration.yaml. Neither I did. With Hagen, you can choose whether to generate some fragments for !include, fragments for inclusion by Jinja2, or whole configuration.yaml and similar files.

Some potential future enhancements:

  • Load entities, attributes and devices from the real HA instance and estimate their types. This means you wouldn’t need any manual declaration of HA’s entities, unless you need adjust the type. It would also allow you to filter some entities based on wildcards.
  • Error message enhancements – for example, when you create a cyclic dependency of modules, the error message is not very helpful.
  • Dashboard support – currently, you can’t define a dashboard without using raw objects. This kind of works, but it is not that much better than using YAML.
  • Optimizations – some expressions are a bit cumbersome and can be simplified. Some parts of expressions are evaluated multiple times due to hacky implementation of Assing operation.
  • Output file definition – I believe this can be more user-friendly.
  • Type system refinement.
  • Reconsider naming of some classes.
  • We check whether the referenced entities are defined (either in DefinedItems or by your own definition). This check currently doesn’t happen for attributes, dashboards and other items.

Substantial limitations:

  • Entity IDs are estimated based on the names. If you know a better way to handle entity names, you are welcome.
  • At the moment, dashboard support is very limited and not well designed. When you want to generate more than one dashboard, you probably out of luck due to a bad design. It is probably not hard to redesign it, but I don’t consider it to be crucial for the first release.

Current status: proof of concept; I wonder about your feedback. Please don’t rely on it too much (yet) unless you are ready to rewrite your code.

URL: GitHub - v6ak/hagen: Home Assistang config GENerator – Scala-based DSL for your home automation

Example configuration: hagen/src/main/scala/com/v6ak/hagen/examples at master · v6ak/hagen · GitHub (you also might want to see the FridgeModule code: hagen/Fridge.scala at 404d5d4140bae4c91cfa9e67d627878fd8615e52 · v6ak/hagen · GitHub )

Note that the example configuration contains just a tiny fraction of my personal configuration. If there is somebody interested, more examples will come.

Build of the example configuration: Add CI build · v6ak/hagen@7e6bf7a · GitHub

I wonder if you find this useful!

1 Like