Switch button

Making a custom comonent.
How can i control what icon or switch type is used?
image
Below is what I want it to loo like.
image

"""Platform for switch integration."""

from __future__ import annotations
from datetime import datetime
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from homeassistant.components.switch import SwitchEntity

from homeassistant.const import CONF_NAME
from homeassistant.core import callback
from homeassistant.helpers.typing import HomeAssistantType
import homeassistant.util.dt as dt_util

from .const import (
    ATTR_MANUFACTURER,
    DOMAIN,
    SWITCH_TYPES,
    AmberModbusSwitchEntityDescription,
)

#from .hub import *

async def async_setup_entry(hass, entry, async_add_entities):
    hub_name = entry.data[CONF_NAME]
    hub = hass.data[DOMAIN][hub_name]["hub"]

    device_info = {
        "identifiers": {(DOMAIN, hub_name)},
        "name": hub_name,
        "manufacturer": ATTR_MANUFACTURER,
    }

    entities = []
    for switch_description in SWITCH_TYPES.values():
        switch = AmberSwitch(
            hub_name,
            hub,
            device_info,
            switch_description,
        )
        entities.append(switch)

    async_add_entities(entities)
    return True

class AmberSwitch(CoordinatorEntity, SwitchEntity):
    """Representation of a Amber Modbus switch."""

    def __init__(
        self,
        platform_name: str,
        hub: AmberModbusHub,
        device_info,
        description: AmberModbusSwitchEntity,
    ):
        """Initialize the switch."""
        self._platform_name = platform_name
        self._attr_device_info = device_info
        self.entity_description: AmberModbusSwitchEntity = description
        self._hub = hub
        self._state = None

        super().__init__(coordinator=hub)
        
    @property
    def name(self):
        """Return the name."""
        return f"{self._platform_name} {self.entity_description.name}"

    @property
    def unique_id(self) -> Optional[str]:
        return f"{self._platform_name}_{self.entity_description.key}"

    @property
    def is_on(self) -> bool | None:
        """Return the state."""

        return (
            self.coordinator.data[self.entity_description.key]
            if self.entity_description.key in self.coordinator.data
            else None
        )              
  
    async def async_turn_on(self, **kwargs):
        """Send the on command."""
        self._hub.write_registers(92, 1)
  
        self.async_write_ha_state()

    async def async_turn_off(self, **kwargs):
        """Send the off command."""
        self._hub.write_registers(92, 0)

        self.async_write_ha_state()  

The above code renders the correct switch and also updates the state.
the only problem I have with this is that when I switch on, a few moments later the switch goes back to off and when the Modbus update comes (20sec later) the correct (on) state is set again.
Obvious this is unwanted.

I know that the address and value are hard coded, need to figure out how to get the used modbus address.

The 2 flash buttons typically appear when your entity has assumed_state set to True.

I don’t think you can change the icons of those buttons.

With the code above, it renders a button shown in the second image.
It also updates the switch status within Home Assistant when controlled outside of Home Assistant.

The only thing is, that when I flip the switch to on in HA it goes on, after a few seconds goes off again. "
And when the modbus updates comes the switch goes on again.
(because the is_on function updates)
I don’t understand why this is happening.

Ah, I misunderstood the question.

Yeah, switches behave a bit wonky with slow updates.

When you switch it on in the frontend then at that point it basically shows the future state. After a few seconds the frontend falls back to showing the current state. When that current state is not updated yet by the integration it causes the 'flipflop" of the switch.

There was a whole architecture discussion on it Unify optimistic states for entities at core level to prevent UI "flipflops" and Voice Assistant errors · home-assistant/architecture · Discussion #740 · GitHub which unfortunately seems to have stalled.

I think the only way around it is to cheat and just assume the update will succeed and update the internal state already. Then next update will fix it in case it failed from some reason.

Do you know any code example I can look at this cheating part?

Sorry, I don’t have real examples.

You probably have the state of the device stored somewhere in your integration so you can return the state from your entities.

Lets take a switch as example. When the turn_on method is called you would next to sending the command to the device also already set the state. And then same for turn_off

So something like below. Lets assume self.state.on exists and gets updated when the device sends an update. Note that his probably does not compile, it is more to give an idea of how it could work.

class MySwitch(SwitchEntity):
... more stuff ...
@property
def is_on(self):
    return self.state.on

def turn_on(self):
    self.state.on = True  # Update state, so assuming the command will succeed
    send_the_command_to_device()

    # might need to call this to let HA know state was updated, check if really needed
    self.schedule_update_ha_state()

Problem with this solution is that it renders the switch like this:
image

Returns no state at all.

Thank you for your time, for trying to help me.
I give up.