How can I make the rise and fall buttons of the Cover component always available?

Tags: #<Tag:0x00007f73963072b0>
    """

Support for covers which integrate with other components.
For more details about this platform, please refer to the documentation at


“”"
import logging

import voluptuous as vol

from homeassistant.core import callback
from homeassistant.components.cover import (
ENTITY_ID_FORMAT, CoverDevice, PLATFORM_SCHEMA,
SUPPORT_OPEN_TILT, SUPPORT_CLOSE_TILT, SUPPORT_STOP_TILT,
SUPPORT_SET_TILT_POSITION, SUPPORT_OPEN, SUPPORT_CLOSE, SUPPORT_STOP,
SUPPORT_SET_POSITION, ATTR_POSITION, ATTR_TILT_POSITION)
from homeassistant.const import (
CONF_FRIENDLY_NAME, CONF_ENTITY_ID,
EVENT_HOMEASSISTANT_START, MATCH_ALL,
CONF_VALUE_TEMPLATE, CONF_ICON_TEMPLATE,
CONF_ENTITY_PICTURE_TEMPLATE, CONF_OPTIMISTIC,
STATE_OPEN, STATE_CLOSED)
from homeassistant.exceptions import TemplateError
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import async_generate_entity_id
from homeassistant.helpers.event import async_track_state_change
from homeassistant.helpers.script import Script

_LOGGER = logging.getLogger(name)
_VALID_STATES = [STATE_OPEN, STATE_CLOSED, ‘true’, ‘false’]

CONF_COVERS = ‘covers’

CONF_POSITION_TEMPLATE = ‘position_template’
CONF_TILT_TEMPLATE = ‘tilt_template’
OPEN_ACTION = ‘open_cover’
CLOSE_ACTION = ‘close_cover’
STOP_ACTION = ‘stop_cover’
POSITION_ACTION = ‘set_cover_position’
TILT_ACTION = ‘set_cover_tilt_position’
CONF_TILT_OPTIMISTIC = ‘tilt_optimistic’

CONF_VALUE_OR_POSITION_TEMPLATE = ‘value_or_position’
CONF_OPEN_OR_CLOSE = ‘open_or_close’

TILT_FEATURES = (SUPPORT_OPEN_TILT | SUPPORT_CLOSE_TILT | SUPPORT_STOP_TILT |
SUPPORT_SET_TILT_POSITION)

COVER_SCHEMA = vol.Schema({
vol.Inclusive(OPEN_ACTION, CONF_OPEN_OR_CLOSE): cv.SCRIPT_SCHEMA,
vol.Inclusive(CLOSE_ACTION, CONF_OPEN_OR_CLOSE): cv.SCRIPT_SCHEMA,
vol.Optional(STOP_ACTION): cv.SCRIPT_SCHEMA,
vol.Exclusive(CONF_POSITION_TEMPLATE,
CONF_VALUE_OR_POSITION_TEMPLATE): cv.template,
vol.Exclusive(CONF_VALUE_TEMPLATE,
CONF_VALUE_OR_POSITION_TEMPLATE): cv.template,
vol.Optional(CONF_POSITION_TEMPLATE): cv.template,
vol.Optional(CONF_TILT_TEMPLATE): cv.template,
vol.Optional(CONF_ICON_TEMPLATE): cv.template,
vol.Optional(CONF_ENTITY_PICTURE_TEMPLATE): cv.template,
vol.Optional(CONF_OPTIMISTIC): cv.boolean,
vol.Optional(CONF_TILT_OPTIMISTIC): cv.boolean,
vol.Optional(POSITION_ACTION): cv.SCRIPT_SCHEMA,
vol.Optional(TILT_ACTION): cv.SCRIPT_SCHEMA,
vol.Optional(CONF_FRIENDLY_NAME): cv.string,
vol.Optional(CONF_ENTITY_ID): cv.entity_ids
})

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_COVERS): vol.Schema({cv.slug: COVER_SCHEMA}),
})

async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
“”“Set up the Template cover.”""
covers = []

for device, device_config in config[CONF_COVERS].items():
    friendly_name = device_config.get(CONF_FRIENDLY_NAME, device)
    state_template = device_config.get(CONF_VALUE_TEMPLATE)
    position_template = device_config.get(CONF_POSITION_TEMPLATE)
    tilt_template = device_config.get(CONF_TILT_TEMPLATE)
    icon_template = device_config.get(CONF_ICON_TEMPLATE)
    entity_picture_template = device_config.get(
        CONF_ENTITY_PICTURE_TEMPLATE)
    open_action = device_config.get(OPEN_ACTION)
    close_action = device_config.get(CLOSE_ACTION)
    stop_action = device_config.get(STOP_ACTION)
    position_action = device_config.get(POSITION_ACTION)
    tilt_action = device_config.get(TILT_ACTION)
    optimistic = device_config.get(CONF_OPTIMISTIC)
    tilt_optimistic = device_config.get(CONF_TILT_OPTIMISTIC)

    if position_action is None and open_action is None:
        _LOGGER.error('Must specify at least one of %s' or '%s',
                      OPEN_ACTION, POSITION_ACTION)
        continue
    template_entity_ids = set()
    if state_template is not None:
        temp_ids = state_template.extract_entities()
        if str(temp_ids) != MATCH_ALL:
            template_entity_ids |= set(temp_ids)

    if position_template is not None:
        temp_ids = position_template.extract_entities()
        if str(temp_ids) != MATCH_ALL:
            template_entity_ids |= set(temp_ids)

    if tilt_template is not None:
        temp_ids = tilt_template.extract_entities()
        if str(temp_ids) != MATCH_ALL:
            template_entity_ids |= set(temp_ids)

    if icon_template is not None:
        temp_ids = icon_template.extract_entities()
        if str(temp_ids) != MATCH_ALL:
            template_entity_ids |= set(temp_ids)

    if entity_picture_template is not None:
        temp_ids = entity_picture_template.extract_entities()
        if str(temp_ids) != MATCH_ALL:
            template_entity_ids |= set(temp_ids)

    if not template_entity_ids:
        template_entity_ids = MATCH_ALL

    entity_ids = device_config.get(CONF_ENTITY_ID, template_entity_ids)

    covers.append(
        CoverTemplate(
            hass,
            device, friendly_name, state_template,
            position_template, tilt_template, icon_template,
            entity_picture_template, open_action, close_action,
            stop_action, position_action, tilt_action,
            optimistic, tilt_optimistic, entity_ids
        )
    )
if not covers:
    _LOGGER.error("No covers added")
    return False

async_add_entities(covers)
return True

class CoverTemplate(CoverDevice):
“”“Representation of a Template cover.”""

def __init__(self, hass, device_id, friendly_name, state_template,
             position_template, tilt_template, icon_template,
             entity_picture_template, open_action, close_action,
             stop_action, position_action, tilt_action,
             optimistic, tilt_optimistic, entity_ids):
    """Initialize the Template cover."""
    self.hass = hass
    self.entity_id = async_generate_entity_id(
        ENTITY_ID_FORMAT, device_id, hass=hass)
    self._name = friendly_name
    self._template = state_template
    self._position_template = position_template
    self._tilt_template = tilt_template
    self._icon_template = icon_template
    self._entity_picture_template = entity_picture_template
    self._open_script = None
    if open_action is not None:
        self._open_script = Script(hass, open_action)
    self._close_script = None
    if close_action is not None:
        self._close_script = Script(hass, close_action)
    self._stop_script = None
    if stop_action is not None:
        self._stop_script = Script(hass, stop_action)
    self._position_script = None
    if position_action is not None:
        self._position_script = Script(hass, position_action)
    self._tilt_script = None
    if tilt_action is not None:
        self._tilt_script = Script(hass, tilt_action)
    self._optimistic = (optimistic or
                        (not state_template and not position_template))
    self._tilt_optimistic = tilt_optimistic or not tilt_template
    self._icon = None
    self._entity_picture = None
    self._position = None
    self._tilt_value = None
    self._entities = entity_ids

    if self._template is not None:
        self._template.hass = self.hass
    if self._position_template is not None:
        self._position_template.hass = self.hass
    if self._tilt_template is not None:
        self._tilt_template.hass = self.hass
    if self._icon_template is not None:
        self._icon_template.hass = self.hass
    if self._entity_picture_template is not None:
        self._entity_picture_template.hass = self.hass

async def async_added_to_hass(self):
    """Register callbacks."""
    @callback
    def template_cover_state_listener(entity, old_state, new_state):
        """Handle target device state changes."""
        self.async_schedule_update_ha_state(True)

    @callback
    def template_cover_startup(event):
        """Update template on startup."""
        async_track_state_change(
            self.hass, self._entities, template_cover_state_listener)

        self.async_schedule_update_ha_state(True)

    self.hass.bus.async_listen_once(
        EVENT_HOMEASSISTANT_START, template_cover_startup)

@property
def name(self):
    """Return the name of the cover."""
    return self._name

@property
def is_closed(self):
    """Return if the cover is closed."""
    return self._position == 0

@property
def current_cover_position(self):
    """Return current position of cover.
    None is unknown, 0 is closed, 100 is fully open.
    """
    if self._position_template or self._position_script:
        return self._position
    return None

@property
def current_cover_tilt_position(self):
    """Return current position of cover tilt.
    None is unknown, 0 is closed, 100 is fully open.
    """
    return self._tilt_value

@property
def icon(self):
    """Return the icon to use in the frontend, if any."""
    return self._icon

@property
def entity_picture(self):
    """Return the entity picture to use in the frontend, if any."""
    return self._entity_picture

@property
def supported_features(self):
    """Flag supported features."""
    supported_features = SUPPORT_OPEN | SUPPORT_CLOSE

    if self._stop_script is not None:
        supported_features |= SUPPORT_STOP

    if self._position_script is not None:
        supported_features |= SUPPORT_SET_POSITION

    if self.current_cover_tilt_position is not None:
        supported_features |= TILT_FEATURES

    return supported_features

@property
def should_poll(self):
    """Return the polling state."""
    return False

async def async_open_cover(self, **kwargs):
    """Move the cover up."""
    if self._open_script:
        await self._open_script.async_run(context=self._context)
    elif self._position_script:
        await self._position_script.async_run(
            {"position": 100}, context=self._context)
    if self._optimistic:
        self._position = 100
        self.async_schedule_update_ha_state()
    #self.async_schedule_update_ha_state()

async def async_close_cover(self, **kwargs):
    """Move the cover down."""
    if self._close_script:
        await self._close_script.async_run(context=self._context)
    elif self._position_script:
        await self._position_script.async_run(
            {"position": 0}, context=self._context)
    if self._optimistic:
        self._position = 0
        self.async_schedule_update_ha_state()
    #self.async_schedule_update_ha_state()

async def async_stop_cover(self, **kwargs):
    """Fire the stop action."""
    if self._stop_script:
        await self._stop_script.async_run(context=self._context)

async def async_set_cover_position(self, **kwargs):
    """Set cover position."""
    self._position = kwargs[ATTR_POSITION]
    await self._position_script.async_run(
        {"position": self._position}, context=self._context)
    if self._optimistic:
        self.async_schedule_update_ha_state()

async def async_open_cover_tilt(self, **kwargs):
    """Tilt the cover open."""
    self._tilt_value = 100
    await self._tilt_script.async_run(
        {"tilt": self._tilt_value}, context=self._context)
    if self._tilt_optimistic:
        self.async_schedule_update_ha_state()

async def async_close_cover_tilt(self, **kwargs):
    """Tilt the cover closed."""
    self._tilt_value = 0
    await self._tilt_script.async_run(
        {"tilt": self._tilt_value}, context=self._context)
    if self._tilt_optimistic:
        self.async_schedule_update_ha_state()

async def async_set_cover_tilt_position(self, **kwargs):
    """Move the cover tilt to a specific position."""
    self._tilt_value = kwargs[ATTR_TILT_POSITION]
    await self._tilt_script.async_run(
        {"tilt": self._tilt_value}, context=self._context)
    if self._tilt_optimistic:
        self.async_schedule_update_ha_state()

async def async_update(self):
    """Update the state from the template."""
    if self._template is not None:
        try:
            state = self._template.async_render().lower()
            if state in _VALID_STATES:
                if state in ('true', STATE_OPEN):
                    self._position = 100
                else:
                    self._position = 0
            else:
                _LOGGER.error(
                    'Received invalid cover is_on state: %s. Expected: %s',
                    state, ', '.join(_VALID_STATES))
                self._position = None
        except TemplateError as ex:
            _LOGGER.error(ex)
            self._position = None
    if self._position_template is not None:
        try:
            state = float(self._position_template.async_render())
            if state < 0 or state > 100:
                self._position = None
                _LOGGER.error("Cover position value must be"
                              " between 0 and 100."
                              " Value was: %.2f", state)
            else:
                self._position = state
        except TemplateError as ex:
            _LOGGER.error(ex)
            self._position = None
        except ValueError as ex:
            _LOGGER.error(ex)
            self._position = None
    if self._tilt_template is not None:
        try:
            state = float(self._tilt_template.async_render())
            if state < 0 or state > 100:
                self._tilt_value = None
                _LOGGER.error("Tilt value must be between 0 and 100."
                              " Value was: %.2f", state)
            else:
                self._tilt_value = state
        except TemplateError as ex:
            _LOGGER.error(ex)
            self._tilt_value = None
        except ValueError as ex:
            _LOGGER.error(ex)
            self._tilt_value = None

    for property_name, template in (
            ('_icon', self._icon_template),
            ('_entity_picture', self._entity_picture_template)):
        if template is None:
            continue

        try:
            setattr(self, property_name, template.async_render())
        except TemplateError as ex:
            friendly_property_name = property_name[1:].replace('_', ' ')
            if ex.args and ex.args[0].startswith(
                    "UndefinedError: 'None' has no attribute"):
                # Common during HA startup - so just a warning
                _LOGGER.warning('Could not render %s template %s,'
                                ' the state is unknown.',
                                friendly_property_name, self._name)
                return

            try:
                setattr(self, property_name,
                        getattr(super(), property_name))
            except AttributeError:
                _LOGGER.error('Could not render %s template %s: %s',
                              friendly_property_name, self._name, ex)

A59W0_GF3XSL4Z%25O4KQMQT3

The actual situation is that the curtain status is inconsistent with the interface display, so I want the buttons on the interface to be used all the time.