예제 #1
0
class ScriptEntity(ToggleEntity):
    """Representation of a script entity."""

    def __init__(self, hass, object_id, name, sequence):
        """Initialize the script."""
        self.object_id = object_id
        self.entity_id = ENTITY_ID_FORMAT.format(object_id)
        self.script = Script(hass, sequence, name, self.async_update_ha_state)

    @property
    def should_poll(self):
        """No polling needed."""
        return False

    @property
    def name(self):
        """Return the name of the entity."""
        return self.script.name

    @property
    def state_attributes(self):
        """Return the state attributes."""
        attrs = {}
        attrs[ATTR_LAST_TRIGGERED] = self.script.last_triggered
        if self.script.can_cancel:
            attrs[ATTR_CAN_CANCEL] = self.script.can_cancel
        if self.script.last_action:
            attrs[ATTR_LAST_ACTION] = self.script.last_action
        return attrs

    @property
    def is_on(self):
        """Return true if script is on."""
        return self.script.is_running

    @asyncio.coroutine
    def async_turn_on(self, **kwargs):
        """Turn the script on."""
        yield from self.script.async_run(kwargs.get(ATTR_VARIABLES))

    @asyncio.coroutine
    def async_turn_off(self, **kwargs):
        """Turn script off."""
        self.script.async_stop()

    def async_remove(self):
        """Remove script from HASS.

        This method must be run in the event loop and returns a coroutine.
        """
        if self.script.is_running:
            self.script.async_stop()

        # remove service
        self.hass.services.async_remove(DOMAIN, self.object_id)

        return super().async_remove()
예제 #2
0
class ScriptEntity(ToggleEntity):
    """Representation of a script entity."""

    def __init__(self, hass, object_id, name, sequence):
        """Initialize the script."""
        self.object_id = object_id
        self.entity_id = ENTITY_ID_FORMAT.format(object_id)
        self.script = Script(hass, sequence, name, self.async_update_ha_state)

    @property
    def should_poll(self):
        """No polling needed."""
        return False

    @property
    def name(self):
        """Return the name of the entity."""
        return self.script.name

    @property
    def state_attributes(self):
        """Return the state attributes."""
        attrs = {}
        attrs[ATTR_LAST_TRIGGERED] = self.script.last_triggered
        if self.script.can_cancel:
            attrs[ATTR_CAN_CANCEL] = self.script.can_cancel
        if self.script.last_action:
            attrs[ATTR_LAST_ACTION] = self.script.last_action
        return attrs

    @property
    def is_on(self):
        """Return true if script is on."""
        return self.script.is_running

    @asyncio.coroutine
    def async_turn_on(self, **kwargs):
        """Turn the script on."""
        yield from self.script.async_run(kwargs.get(ATTR_VARIABLES))

    @asyncio.coroutine
    def async_turn_off(self, **kwargs):
        """Turn script off."""
        self.script.async_stop()

    def async_remove(self):
        """Remove script from HASS.

        This method must be run in the event loop and returns a coroutine.
        """
        if self.script.is_running:
            self.script.async_stop()

        # remove service
        self.hass.services.async_remove(DOMAIN, self.object_id)

        return super().async_remove()
예제 #3
0
class ScriptEntity(ToggleEntity):
    """Representation of a script entity."""

    def __init__(self, hass, object_id, name, sequence):
        """Initialize the script."""
        self.object_id = object_id
        self.entity_id = ENTITY_ID_FORMAT.format(object_id)
        self.script = Script(hass, sequence, name, self.async_update_ha_state)

    @property
    def should_poll(self):
        """No polling needed."""
        return False

    @property
    def name(self):
        """Return the name of the entity."""
        return self.script.name

    @property
    def state_attributes(self):
        """Return the state attributes."""
        attrs = {}
        if self.script.can_cancel:
            attrs[ATTR_CAN_CANCEL] = self.script.can_cancel
        if self.script.last_action:
            attrs[ATTR_LAST_ACTION] = self.script.last_action
        return attrs

    @property
    def is_on(self):
        """Return true if script is on."""
        return self.script.is_running

    @asyncio.coroutine
    def async_turn_on(self, **kwargs):
        """Turn the script on."""
        yield from self.script.async_run(kwargs.get(ATTR_VARIABLES))

    @asyncio.coroutine
    def async_turn_off(self, **kwargs):
        """Turn script off."""
        self.script.async_stop()
예제 #4
0
class ScriptEntity(ToggleEntity):
    """Representation of a script entity."""
    def __init__(self, hass, object_id, name, sequence):
        """Initialize the script."""
        self.object_id = object_id
        self.entity_id = ENTITY_ID_FORMAT.format(object_id)
        self.script = Script(hass, sequence, name, self.async_update_ha_state)

    @property
    def should_poll(self):
        """No polling needed."""
        return False

    @property
    def name(self):
        """Return the name of the entity."""
        return self.script.name

    @property
    def state_attributes(self):
        """Return the state attributes."""
        attrs = {}
        if self.script.can_cancel:
            attrs[ATTR_CAN_CANCEL] = self.script.can_cancel
        if self.script.last_action:
            attrs[ATTR_LAST_ACTION] = self.script.last_action
        return attrs

    @property
    def is_on(self):
        """Return true if script is on."""
        return self.script.is_running

    @asyncio.coroutine
    def async_turn_on(self, **kwargs):
        """Turn the script on."""
        yield from self.script.async_run(kwargs.get(ATTR_VARIABLES))

    @asyncio.coroutine
    def async_turn_off(self, **kwargs):
        """Turn script off."""
        self.script.async_stop()
예제 #5
0
class CoverTemplate(CoverDevice):
    """Representation of a Template cover."""

    def __init__(self, hass, device_id, friendly_name, state_template,
                 position_template, tilt_template, icon_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._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._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

    @asyncio.coroutine
    def async_added_to_hass(self):
        """Register callbacks."""
        state = yield from async_get_last_state(self.hass, self.entity_id)
        if state:
            self._position = 100 if state.state == STATE_OPEN else 0

        @callback
        def template_cover_state_listener(entity, old_state, new_state):
            """Handle target device state changes."""
            self.hass.async_add_job(self.async_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.hass.async_add_job(self.async_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.
        """
        return self._position

    @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 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

    @asyncio.coroutine
    def async_open_cover(self, **kwargs):
        """Move the cover up."""
        if self._open_script:
            yield from self._open_script.async_run()
        elif self._position_script:
            yield from self._position_script.async_run({"position": 100})
        if self._optimistic:
            self._position = 100
            self.hass.async_add_job(self.async_update_ha_state())

    @asyncio.coroutine
    def async_close_cover(self, **kwargs):
        """Move the cover down."""
        if self._close_script:
            yield from self._close_script.async_run()
        elif self._position_script:
            yield from self._position_script.async_run({"position": 0})
        if self._optimistic:
            self._position = 0
            self.hass.async_add_job(self.async_update_ha_state())

    @asyncio.coroutine
    def async_stop_cover(self, **kwargs):
        """Fire the stop action."""
        if self._stop_script:
            self.hass.async_add_job(self._stop_script.async_run())

    @asyncio.coroutine
    def async_set_cover_position(self, **kwargs):
        """Set cover position."""
        self._position = kwargs[ATTR_POSITION]
        yield from self._position_script.async_run(
            {"position": self._position})
        if self._optimistic:
            self.hass.async_add_job(self.async_update_ha_state())

    @asyncio.coroutine
    def async_open_cover_tilt(self, **kwargs):
        """Tilt the cover open."""
        self._tilt_value = 100
        yield from self._tilt_script.async_run({"tilt": self._tilt_value})
        if self._tilt_optimistic:
            self.hass.async_add_job(self.async_update_ha_state())

    @asyncio.coroutine
    def async_close_cover_tilt(self, **kwargs):
        """Tilt the cover closed."""
        self._tilt_value = 0
        yield from self._tilt_script.async_run(
            {"tilt": self._tilt_value})
        if self._tilt_optimistic:
            self.hass.async_add_job(self.async_update_ha_state())

    @asyncio.coroutine
    def async_set_cover_tilt_position(self, **kwargs):
        """Move the cover tilt to a specific position."""
        self._tilt_value = kwargs[ATTR_TILT_POSITION]
        yield from self._tilt_script.async_run({"tilt": self._tilt_value})
        if self._tilt_optimistic:
            self.hass.async_add_job(self.async_update_ha_state())

    @asyncio.coroutine
    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
        if self._icon_template is not None:
            try:
                self._icon = self._icon_template.async_render()
            except TemplateError as ex:
                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 icon template %s,'
                                    ' the state is unknown.', self._name)
                    return
                self._icon = super().icon
                _LOGGER.error('Could not render icon template %s: %s',
                              self._name, ex)
예제 #6
0
class LightTemplate(Light):
    """Representation of a templated Light, including dimmable."""
    def __init__(self, hass, device_id, friendly_name, state_template,
                 on_action, off_action, level_action, level_template,
                 entity_ids):
        """Initialize the light."""
        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._on_script = Script(hass, on_action)
        self._off_script = Script(hass, off_action)
        self._level_script = None
        if level_action is not None:
            self._level_script = Script(hass, level_action)
        self._level_template = level_template

        self._state = False
        self._brightness = None
        self._entities = entity_ids

        if self._template is not None:
            self._template.hass = self.hass
        if self._level_template is not None:
            self._level_template.hass = self.hass

    @property
    def brightness(self):
        """Return the brightness of the light."""
        return self._brightness

    @property
    def name(self):
        """Return the display name of this light."""
        return self._name

    @property
    def supported_features(self):
        """Flag supported features."""
        if self._level_script is not None:
            return SUPPORT_BRIGHTNESS

        return 0

    @property
    def is_on(self):
        """Return true if device is on."""
        return self._state

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

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

        @callback
        def template_light_startup(event):
            """Update template on startup."""
            if (self._template is not None
                    or self._level_template is not None):
                async_track_state_change(self.hass, self._entities,
                                         template_light_state_listener)

            self.async_schedule_update_ha_state(True)

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

    @asyncio.coroutine
    def async_turn_on(self, **kwargs):
        """Turn the light on."""
        optimistic_set = False
        # set optimistic states
        if self._template is None:
            self._state = True
            optimistic_set = True

        if self._level_template is None and ATTR_BRIGHTNESS in kwargs:
            _LOGGER.info("Optimistically setting brightness to %s",
                         kwargs[ATTR_BRIGHTNESS])
            self._brightness = kwargs[ATTR_BRIGHTNESS]
            optimistic_set = True

        if ATTR_BRIGHTNESS in kwargs and self._level_script:
            self.hass.async_add_job(
                self._level_script.async_run(
                    {"brightness": kwargs[ATTR_BRIGHTNESS]}))
        else:
            self.hass.async_add_job(self._on_script.async_run())

        if optimistic_set:
            self.async_schedule_update_ha_state()

    @asyncio.coroutine
    def async_turn_off(self, **kwargs):
        """Turn the light off."""
        self.hass.async_add_job(self._off_script.async_run())
        if self._template is None:
            self._state = False
            self.async_schedule_update_ha_state()

    @asyncio.coroutine
    def async_update(self):
        """Update the state from the template."""
        print("ASYNC UPDATE")
        if self._template is not None:
            try:
                state = self._template.async_render().lower()
            except TemplateError as ex:
                _LOGGER.error(ex)
                self._state = None

            if state in _VALID_STATES:
                self._state = state in ('true', STATE_ON)
            else:
                _LOGGER.error(
                    'Received invalid light is_on state: %s. ' +
                    'Expected: %s', state, ', '.join(_VALID_STATES))
                self._state = None

        if self._level_template is not None:
            try:
                brightness = self._level_template.async_render()
            except TemplateError as ex:
                _LOGGER.error(ex)
                self._state = None

            if 0 <= int(brightness) <= 255:
                self._brightness = brightness
            else:
                _LOGGER.error(
                    'Received invalid brightness : %s' + 'Expected: 0-255',
                    brightness)
                self._brightness = None
예제 #7
0
class ScriptEntity(ToggleEntity):
    """Representation of a script entity."""

    icon = None

    def __init__(self, hass, object_id, cfg):
        """Initialize the script."""
        self.object_id = object_id
        self.icon = cfg.get(CONF_ICON)
        self.entity_id = ENTITY_ID_FORMAT.format(object_id)
        self.script = Script(
            hass,
            cfg[CONF_SEQUENCE],
            cfg.get(CONF_ALIAS, object_id),
            DOMAIN,
            running_description="script sequence",
            change_listener=self.async_change_listener,
            script_mode=cfg[CONF_MODE],
            max_runs=cfg[CONF_MAX],
            max_exceeded=cfg[CONF_MAX_EXCEEDED],
            logger=logging.getLogger(f"{__name__}.{object_id}"),
            variables=cfg.get(CONF_VARIABLES),
        )
        self._changed = asyncio.Event()

    @property
    def should_poll(self):
        """No polling needed."""
        return False

    @property
    def name(self):
        """Return the name of the entity."""
        return self.script.name

    @property
    def state_attributes(self):
        """Return the state attributes."""
        attrs = {
            ATTR_LAST_TRIGGERED: self.script.last_triggered,
            ATTR_MODE: self.script.script_mode,
            ATTR_CUR: self.script.runs,
        }
        if self.script.supports_max:
            attrs[ATTR_MAX] = self.script.max_runs
        if self.script.last_action:
            attrs[ATTR_LAST_ACTION] = self.script.last_action
        return attrs

    @property
    def is_on(self):
        """Return true if script is on."""
        return self.script.is_running

    @callback
    def async_change_listener(self):
        """Update state."""
        self.async_write_ha_state()
        self._changed.set()

    async def async_turn_on(self, **kwargs):
        """Turn the script on."""
        variables = kwargs.get("variables")
        context = kwargs.get("context")
        wait = kwargs.get("wait", True)
        self.async_set_context(context)
        self.hass.bus.async_fire(
            EVENT_SCRIPT_STARTED,
            {ATTR_NAME: self.script.name, ATTR_ENTITY_ID: self.entity_id},
            context=context,
        )
        coro = self.script.async_run(variables, context)
        if wait:
            await coro
            return

        # Caller does not want to wait for called script to finish so let script run in
        # separate Task. However, wait for first state change so we can guarantee that
        # it is written to the State Machine before we return.
        self._changed.clear()
        self.hass.async_create_task(coro)
        await self._changed.wait()

    async def async_turn_off(self, **kwargs):
        """Turn script off."""
        await self.script.async_stop()

    async def async_will_remove_from_hass(self):
        """Stop script and remove service when it will be removed from Home Assistant."""
        await self.script.async_stop()

        # remove service
        self.hass.services.async_remove(DOMAIN, self.object_id)
예제 #8
0
class CoverTemplate(CoverDevice):
    """Representation of a Template cover."""

    def __init__(self, hass, device_id, friendly_name, state_template,
                 position_template, tilt_template, icon_template,
                 open_action, close_action, stop_action,
                 position_action, tilt_action, 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._open_script = Script(hass, open_action)
        self._close_script = Script(hass, close_action)
        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._icon = 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

    @asyncio.coroutine
    def async_added_to_hass(self):
        """Register callbacks."""
        state = yield from async_get_last_state(self.hass, self.entity_id)
        if state:
            self._position = 100 if state.state == STATE_OPEN else 0

        @callback
        def template_cover_state_listener(entity, old_state, new_state):
            """Handle target device state changes."""
            self.hass.async_add_job(self.async_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.hass.async_add_job(self.async_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.
        """
        return self._position

    @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 supported_features(self):
        """Flag supported features."""
        supported_features = SUPPORT_OPEN | SUPPORT_CLOSE | SUPPORT_STOP

        if self.current_cover_position 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

    @asyncio.coroutine
    def async_open_cover(self, **kwargs):
        """Move the cover up."""
        self.hass.async_add_job(self._open_script.async_run())

    @asyncio.coroutine
    def async_close_cover(self, **kwargs):
        """Move the cover down."""
        self.hass.async_add_job(self._close_script.async_run())

    @asyncio.coroutine
    def async_stop_cover(self, **kwargs):
        """Fire the stop action."""
        self.hass.async_add_job(self._stop_script.async_run())

    @asyncio.coroutine
    def async_set_cover_position(self, **kwargs):
        """Set cover position."""
        if ATTR_POSITION not in kwargs:
            return
        self._position = kwargs[ATTR_POSITION]
        self.hass.async_add_job(self._position_script.async_run(
            {"position": self._position}))

    @asyncio.coroutine
    def async_open_cover_tilt(self, **kwargs):
        """Tilt the cover open."""
        self._tilt_value = 100
        self.hass.async_add_job(self._tilt_script.async_run(
            {"tilt": self._tilt_value}))

    @asyncio.coroutine
    def async_close_cover_tilt(self, **kwargs):
        """Tilt the cover closed."""
        self._tilt_value = 0
        self.hass.async_add_job(self._tilt_script.async_run(
            {"tilt": self._tilt_value}))

    @asyncio.coroutine
    def async_set_cover_tilt_position(self, **kwargs):
        """Move the cover tilt to a specific position."""
        if ATTR_TILT_POSITION not in kwargs:
            return
        self._tilt_value = kwargs[ATTR_TILT_POSITION]
        self.hass.async_add_job(self._tilt_script.async_run(
            {"tilt": self._tilt_value}))

    @asyncio.coroutine
    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
        if self._icon_template is not None:
            try:
                self._icon = self._icon_template.async_render()
            except TemplateError as ex:
                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 icon template %s,'
                                    ' the state is unknown.', self._name)
                    return
                self._icon = super().icon
                _LOGGER.error('Could not render icon template %s: %s',
                              self._name, ex)
예제 #9
0
class LightTemplate(Light):
    """Representation of a templated Light, including dimmable."""

    def __init__(self, hass, device_id, friendly_name, state_template,
                 icon_template, entity_picture_template, on_action,
                 off_action, level_action, level_template, entity_ids):
        """Initialize the light."""
        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._icon_template = icon_template
        self._entity_picture_template = entity_picture_template
        self._on_script = Script(hass, on_action)
        self._off_script = Script(hass, off_action)
        self._level_script = None
        if level_action is not None:
            self._level_script = Script(hass, level_action)
        self._level_template = level_template

        self._state = False
        self._icon = None
        self._entity_picture = None
        self._brightness = None
        self._entities = entity_ids

        if self._template is not None:
            self._template.hass = self.hass
        if self._level_template is not None:
            self._level_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

    @property
    def brightness(self):
        """Return the brightness of the light."""
        return self._brightness

    @property
    def name(self):
        """Return the display name of this light."""
        return self._name

    @property
    def supported_features(self):
        """Flag supported features."""
        if self._level_script is not None:
            return SUPPORT_BRIGHTNESS

        return 0

    @property
    def is_on(self):
        """Return true if device is on."""
        return self._state

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

    @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

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

        @callback
        def template_light_startup(event):
            """Update template on startup."""
            if (self._template is not None or
                    self._level_template is not None):
                async_track_state_change(
                    self.hass, self._entities, template_light_state_listener)

            self.async_schedule_update_ha_state(True)

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

    @asyncio.coroutine
    def async_turn_on(self, **kwargs):
        """Turn the light on."""
        optimistic_set = False
        # set optimistic states
        if self._template is None:
            self._state = True
            optimistic_set = True

        if self._level_template is None and ATTR_BRIGHTNESS in kwargs:
            _LOGGER.info("Optimistically setting brightness to %s",
                         kwargs[ATTR_BRIGHTNESS])
            self._brightness = kwargs[ATTR_BRIGHTNESS]
            optimistic_set = True

        if ATTR_BRIGHTNESS in kwargs and self._level_script:
            self.hass.async_add_job(self._level_script.async_run(
                {"brightness": kwargs[ATTR_BRIGHTNESS]}))
        else:
            yield from self._on_script.async_run()

        if optimistic_set:
            self.async_schedule_update_ha_state()

    @asyncio.coroutine
    def async_turn_off(self, **kwargs):
        """Turn the light off."""
        yield from self._off_script.async_run()
        if self._template is None:
            self._state = False
            self.async_schedule_update_ha_state()

    @asyncio.coroutine
    def async_update(self):
        """Update the state from the template."""
        if self._template is not None:
            try:
                state = self._template.async_render().lower()
            except TemplateError as ex:
                _LOGGER.error(ex)
                self._state = None

            if state in _VALID_STATES:
                self._state = state in ('true', STATE_ON)
            else:
                _LOGGER.error(
                    'Received invalid light is_on state: %s. Expected: %s',
                    state, ', '.join(_VALID_STATES))
                self._state = None

        if self._level_template is not None:
            try:
                brightness = self._level_template.async_render()
            except TemplateError as ex:
                _LOGGER.error(ex)
                self._state = None

            if 0 <= int(brightness) <= 255:
                self._brightness = int(brightness)
            else:
                _LOGGER.error(
                    'Received invalid brightness : %s. Expected: 0-255',
                    brightness)
                self._brightness = 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)
예제 #10
0
class SwitchTemplate(SwitchDevice):
    """Representation of a Template switch."""

    def __init__(self, hass, device_id, friendly_name, state_template,
                 icon_template, entity_picture_template, on_action,
                 off_action, entity_ids):
        """Initialize the Template switch."""
        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._on_script = Script(hass, on_action)
        self._off_script = Script(hass, off_action)
        self._state = False
        self._icon_template = icon_template
        self._entity_picture_template = entity_picture_template
        self._icon = None
        self._entity_picture = None
        self._entities = entity_ids

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

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

            self.async_schedule_update_ha_state(True)

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

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

    @property
    def is_on(self):
        """Return true if device is on."""
        return self._state

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

    @property
    def available(self):
        """If switch is available."""
        return self._state is not None

    @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

    @asyncio.coroutine
    def async_turn_on(self, **kwargs):
        """Fire the on action."""
        yield from self._on_script.async_run()

    @asyncio.coroutine
    def async_turn_off(self, **kwargs):
        """Fire the off action."""
        yield from self._off_script.async_run()

    @asyncio.coroutine
    def async_update(self):
        """Update the state from the template."""
        try:
            state = self._template.async_render().lower()

            if state in _VALID_STATES:
                self._state = state in ('true', STATE_ON)
            else:
                _LOGGER.error(
                    'Received invalid switch is_on state: %s. Expected: %s',
                    state, ', '.join(_VALID_STATES))
                self._state = None

        except TemplateError as ex:
            _LOGGER.error(ex)
            self._state = 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)
예제 #11
0
class LightTemplate(Light):
    """Representation of a templated Light, including dimmable."""

    def __init__(self, hass, device_id, friendly_name, state_template,
                 on_action, off_action, level_action, level_template,
                 entity_ids):
        """Initialize the light."""
        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._on_script = Script(hass, on_action)
        self._off_script = Script(hass, off_action)
        self._level_script = None
        if level_action is not None:
            self._level_script = Script(hass, level_action)
        self._level_template = level_template

        self._state = False
        self._brightness = None
        self._entities = entity_ids

        if self._template is not None:
            self._template.hass = self.hass
        if self._level_template is not None:
            self._level_template.hass = self.hass

    @property
    def brightness(self):
        """Return the brightness of the light."""
        return self._brightness

    @property
    def name(self):
        """Return the display name of this light."""
        return self._name

    @property
    def supported_features(self):
        """Flag supported features."""
        if self._level_script is not None:
            return SUPPORT_BRIGHTNESS

        return 0

    @property
    def is_on(self):
        """Return true if device is on."""
        return self._state

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

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

        @callback
        def template_light_startup(event):
            """Update template on startup."""
            if (self._template is not None or
                    self._level_template is not None):
                async_track_state_change(
                    self.hass, self._entities, template_light_state_listener)

            self.async_schedule_update_ha_state(True)

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

    @asyncio.coroutine
    def async_turn_on(self, **kwargs):
        """Turn the light on."""
        optimistic_set = False
        # set optimistic states
        if self._template is None:
            self._state = True
            optimistic_set = True

        if self._level_template is None and ATTR_BRIGHTNESS in kwargs:
            _LOGGER.info("Optimistically setting brightness to %s",
                         kwargs[ATTR_BRIGHTNESS])
            self._brightness = kwargs[ATTR_BRIGHTNESS]
            optimistic_set = True

        if ATTR_BRIGHTNESS in kwargs and self._level_script:
            self.hass.async_add_job(self._level_script.async_run(
                {"brightness": kwargs[ATTR_BRIGHTNESS]}))
        else:
            self.hass.async_add_job(self._on_script.async_run())

        if optimistic_set:
            self.async_schedule_update_ha_state()

    @asyncio.coroutine
    def async_turn_off(self, **kwargs):
        """Turn the light off."""
        self.hass.async_add_job(self._off_script.async_run())
        if self._template is None:
            self._state = False
            self.async_schedule_update_ha_state()

    @asyncio.coroutine
    def async_update(self):
        """Update the state from the template."""
        print("ASYNC UPDATE")
        if self._template is not None:
            try:
                state = self._template.async_render().lower()
            except TemplateError as ex:
                _LOGGER.error(ex)
                self._state = None

            if state in _VALID_STATES:
                self._state = state in ('true', STATE_ON)
            else:
                _LOGGER.error(
                    'Received invalid light is_on state: %s. ' +
                    'Expected: %s',
                    state, ', '.join(_VALID_STATES))
                self._state = None

        if self._level_template is not None:
            try:
                brightness = self._level_template.async_render()
            except TemplateError as ex:
                _LOGGER.error(ex)
                self._state = None

            if 0 <= int(brightness) <= 255:
                self._brightness = brightness
            else:
                _LOGGER.error(
                    'Received invalid brightness : %s' +
                    'Expected: 0-255',
                    brightness)
                self._brightness = None
예제 #12
0
class TemplateLock(LockDevice):
    def __init__(self, hass, name, value_template, command_lock,
                 command_unlock, optimistic):
        self._state = None
        self._hass = hass
        self._name = name
        self._state_template = value_template
        self._state_entities = value_template.extract_entities()
        self._command_lock = Script(hass, command_lock)
        self._command_unlock = Script(hass, command_unlock)
        self._optimistic = optimistic

    @asyncio.coroutine
    def async_added_to_hass(self):
        @callback
        def template_lock_state_listener(entity, old_state, new_state):
            self.update_state()

        @callback
        def template_lock_startup(event):
            async_track_state_change(self._hass, self._state_entities,
                                     template_lock_state_listener)
            self.update_state()

        self._hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START,
                                         template_lock_startup)

    @property
    def assumed_state(self):
        return self._optimistic

    @property
    def should_poll(self):
        return False

    @property
    def name(self):
        return self._name

    @property
    def is_locked(self):
        return self._state

    def update_state(self):
        try:
            self._state = self._state_template.async_render().lower() in (
                'true', 'on', '1', 'locked')
        except TemplateError as ex:
            self._state = None
            _LOGGER.error('Could not render template %s: %s', self._name, ex)
        self.async_schedule_update_ha_state(True)

    @asyncio.coroutine
    def async_lock(self, **kwargs):
        if self._optimistic:
            self._state = True
            self.async_schedule_update_ha_state()
        yield from self._command_lock.async_run()

    @asyncio.coroutine
    def async_unlock(self, **kwargs):
        if self._optimistic:
            self._state = False
            self.async_schedule_update_ha_state()
        yield from self._command_unlock.async_run()
예제 #13
0
class ScriptEntity(ToggleEntity):
    """Representation of a script entity."""

    icon = None

    def __init__(self, hass, object_id, name, icon, sequence, mode, queue_max):
        """Initialize the script."""
        self.object_id = object_id
        self.icon = icon
        self.entity_id = ENTITY_ID_FORMAT.format(object_id)
        self.script = Script(
            hass,
            sequence,
            name,
            self.async_change_listener,
            mode,
            queue_max,
            logging.getLogger(f"{__name__}.{object_id}"),
        )
        self._changed = asyncio.Event()

    @property
    def should_poll(self):
        """No polling needed."""
        return False

    @property
    def name(self):
        """Return the name of the entity."""
        return self.script.name

    @property
    def state_attributes(self):
        """Return the state attributes."""
        attrs = {ATTR_LAST_TRIGGERED: self.script.last_triggered}
        if self.script.can_cancel:
            attrs[ATTR_CAN_CANCEL] = self.script.can_cancel
        if self.script.last_action:
            attrs[ATTR_LAST_ACTION] = self.script.last_action
        return attrs

    @property
    def is_on(self):
        """Return true if script is on."""
        return self.script.is_running

    @callback
    def async_change_listener(self):
        """Update state."""
        self.async_write_ha_state()
        self._changed.set()

    async def async_turn_on(self, **kwargs):
        """Turn the script on."""
        variables = kwargs.get("variables")
        context = kwargs.get("context")
        wait = kwargs.get("wait", True)
        self.async_set_context(context)
        self.hass.bus.async_fire(
            EVENT_SCRIPT_STARTED,
            {
                ATTR_NAME: self.script.name,
                ATTR_ENTITY_ID: self.entity_id
            },
            context=context,
        )
        coro = self.script.async_run(variables, context)
        if wait:
            await coro
            return

        # Caller does not want to wait for called script to finish so let script run in
        # separate Task. However, wait for first state change so we can guarantee that
        # it is written to the State Machine before we return. Only do this for
        # non-legacy scripts, since legacy scripts don't necessarily change state
        # immediately.
        self._changed.clear()
        self.hass.async_create_task(coro)
        if not self.script.is_legacy:
            await self._changed.wait()

    async def async_turn_off(self, **kwargs):
        """Turn script off."""
        await self.script.async_stop()

    async def async_will_remove_from_hass(self):
        """Stop script and remove service when it will be removed from Home Assistant."""
        await self.script.async_stop()

        # remove service
        self.hass.services.async_remove(DOMAIN, self.object_id)