Diving into HA: understanding the Entity type concept

Hi!

I was using OpenHab for some time now but don’t like Java and wanted to switch to something more RAD-like to add custom functionality. Python seems to fit very well into that picture. That’s how I got to Home Assistant, where I currently play around and try to understand the architecture.

The developer documentation is pretty good, but I still don’t get the Component / Entity approach and how to use it for more complex scenarios.

In OpenHab, there is a strict separation between representation of (mostly) hardware elements (Things) and typed interaction elements (Items). A Thing could for example be a smart fish tank controller that allows to add Things of type Switch (r/w) for the light control and Number:temperature (r/o) for the actual measured temperature. Items can be (re-)connected to different Things- if my fish tank controller broke, I could just reconfigure the Fish Light Living Room - Item to point to a smart power plug.

How would that scenario look like in Home Assistant?

As far as I understand you provided different base classes for Entity Components like Switch, Binary Sensor, Light etc.
If I wanted to create a Component for the smart fish tank, that has different sensors and switches (temperature, light control, auto-feeder control) - or maybe even my smart power plug that is as well a temperature sensor - how would that fit into the picture? It’s neither one of those existing Entities, more of a hybrid kind. How would it look like both, from a developer’s perspective and from the configuration one later on?

Additionaly, consider my previous example. If I was using Automation to script the behavior of the fish tank’s light switch, and the hardware broke and would be replaced by a smart plug. Could I easily modify the target, so the automation would still work?

Thanks in advance!

I did my first integration in July 2018. It ran for a while but I did not keep up with updates and now something is broke. I may not be much help, but it was not that long ago I was in your shoes. I keep getting some of them, platform and components backward. I hope I get it right here. :slight_smile:

Keep in mind this is how I look at the terminology.
Platform - This would be the glue for different components. Lets say there is a product X that was made for your fish tank. It comes with a controller that has a light switch and thermometer. You have an app that can turn on and off the light and show you the temperature of the water. Product X has some sort of API that this app uses. You either reverse engineer or it is documented. So you would write a custom platform.

Components - is like a category. Your example would be switches and sensors. These are standard components. I can’t think of a custom one. HA has evolved over time and most every day have been covered.

Entities - This would be a switch (the light on the fish take) and sensor (the thermometer sensor that is gauging the temperatures of the water).

thanks for your answer!

And that’s exactly my current problem. Many devices out there (and this seems to be a trend) just don’t fit in a single category. They are not only a switch, but also a sensor and maybe even more. So how to choose one of them, if none would really fit? There just doesn’t seem to be a one size fits all category, and creating a completely new Entity for all of those devices ("SwitchAndSensor") just doesn’t seem very - well - structured?!

This is in no way critics on the architecture, I just don’t understand how they developers tend to handle this.

I not familiar with what you are trying to integrate to. Give me some examples and how you would “talk” to the device(s). My guess to answer your question might be your platform might use more than one component.

I do in fact have fish tank control systems. They provider sensors e.g. temperature and water metrics as well as a complex light control for the LED lighting. A similar example would be an IoT gateway I’m currently reverse-engineering which provides a light control and different sensors as well as a speaker and microphone.

The Light Entity provides flags, helpers and logic for handling different types of light. So it would be useful to create my devices as just another Platform for Light. But the same applies for Sensor. I can’t choose one over the other when it comes to requirements.

HTTP(S) for the Gateway and GRPC for the fish tank. Of course I could create 2 platforms, one for Sensor and one for Light, but then I would need to maintain 2 connections to the devices, wouldn’t I? Seems like a waste of ressources, especially for limited IoT devices :roll_eyes:.

[Edit]

There is a Smart Plug that allows for measuring the power consumption and temperatue as well. It is integrated in the HA codebase a Platform for Switch. Then, I still don’t get the point if sensors are not using the Sensor Entity - as in the case, it just doesn’t seem to be coherent at all, or am I missing the point?

The platform is what would handle the API and the components are what exposes the devices to HA.

Let me give you my example. I have a Securifi Almond+. It has an API. So I created a class call almond_plus that handles all the API, which in my case is a WebSocket. Today it supports switches and covers.

@thewilli I saw a similar question back in the day on the Almond+ forum. Is that you?

I am going to post the code and where I put it in the custom folders off of the configuration directory. Sometimes an example helps and I don’t think the code is too complicated that you get lost in the details. Let’s try. :slight_smile: Also, this may not be best HA pratices. Once upon a time, I thought it might be useful for others, but I think everyone has abandoned the Almond+, so I just ran it in my HA custom directories. The main reason I wanted to interface with it was HA zwave had issues with barrier devices and could not use my garage door opener without hacking the code after every update. I think that is getting close to being fixed. Now my use case would be to keep the load of communicating to devices off of the HA processor Also now that is it broke, I would like to get it running to understand how to interface with HA. Plus I have some of the Almond Zigbee buttons.

forlder: [configuration]/custom_componets
file: almond_plus.py

https://hastebin.com/afeluhenaq.py

forlder: [configuration]/custom_componets/switches
file: almond_plus.py

https://hastebin.com/sexupupete.py

forlder: [configuration]/custom_componets/cover
file: almond_plus.py

https://hastebin.com/ifaxadozol.py

Keep in mind right now something is broke in the code. It worked in previous versions, but something changed in HA that I did not keep up with and now I need to figure it out :slight_smile:

2 Likes

Thanks for the example, that’ll for sure help :+1:. Will take some time to go through this for me, though.

No, but the product looks really interesting, thanks for mentioning it!

It’s actually the other way around if I read you correctly.

@thewilli
Here’s how I would describe the relation / difference between components and platforms. The component would be the foundation for the support of a group of devices from a vendor. So for example the Philips Hue products (lights, sensors) as a central component that is responsible for handeling the communication with the Hue Bridge.
The lights and sensors are additional parts where device-specific code falls into a category. In this case those would be lights and sensors. Those categories are what is called a platform.

So there is a central component which can be configured (IP of the hub, API token, whatever it takes), and then additionally you either auto-detect the single devices or you have to configure them manually. In both cases you still have the platform code the eventually controls the device.

Now if we take the fishtank that consists of several lights, switches, sensors, maybe even thermostats, there has to be platform code for every type of device. If there is no such thing as a central API, then this would work without a central component. But if they can share credentials, IP of a hub or whatever, then it makes sense the have the component. Just like with Philips Hue, where you only setup the hub (which is a component), and the lights, groups and sensors (which are platforms) are generated automatically.

In the end the switches, lights and sensors of the fishtank will be displayed as separate entities. Entities represent a single unit which can be controlled by the user or by automations. Theoretically there could be a dedicated fish-tank platform which incorporates the functionality of multiple lights and switches. But I personally don’t think this would be integrated into Home Assistant because, in contrast to climate controls etc., they are not that common.

So essentially you have to think about it this way: your fishtank might be a single product, but it actually consits of several different devices (in terms of platforms). You can use a component to make configuration easier and improve performance / efficiency. But you don’t have to do that (e.g. no shared API token, backen server etc.).

1 Like

Thank you for your detailled answer!

yes, I’m fully aware of that :wink: It only serves as a good example of what I am currently trying to understand about the architecture. I’m not going to open a PR for such a system. But if my feature request is accepted, I might be able to distribute it separately :grin:

So let me recap what you and penright said, and what I have learned so far from HA. For the sake of simplicity let’s just say the fish thank is of brand myfishtank and supports light control, switches and different sensors. If I actually wanted to integrate the fish tank into the HA core, and if it would be a commonly used system, I would have the following options to provide support for it:

  1. Create the 3 platforms components/{light,switch,sensor}/myfishtank.py, each convering a particular aspect of the fish tank independent of each other
  2. Like 1., but in addition create component components/myfishtank.py that encapsulates different common aspects from the connection preventing too much redundancy in the 3 platforms and e.g. a shared TCP connection to the fish tank - as well as some central configuration for it like authentication. It would be declared as a dependency to the platforms.
  3. Create a single platform components/sensor/myfishtank.py that - even though it is a sensor platform, provides switch and light functionality as well.
  4. Create a single (entity-) component components/myfishtank.py that covers all, connection and adding of devices.
  5. Create a single (entity-) component components/myfishtank and 3 platforms myfishtank/{sensor,light,switch}.py to it.

Still leaves me confused. Might be the inner developer’s compulsion to have everything ordered and binary decision trees given :wink: So when it comes to the possible solutions, I see the following remarks:

  • 1. 2. I don’t like the idea of having code belonging to the same concern distributed through the code tree. But that is just my opinion. It seemed to me that this would be the preferred way to go, but just look at how the deCONZ sensors were added as platforms to a dedicated component?
  • 3. This is done e.g. for this smart plug + temperature sensor. But doesn’t this question the overall concept of base entites like switch and sensor?
  • 4. Seems a commonly used way to go. But still, doesn’t this violate the concept of basic entity types?
  • 5. This is wrong, or at least does not corresspond to what you think of a platform, right?

What do you say, do you agree on my assumptions? What would be the way to go?

Have you had a chance to read the developer’s documentation? It does a good job of explaining Home Assistant’s architecture and concepts. Here’s the section for Components:

FWIW, I’ve been using another home automation software (Premise) for over a decade. A few months ago I began exploring openHAB. More recently, I’ve started learning how to use Home Assistant.

In practice, I use all three systems and they communicate via MQTT. Here they are, in descending order of responsibility:

  • Premise defines all objects in my home and contains all the logic to control and automate them.
  • Home Assistant provides the UI, a few additional sensors (template sensors) and HomeKit support.
  • OpenHAB provides the UI for free remote access to the system.

Given my long-standing familiarity with Premise, I’m more comfortable with Home Assistant than openHAB. Why? Because of the concept of components. In Premise there are dozens of base classes representing common household devices like switches, dimmers, relays, thermostats, environmental sensors, security sensors, security systems, audio-visual equipment, etc. Home Assistant comes closest to this model with components for lights, switches, covers, sensors, alarm_panels, binary_sensors, weather, etc.

In contrast, openHAB doesn’t model physical devices but distills everything down to a core set of Items: Number, String, Contact, Color, DateTime, Dimmer, Switch, etc. There’s no concept of, for example, a thermostat. To model a thermostat, you just use a combination of items, like Number, String, Switch, Contact, etc , to represent the thermostat’s properties.

In Home Assistant, a climate component is understood to represent a thermostat (or at least a device able to control an HVAC system). The climate component’s platform is what manages the interaction with the physical device (well, there’s actually one more level but let’s skip that for now) .

Here’s documentation for the Ecobee platform for the climate component. An Ecobee thermostat’s feature-set exceeds what is found in the climate component, so the additional functions are represented by other components like binary_sensor, sensor, notify, and weather (see right-hand sidebar in the documentation).

Circling back to your question about the fish tank, if there was a large market of ‘fish tank controllers’, and a large number of fish tank owners using Home Assistant, there would be a case to create a fishtank component with a platform for each brand of fishtank controller. For example (long-standing Home Assistant users can correct me here) some components were created specifically for one brand of gizmo like an irrigation system made by, say, Rachio. People discovered the component is really useful and wanted one for, say, RainBird. Paulus and the developer community decide it’s best if a shiny new component is created called irrigation and platforms are created for each different brand (Rachio, RainBird, Hydrawise, etc). If some new sprinkler system arrives on the market, like RainMachine, one need not touch the irrigation component but simply create a new platform for RainMachine.

What I’ve skipped is all the research needed to ensure the irrigation component properly models the majority of sprinkler systems.

I hope this clarifies a few things.

@123 gave a good altenative explanation.

To answer your question about the possible options:

  1. Yes, that’s a valid solution. I did that for the Llamalab Automate notify platform since it does not require to be a component.
  2. Yes, that’s also a common solution (Philips Hue, Wink, HomeMatic etc.)
  3. No, that would mean you have to add your implementation as a e.g. light, but that light would create switches. That’s not how it should be, even though technically possible. In case of your specific example, the platform does not create multiple entites (as it should be), but insteas includes the additional data as attribues. That’s possible, but it would make more sensor to create an extra entity (platform) that holds a sensor value.
  4. No. If there’s a light, there usually should be a light-platform for it. At least if I understand correctly, this would just be a messy 1-file solution where all platform code is part of the component. Could be done I guess, but probably wouldn’t get accepted.
  5. I don’t see the difference to 2.

Regarding your remarks:

  • 1 + 2: That’s actually very common. It’s object orientated. You could compare platforms to classes in Java, where in the folder light you find all the different device/vendor-specific implementations of a light, but is managed by the base component.
  • 3: As mentioned above, a bad example. Acceptable in that case, but usually you don’t want that.
  • 4: If the required platforms are imported into the component it would work. But splitting it up like in 1 and 2 would be much more clean.
  • 5: Again, I don’t see the difference to 2.

Just to expand on this, I recall rooting around in some platform’s code looking for how it communicates with the physical device. I saw no code to communicate via a serial port or TCP port or whatever. Communication with the bare-metal is handled by external python packages (typically posted on PyPi and imported into HA when needed). That’s the way Paulus wants it and I’ve seen a few recent Pull Requests denied because the proposed platform was handling direct communications with the device (author was asked to separate it out of the platform).

Yes, the bare-metal code always should be outsourced to an external package. If it wasn’t that way, all the bugs would be part of Home Assistant. :smiley:
As an example, the pyhomematic (it’s mine, so taking this as an example as I know what I’m talking about in this case) package used for the HomeMatic component has 4521 lines of code. And I’m sure other external packages are even bigger, maybe even requiring additional packages themselves. If all that was part of the Home Assistant code base the repository would be huge.

Okay, you both, @danielperna84 and @123 helped me a lot, thanks.

The approaches 1. and 2. would be, what I’ve understood from the documentation. Still, if you could answer me that last question, why aren’t just all appropriate sensor, light and switch devices implemented as platforms for those entity components?

Consider e.g.

as opposed to all the many platforms still residing in the switch, sensor` etc. folders being a platform to the base entity components.

Isn’t that a strict contradiction to that platform approach? Why would I need platforms if those components don’t make use of it? Isn’t that applying double standards?

Again, this isn’t critics, I just want to understand the conception behind the decisions and classifications. The way deconz is restructured even feels more natural to me, to have related files in the same directory structure (especially in a git repo), but still - I’m too new to make up my mind about that…

I haven’t been here long enough to answer that definitely. It’s probably due to more than one reason. For example, here’s a recent PR for reorganizing MQTT-related items:
https://github.com/home-assistant/home-assistant/pull/20050

Aooarently there seems to be a change going on. What I have talked above was the standard for a long time. But it seems like this is indeed going to be changed. Have a look at this issue: https://github.com/home-assistant/architecture/issues/124

1 Like

Yes there was a recent PR that allows all platform code to reside in the component folder. But recognize that the platform and component terminology is still completely valid and the concept still operative regardless where the files are residing. The change was a structural one I think down to how components and platforms are packaged together rather than a wholesale shift in how the backend HA model works (in other words, take deCONZ as an example. It still consists of a component (the central logic that communicates with the underlying tech via your API code, and provides integration with HA’s config entries, for example) and platform code (the light, sensors, binary sensors, etc - that’s still platform code).

Coming from OpenHab I think of the structural differences as follows:

  1. OpenHab “Things” - there isn’t a direct correlation in HA, the closest is now the Device Registry which links all of the entities of a given physical device together for representation in the front end.
  2. OH “Channels” - OH Things can have Channels which represent their features (eg a Hue Light Thing may have both brightness and colour channels, which can be assigned to items for user control). Again, not really a direct correlation in HA, except…
  3. OH “Items” - think of HA’s Entities as an amalgamation of Channels and Items, except the end user doesn’t control how they are linked, you as the backend developer of the component/platform does. To go back to the Hue Light example: a physical Hue light bulb is represented in HA as a light entity that provides the user with control over both brightness and colour, and the backend code interfaces with Hue’s API to allow the user to interact with both attributes. Another example of the developer’s choice/preference might be a device that has a battery, eg a motion sensor - some components will create a binary_sensor entity that has a device state attribute of battery_level, so both the motion sensing and battery status are present in that one entity, but you could also choose to implement the motion sensing as a binary_sensor and have the battery attribute appear as a sensor entity.

I’m not sure how OH’s backend code works (I never got that far) but in HA your backend code (both the underlying python library you will create for interacting with your particular device’s API) and the HA code itself is responsible for making the choices about how the information from the API is modeled in HA. In that way the user by default has less control over how a particular device is represented in HA than in OpenHab, but hopefully with the advantage of a more standardized approach to that device’s representation.

2 Likes

@marthocoo
That totally makes sense to me, thanks! The only question that arises from this approach (and maybe I’m totally wrong with this, and it’s just out of my lack of experience and inner compulsion to keep everything sorted and categorized): Doesn’t this lead to a patchy configuration, where for a single kind of device (e.g. a sensor) you’d sometime need a sensor platform and sometimes just a component - maybe even both? Considering OpenHAB as a reference we’re both familiar with, a Thing and an Item might require different configurational arguments, but are always defined in the same, sound way. So if I wanted to add devices of brand Foo, I would only need to lookup those arguments, instead of the way they’re defined. Am I misssing a point?

I suppose you’re right that this is a fragmented approach, but does allow the developer to have flexibility. You could have:

  1. A component with no platform code (when no entities are required, for example if the desire was to just listen to a websocket and fire an event on the Home Assistant event bus when a certain message was received).
  2. A platform with no component code (when your underlying tech only creates one type of entity - for example, a MyQ garage door opener is only modelled in HA as a “cover” platform, so you’ll only find the code related to MyQ’s integration in HA in components/cover/myq.py; or, for when you have multiple platforms but theres no need or ability to tie the logic that interacts with the underlying technology together).
  3. A component with platform code (when your underlying tech has different types of devices that will be modelled in HA as different types of entities, and there is a need or desire to interact with the underlying tech in a uniform way; many technologies that have multiple different types of device are modelled in HA like this - the component interacts with the underlying technology in a uniform way and distributes updates to the (e.g. light, switch, sensor, binary_sensor, cover) platforms - an example is deconz.)

I think you may be. This is the point of the entity abstraction and the platform code for your devices. If you create a component with a light platform, or you integrate a tech that only has light devices and so only create platform code of the light component, you end up with light entities that are presented to the user in a completely uniform way. Take a look at components/light/init.py and you’ll see the Light class which is itself subclasses the Entity class. There are a standard set of python properties that define the data that an entity presents and so interaction with it is standardized. The Light class extends this concept with other properties relevant to lights and methods (e.g. async_turn_on and async_turn_off) that standardize how those actions are taken by HA. All light entities in HA are turned on the same way, from a code perspective: when you toggle on in the front end, HA calls async_turn_on().

Another potential point of confusion coming from OpenHAB is that the item concept doesn’t translate directly to HA either. In OH items are purely arbitrary in that you can define any type of item and link it to any Thing’s channel to represent the information from that channel as you wish.

In HA entities are not so arbitrarily flexible. If you, as the user, would like to create a particular type of entity to model data from another entity (remembering that the primary way that entities are defined and therefore represented in the HA front end is the choice of the developer, not user), HA provides several different built in options for achieveing this - the template platforms are one way - for example, a user can define a template_sensor to take an attribute or state of one or multiple sensors and combine them together; there are also statistics sensors for this purpose (eg the min_max sensor). Each of these types of sensors has configuration directives to add to configuration.yaml that allow the user to define data for consumption by the sensor in a standardized way (and, spoiler alert, these types of sensor have configuration directives in configuration.yaml because they themselves are platforms of the sensor component, except instead of connecting to an underlying external tech, they take data from HA itself and model it in useful ways).

I think the HA project as a whole is more fragmented than the OH project, but what it gives up in terms of becoming fragmented it gains in flexibility for the user/developer. This is also a reflection of the age and relative maturity of the projects - OH for example has a stable release that only happens on a lengthier cycle that the HA project doesn’t have - releases for HA are much more frequent to 1) rapidly improve the Core code base and 2) to allow new technologies to be rapidly integrated into the project, since that’s really what it’s all about.

Eventually, HA may evolve to a model where there is a stable core with a stable set of supported technologies that gets released infrequently, and a type of plugin system for new components/platforms to be rapidly integrated by developers (with the long term view of having them eventually integrated into a stable release).

But the project isn’t there yet, it’s still very much an alphaish-beta project, with frequent code additions (and I mean core, central features) and frequently, breaking changes (and by that I mean intentionally breaking things, leaving aside the fact that unintentional bugs also break things). OH has been around longer and has “found it’s legs” on many of the core things that HA’s core devs still are developing and adding.