New Developer: questions about adding a switch to an existing integration

TL;DR: First attempt at modifying an integration, and I have questions :wink:

  1. What’s the preferred way to access the state of an entity from another of the same device’s entities? e.g. a CoverEntity being able to access the state of a SwitchEntity that belongs to the same parent Device
  2. How do you preserve the state of a SwitchEntity across Home Assistant restarts?

More Details/Context:
I want to add the capability to chose one of two modes when opening/closing my blinds. They are normal (fast, loud), and morning (slow, quiet). This is the soma integration if you’re familar, and the current implementation defaults to normal (fast, loud) for all Home-Assistant-initiated operations. This has caused the other members of my household to invoke veto/product-return power if I don’t find a way to make them quieter.

Implementation:
I chose to add a SwitchEntity to the existing integration to expose the option to the user to pick an operation mode (normal/morning). I considered other options (cover entity attribute, parameter to service calls only), but I want the users in my home to be able to decide (from the UI) which mode to use at the time they initiate a request.

Detailed Questions:

  1. How do you preserve the state of a SwitchEntity across Home Assistant restarts? The switch doesn’t correspond to anything on the hardware device, so there’s not anything external that gets polled upon HA restart. I’ve implemented the constructor for the new SwitchEntity and called the parent constructors, too. I’ve implented the turn_on(), turn_off(), and is_on() methods and defined the name property, as described in the example docs. Any other things I need to do? As of now, the new switch always returns to off when I retart the HA container.

  2. What’s the preferred way to access the state of an entity from another of the same device’s entities? The existing device already has a cover entity and a battery sensor entity. I’m adding a switch entity. I’d like for the cover entity to be able to access the new switch entity’s state so it can use this state data in open_cover() and close_cover() to invoke normal/morning mode. Right now, I’ve implemented it by finding the switch entity in the hass object by its name, but it’s hacky, and if the user changes the entity name, that would break it.

I’m assuming something like this is a bad idea when inside the open_cover() method for the CoverEntity…

switch_entity = f"switch.{self.device['name']} Morning Mode".lower().replace(" ", "_")
self.hass.states.is_state(switch_entity, STATE_ON)

That creates something like (switch_entity == switch.bedroom_morning_mode). It works as a quick hack, but I’m guessing that I should be able to find the switch somewhere under the self.device object for a more reliable and PR-able solution. I don’t see it, though. Can someone point me in the right direction? … or is the answer “everything should be self-contained, so don’t try to do inter-entity communication unless you’re a user writing automations”?

1 Like

Entities should be presentation layer, they are not expected to communicate internally.

There should be a storage layer inside integration which holds current state and settings, your switch should update this layer and aforementioned cover should behave according to settings.

So, stop thinking about communicating between entities, rather have a data layer and let your entities read from and write into it.

Thanks, @anon63427907!

Yeah, I was thinking more of how a user implements things with automations, not how you can do things within integration code.

I see how the setup methods instantiate the different entity objects (with their own protected data as in the example docs), but I don’t see how/where a device-level data layer would be instantiated. Know of any other integrations that use a data layer so I could look at an example?

1- data update coordinator is responsible to holding the state of all entities.
2- entities have access to update coordinator and reading their interested attributes from its internal state
3- entities can modify update coordinator’s internal state

My own custom integration: GitHub - fuatakgun/eufy_security: Home Assistant integration to manage Eufy Security devices as cameras, home base stations, doorbells, motion and contact sensors.

FYI: I am not claiming to follow all best practices