예제 #1
0
class WOLSwitch(SwitchDevice):
    """Representation of a wake on lan switch."""
    def __init__(self, hass, name, host, mac_address, off_action,
                 broadcast_address):
        """Initialize the WOL switch."""
        import wakeonlan
        self._hass = hass
        self._name = name
        self._host = host
        self._mac_address = mac_address
        self._broadcast_address = broadcast_address
        self._off_script = Script(hass, off_action) if off_action else None
        self._state = False
        self._wol = wakeonlan

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

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

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

    def turn_on(self, **kwargs):
        """Turn the device on."""
        if self._broadcast_address:
            self._wol.send_magic_packet(self._mac_address,
                                        ip_address=self._broadcast_address)
        else:
            self._wol.send_magic_packet(self._mac_address)

    def turn_off(self, **kwargs):
        """Turn the device off if an off action is present."""
        if self._off_script is not None:
            self._off_script.run()

    def update(self):
        """Check if device is on and update the state."""
        if platform.system().lower() == 'windows':
            ping_cmd = [
                'ping', '-n', '1', '-w',
                str(DEFAULT_PING_TIMEOUT * 1000),
                str(self._host)
            ]
        else:
            ping_cmd = [
                'ping', '-c', '1', '-W',
                str(DEFAULT_PING_TIMEOUT),
                str(self._host)
            ]

        status = sp.call(ping_cmd, stdout=sp.DEVNULL, stderr=sp.DEVNULL)
        self._state = not bool(status)
예제 #2
0
class WOLSwitch(SwitchDevice):
    """Representation of a wake on lan switch."""

    def __init__(self, hass, name, host, mac_address,
                 off_action, broadcast_address):
        """Initialize the WOL switch."""
        from wakeonlan import wol
        self._hass = hass
        self._name = name
        self._host = host
        self._mac_address = mac_address
        self._broadcast_address = broadcast_address
        self._off_script = Script(hass, off_action) if off_action else None
        self._state = False
        self._wol = wol
        self.update()

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

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

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

    def turn_on(self):
        """Turn the device on."""
        if self._broadcast_address:
            self._wol.send_magic_packet(
                self._mac_address, ip_address=self._broadcast_address)
        else:
            self._wol.send_magic_packet(self._mac_address)

    def turn_off(self):
        """Turn the device off if an off action is present."""
        if self._off_script is not None:
            self._off_script.run()

    def update(self):
        """Check if device is on and update the state."""
        if platform.system().lower() == 'windows':
            ping_cmd = ['ping', '-n', '1', '-w',
                        str(DEFAULT_PING_TIMEOUT * 1000), str(self._host)]
        else:
            ping_cmd = ['ping', '-c', '1', '-W',
                        str(DEFAULT_PING_TIMEOUT), str(self._host)]

        status = sp.call(ping_cmd, stdout=sp.DEVNULL, stderr=sp.DEVNULL)
        self._state = not bool(status)
예제 #3
0
    def invoke_current_scene(self):
        current_scene = self.get_current_scene()

        _LOGGER.debug(f'Invoking script of {current_scene}')

        if self._scenes is not None and current_scene in self._scenes:
            scene = self._scenes[current_scene]

            if CONF_SCENE_SCRIPT in scene:
                scene_script = scene[CONF_SCENE_SCRIPT]

                if scene_script is not None:
                    script_invoker = Script(self._hass, scene_script)
                    script_invoker.run()
예제 #4
0
 def restore(self, entity_id, restore_script, delete):
     if entity_id not in self._entities_db:
         return
     old = self._entities_db[entity_id]
     variables = SaverEntity.convert_to_variables(old)
     if delete:
         self._entities_db.pop(entity_id)
     script = Script(self.hass,
                     restore_script,
                     self.name,
                     DOMAIN,
                     script_mode=SCRIPT_MODE_PARALLEL)
     script.run(variables=variables, context=Context())
     self.schedule_update_ha_state()
예제 #5
0
 def execute(self, script):
     script = Script(self.hass,
                     script,
                     self.name,
                     DOMAIN,
                     script_mode=SCRIPT_MODE_PARALLEL)
     variables = {}
     variables.update(self._variables_db)
     for entity_id in self._entities_db:
         variables.update(
             SaverEntity.convert_to_variables(self._entities_db[entity_id],
                                              entity_id))
     script.run(variables=variables, context=Context())
     self.schedule_update_ha_state()
예제 #6
0
class WOLSwitch(SwitchDevice):
    """Representation of a wake on lan switch."""
    def __init__(self, hass, name, host, mac_address, off_action):
        """Initialize the WOL switch."""
        from wakeonlan import wol
        self._hass = hass
        self._name = name
        self._host = host
        self._mac_address = mac_address
        self._off_script = Script(hass, off_action) if off_action else None
        self._state = False
        self._wol = wol
        self.update()

    @property
    def should_poll(self):
        """Poll for status regularly."""
        return True

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

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

    def turn_on(self):
        """Turn the device on."""
        self._wol.send_magic_packet(self._mac_address)

    def turn_off(self):
        """Turn the device off if an off action is present."""
        if self._off_script is not None:
            self._off_script.run()

    def update(self):
        """Check if device is on and update the state."""
        if platform.system().lower() == 'windows':
            ping_cmd = 'ping -n 1 -w {} {}'.format(DEFAULT_PING_TIMEOUT * 1000,
                                                   self._host)
        else:
            ping_cmd = 'ping -c 1 -W {} {}'.format(DEFAULT_PING_TIMEOUT,
                                                   self._host)

        status = sp.getstatusoutput(ping_cmd)[0]
        self._state = not bool(status)
예제 #7
0
class WOLSwitch(SwitchDevice):
    """Representation of a wake on lan switch."""

    def __init__(self, hass, name, host, mac_address, off_action):
        """Initialize the WOL switch."""
        from wakeonlan import wol

        self._hass = hass
        self._name = name
        self._host = host
        self._mac_address = mac_address
        self._off_script = Script(hass, off_action) if off_action else None
        self._state = False
        self._wol = wol
        self.update()

    @property
    def should_poll(self):
        """Poll for status regularly."""
        return True

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

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

    def turn_on(self):
        """Turn the device on."""
        self._wol.send_magic_packet(self._mac_address)

    def turn_off(self):
        """Turn the device off if an off action is present."""
        if self._off_script is not None:
            self._off_script.run()

    def update(self):
        """Check if device is on and update the state."""
        if platform.system().lower() == "windows":
            ping_cmd = "ping -n 1 -w {} {}".format(DEFAULT_PING_TIMEOUT * 1000, self._host)
        else:
            ping_cmd = "ping -c 1 -W {} {}".format(DEFAULT_PING_TIMEOUT, self._host)

        status = sp.getstatusoutput(ping_cmd)[0]
        self._state = not bool(status)
예제 #8
0
class ScriptEntity(ToggleEntity):
    """Representation of a script entity."""

    # pylint: disable=too-many-instance-attributes
    def __init__(self, hass, object_id, name, sequence):
        """Initialize the script."""
        self.entity_id = ENTITY_ID_FORMAT.format(object_id)
        self.script = Script(hass, sequence, name, self.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

    def turn_on(self, **kwargs):
        """Turn the entity on."""
        self.script.run(kwargs.get(ATTR_VARIABLES))

    def turn_off(self, **kwargs):
        """Turn script off."""
        self.script.stop()
예제 #9
0
class ScriptEntity(ToggleEntity):
    """Representation of a script entity."""

    # pylint: disable=too-many-instance-attributes
    def __init__(self, hass, object_id, name, sequence):
        """Initialize the script."""
        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

    def turn_on(self, **kwargs):
        """Turn the entity on."""
        self.script.run(kwargs.get(ATTR_VARIABLES))

    def turn_off(self, **kwargs):
        """Turn script off."""
        self.script.stop()
예제 #10
0
class Instruction:
    def __init__(self, hass, bot, command):
        self.hass = hass
        self.bot = bot
        self.script = None
        self.response = None
        self.command = command[COMMAND]

        _script = command.get(SCRIPT, None)
        if _script is not None:
            self.script = Script(hass, _script)

        _response = command.get(RESPONSE, None)
        if _response is not None:
            self.response = {RESPONSE_TEXT: _response.get(RESPONSE_TEXT, None)}
            _keyboard = _response.get(RESPONSE_KEYBOARD, None)
            if _keyboard:
                self.response[RESPONSE_KEYBOARD] = {
                    "keyboard": [],
                    "resize_keyboard": True,
                    "one_time_keyboard": True
                }
                for _key in _keyboard:
                    self.response[RESPONSE_KEYBOARD]["keyboard"].append([{
                        "text":
                        _key
                    }])
            else:
                self.response[RESPONSE_KEYBOARD] = None

    def execute(self, chat_id):
        if self.script:
            self.script.run()
        if self.response:
            self.bot.sendMessage(chat_id,
                                 self.response[RESPONSE_TEXT],
                                 parse_mode="Markdown",
                                 reply_markup=self.response[RESPONSE_KEYBOARD])
예제 #11
0
class LgWebOSDevice(MediaPlayerDevice):
    """Representation of a LG WebOS TV."""

    def __init__(self, host, name, customize, config, timeout,
                 hass, on_action):
        """Initialize the webos device."""
        from pylgtv import WebOsClient
        self._client = WebOsClient(host, config, timeout)
        self._on_script = Script(hass, on_action) if on_action else None
        self._customize = customize

        self._name = name
        # Assume that the TV is not muted
        self._muted = False
        # Assume that the TV is in Play mode
        self._playing = True
        self._volume = 0
        self._current_source = None
        self._current_source_id = None
        self._state = STATE_UNKNOWN
        self._source_list = {}
        self._app_list = {}
        self._channel = None

    @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS)
    def update(self):
        """Retrieve the latest data."""
        from websockets.exceptions import ConnectionClosed
        try:
            current_input = self._client.get_input()
            if current_input is not None:
                self._current_source_id = current_input
                if self._state in (STATE_UNKNOWN, STATE_OFF):
                    self._state = STATE_PLAYING
            else:
                self._state = STATE_OFF
                self._current_source = None
                self._current_source_id = None
                self._channel = None

            if self._state is not STATE_OFF:
                self._muted = self._client.get_muted()
                self._volume = self._client.get_volume()
                self._channel = self._client.get_current_channel()

                self._source_list = {}
                self._app_list = {}
                conf_sources = self._customize.get(CONF_SOURCES, [])

                for app in self._client.get_apps():
                    self._app_list[app['id']] = app
                    if app['id'] == self._current_source_id:
                        self._current_source = app['title']
                        self._source_list[app['title']] = app
                    elif (not conf_sources or
                          app['id'] in conf_sources or
                          any(word in app['title']
                              for word in conf_sources) or
                          any(word in app['id']
                              for word in conf_sources)):
                        self._source_list[app['title']] = app

                for source in self._client.get_inputs():
                    if source['id'] == self._current_source_id:
                        self._current_source = source['label']
                        self._source_list[source['label']] = source
                    elif (not conf_sources or
                          source['label'] in conf_sources or
                          any(source['label'].find(word) != -1
                              for word in conf_sources)):
                        self._source_list[source['label']] = source
        except (OSError, ConnectionClosed, TypeError,
                asyncio.TimeoutError):
            self._state = STATE_OFF
            self._current_source = None
            self._current_source_id = None
            self._channel = None

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

    @property
    def state(self):
        """Return the state of the device."""
        return self._state

    @property
    def is_volume_muted(self):
        """Boolean if volume is currently muted."""
        return self._muted

    @property
    def volume_level(self):
        """Volume level of the media player (0..1)."""
        return self._volume / 100.0

    @property
    def source(self):
        """Return the current input source."""
        return self._current_source

    @property
    def source_list(self):
        """List of available input sources."""
        return sorted(self._source_list.keys())

    @property
    def media_content_type(self):
        """Content type of current playing media."""
        return MEDIA_TYPE_CHANNEL

    @property
    def media_title(self):
        """Title of current playing media."""
        if (self._channel is not None) and ('channelName' in self._channel):
            return self._channel['channelName']
        return None

    @property
    def media_image_url(self):
        """Image url of current playing media."""
        if self._current_source_id in self._app_list:
            icon = self._app_list[self._current_source_id]['largeIcon']
            if not icon.startswith('http'):
                icon = self._app_list[self._current_source_id]['icon']
            return icon
        return None

    @property
    def supported_features(self):
        """Flag media player features that are supported."""
        if self._on_script:
            return SUPPORT_WEBOSTV | SUPPORT_TURN_ON
        return SUPPORT_WEBOSTV

    def turn_off(self):
        """Turn off media player."""
        from websockets.exceptions import ConnectionClosed
        self._state = STATE_OFF
        try:
            self._client.power_off()
        except (OSError, ConnectionClosed, TypeError,
                asyncio.TimeoutError):
            pass

    def turn_on(self):
        """Turn on the media player."""
        if self._on_script:
            self._on_script.run()

    def volume_up(self):
        """Volume up the media player."""
        self._client.volume_up()

    def volume_down(self):
        """Volume down media player."""
        self._client.volume_down()

    def set_volume_level(self, volume):
        """Set volume level, range 0..1."""
        tv_volume = volume * 100
        self._client.set_volume(tv_volume)

    def mute_volume(self, mute):
        """Send mute command."""
        self._muted = mute
        self._client.set_mute(mute)

    def media_play_pause(self):
        """Simulate play pause media player."""
        if self._playing:
            self.media_pause()
        else:
            self.media_play()

    def select_source(self, source):
        """Select input source."""
        source_dict = self._source_list.get(source)
        if source_dict is None:
            _LOGGER.warning("Source %s not found for %s", source, self.name)
            return
        self._current_source_id = source_dict['id']
        if source_dict.get('title'):
            self._current_source = source_dict['title']
            self._client.launch_app(source_dict['id'])
        elif source_dict.get('label'):
            self._current_source = source_dict['label']
            self._client.set_input(source_dict['id'])

    def play_media(self, media_type, media_id, **kwargs):
        """Play a piece of media."""
        _LOGGER.debug(
            "Call play media type <%s>, Id <%s>", media_type, media_id)

        if media_type == MEDIA_TYPE_CHANNEL:
            _LOGGER.debug("Searching channel...")
            partial_match_channel_id = None
            perfect_match_channel_id = None

            for channel in self._client.get_channels():
                if media_id == channel['channelNumber']:
                    perfect_match_channel_id = channel['channelId']
                    continue
                elif media_id.lower() == channel['channelName'].lower():
                    perfect_match_channel_id = channel['channelId']
                    continue
                elif media_id.lower() in channel['channelName'].lower():
                    partial_match_channel_id = channel['channelId']

            if perfect_match_channel_id is not None:
                _LOGGER.info(
                    "Switching to channel <%s> with perfect match",
                    perfect_match_channel_id)
                self._client.set_channel(perfect_match_channel_id)
            elif partial_match_channel_id is not None:
                _LOGGER.info(
                    "Switching to channel <%s> with partial match",
                    partial_match_channel_id)
                self._client.set_channel(partial_match_channel_id)

            return

    def media_play(self):
        """Send play command."""
        self._playing = True
        self._state = STATE_PLAYING
        self._client.play()

    def media_pause(self):
        """Send media pause command to media player."""
        self._playing = False
        self._state = STATE_PAUSED
        self._client.pause()

    def media_next_track(self):
        """Send next track command."""
        current_input = self._client.get_input()
        if current_input == LIVETV_APP_ID:
            self._client.channel_up()
        else:
            self._client.fast_forward()

    def media_previous_track(self):
        """Send the previous track command."""
        current_input = self._client.get_input()
        if current_input == LIVETV_APP_ID:
            self._client.channel_down()
        else:
            self._client.rewind()
예제 #12
0
class LgWebOSDevice(MediaPlayerDevice):
    """Representation of a LG WebOS TV."""
    def __init__(self, host, name, customize, config, timeout, hass,
                 on_action):
        """Initialize the webos device."""
        from pylgtv import WebOsClient

        self._client = WebOsClient(host, config, timeout)
        self._on_script = Script(hass, on_action) if on_action else None
        self._customize = customize

        self._name = name
        # Assume that the TV is not muted
        self._muted = False
        # Assume that the TV is in Play mode
        self._playing = True
        self._volume = 0
        self._current_source = None
        self._current_source_id = None
        self._state = None
        self._source_list = {}
        self._app_list = {}
        self._channel = None
        self._last_icon = None

    @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS)
    def update(self):
        """Retrieve the latest data."""
        from websockets.exceptions import ConnectionClosed

        try:
            current_input = self._client.get_input()
            if current_input is not None:
                self._current_source_id = current_input
                if self._state in (None, STATE_OFF):
                    self._state = STATE_PLAYING
            else:
                self._state = STATE_OFF
                self._current_source = None
                self._current_source_id = None
                self._channel = None

            if self._state is not STATE_OFF:
                self._muted = self._client.get_muted()
                self._volume = self._client.get_volume()
                self._channel = self._client.get_current_channel()

                self._source_list = {}
                self._app_list = {}
                conf_sources = self._customize.get(CONF_SOURCES, [])

                for app in self._client.get_apps():
                    self._app_list[app["id"]] = app
                    if app["id"] == self._current_source_id:
                        self._current_source = app["title"]
                        self._source_list[app["title"]] = app
                    elif (not conf_sources or app["id"] in conf_sources
                          or any(word in app["title"] for word in conf_sources)
                          or any(word in app["id"] for word in conf_sources)):
                        self._source_list[app["title"]] = app

                for source in self._client.get_inputs():
                    if source["id"] == self._current_source_id:
                        self._current_source = source["label"]
                        self._source_list[source["label"]] = source
                    elif (not conf_sources or source["label"] in conf_sources
                          or any(source["label"].find(word) != -1
                                 for word in conf_sources)):
                        self._source_list[source["label"]] = source
        except (OSError, ConnectionClosed, TypeError, asyncio.TimeoutError):
            self._state = STATE_OFF
            self._current_source = None
            self._current_source_id = None
            self._channel = None

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

    @property
    def state(self):
        """Return the state of the device."""
        return self._state

    @property
    def is_volume_muted(self):
        """Boolean if volume is currently muted."""
        return self._muted

    @property
    def volume_level(self):
        """Volume level of the media player (0..1)."""
        return self._volume / 100.0

    @property
    def source(self):
        """Return the current input source."""
        return self._current_source

    @property
    def source_list(self):
        """List of available input sources."""
        return sorted(self._source_list.keys())

    @property
    def media_content_type(self):
        """Content type of current playing media."""
        return MEDIA_TYPE_CHANNEL

    @property
    def media_title(self):
        """Title of current playing media."""
        if (self._channel is not None) and ("channelName" in self._channel):
            return self._channel["channelName"]
        return None

    @property
    def media_image_url(self):
        """Image url of current playing media."""
        if self._current_source_id in self._app_list:
            icon = self._app_list[self._current_source_id]["largeIcon"]
            if not icon.startswith("http"):
                icon = self._app_list[self._current_source_id]["icon"]

            # 'icon' holds a URL with a transient key. Avoid unnecessary
            # updates by returning the same URL until the image changes.
            if self._last_icon and (icon.split("/")[-1]
                                    == self._last_icon.split("/")[-1]):
                return self._last_icon
            self._last_icon = icon
            return icon
        return None

    @property
    def supported_features(self):
        """Flag media player features that are supported."""
        if self._on_script:
            return SUPPORT_WEBOSTV | SUPPORT_TURN_ON
        return SUPPORT_WEBOSTV

    def turn_off(self):
        """Turn off media player."""
        from websockets.exceptions import ConnectionClosed

        self._state = STATE_OFF
        try:
            self._client.power_off()
        except (OSError, ConnectionClosed, TypeError, asyncio.TimeoutError):
            pass

    def turn_on(self):
        """Turn on the media player."""
        if self._on_script:
            self._on_script.run()

    def volume_up(self):
        """Volume up the media player."""
        self._client.volume_up()

    def volume_down(self):
        """Volume down media player."""
        self._client.volume_down()

    def set_volume_level(self, volume):
        """Set volume level, range 0..1."""
        tv_volume = volume * 100
        self._client.set_volume(tv_volume)

    def mute_volume(self, mute):
        """Send mute command."""
        self._muted = mute
        self._client.set_mute(mute)

    def media_play_pause(self):
        """Simulate play pause media player."""
        if self._playing:
            self.media_pause()
        else:
            self.media_play()

    def select_source(self, source):
        """Select input source."""
        source_dict = self._source_list.get(source)
        if source_dict is None:
            _LOGGER.warning("Source %s not found for %s", source, self.name)
            return
        self._current_source_id = source_dict["id"]
        if source_dict.get("title"):
            self._current_source = source_dict["title"]
            self._client.launch_app(source_dict["id"])
        elif source_dict.get("label"):
            self._current_source = source_dict["label"]
            self._client.set_input(source_dict["id"])

    def play_media(self, media_type, media_id, **kwargs):
        """Play a piece of media."""
        _LOGGER.debug("Call play media type <%s>, Id <%s>", media_type,
                      media_id)

        if media_type == MEDIA_TYPE_CHANNEL:
            _LOGGER.debug("Searching channel...")
            partial_match_channel_id = None
            perfect_match_channel_id = None

            for channel in self._client.get_channels():
                if media_id == channel["channelNumber"]:
                    perfect_match_channel_id = channel["channelId"]
                    continue
                elif media_id.lower() == channel["channelName"].lower():
                    perfect_match_channel_id = channel["channelId"]
                    continue
                elif media_id.lower() in channel["channelName"].lower():
                    partial_match_channel_id = channel["channelId"]

            if perfect_match_channel_id is not None:
                _LOGGER.info(
                    "Switching to channel <%s> with perfect match",
                    perfect_match_channel_id,
                )
                self._client.set_channel(perfect_match_channel_id)
            elif partial_match_channel_id is not None:
                _LOGGER.info(
                    "Switching to channel <%s> with partial match",
                    partial_match_channel_id,
                )
                self._client.set_channel(partial_match_channel_id)

            return

    def media_play(self):
        """Send play command."""
        self._playing = True
        self._state = STATE_PLAYING
        self._client.play()

    def media_pause(self):
        """Send media pause command to media player."""
        self._playing = False
        self._state = STATE_PAUSED
        self._client.pause()

    def media_next_track(self):
        """Send next track command."""
        current_input = self._client.get_input()
        if current_input == LIVETV_APP_ID:
            self._client.channel_up()
        else:
            self._client.fast_forward()

    def media_previous_track(self):
        """Send the previous track command."""
        current_input = self._client.get_input()
        if current_input == LIVETV_APP_ID:
            self._client.channel_down()
        else:
            self._client.rewind()
예제 #13
0
class GenericHumidifierEntity(HumidifierEntity, RestoreEntity):
    def __init__(self, hass, config):
        self._hass = hass
        self._power = False
        self._humidity = 0
        self._mode = MODE_AUTO
        self._name = config.get(NAME_CONFIG, None)
        self._unique_id = config.get(UNIQUE_ID_CONFIG, None)
        self._boot_mode_tether = config.get(BOOT_MODE_TETHER_CONFIG, None)
        self._above_tolerance = float(config.get(ABOVE_TOLERANCE, 0))
        self._below_tolerance = float(config.get(BELOW_TOLERANCE, 0))
        self._first_cycle = True
        self._current_mode = None

        self._modes_script = dict()
        self._available_modes = []

        self.__init_modes_script(config)
        self._init_properties(dict())

        self._turn_off_action = config.get(OFF_ACTION, None)
        if self._turn_off_action:
            if isinstance(self._turn_off_action, list):
                self._turn_off_script = Script(self._hass,
                                               self._turn_off_action,
                                               self._unique_id, DOMAIN)
            else:
                self._turn_off_script = Script(self._hass,
                                               [self._turn_off_action],
                                               self._unique_id, DOMAIN)

        self._humidity_sensor = config.get(HUMIDITY_SENSOR, None)
        if self._humidity_sensor:
            async_track_state_change(self._hass, self._humidity_sensor,
                                     self._handle_humidity_state_update)

    def __init_modes_script(self, config):
        for mode in MODES:
            mode_action = config.get(mode, None)

            if not mode_action:
                continue

            if isinstance(mode_action, list):
                self._modes_script[mode] = Script(self._hass, mode_action,
                                                  self._unique_id, DOMAIN)
            else:
                self._modes_script[mode] = Script(self._hass, [mode_action],
                                                  self._unique_id, DOMAIN)

            self._available_modes.append(mode)

        if len(self._available_modes) > 1:
            self._supported_features = SUPPORT_MODES
        else:
            self._supported_features = 0

    def _handle_humidity_state_update(self, entity_id: str, old_state: State,
                                      new_state: State) -> None:
        self.__handle_mode()

    def __handle_mode(self):
        if not self.is_on:
            return

        sensor_state = self._hass.states.get(self._humidity_sensor)

        if not sensor_state or not sensor_state.state:
            return

        sensor_value = float(sensor_state.state)

        if self._first_cycle:
            if self.target_humidity <= sensor_value:
                self.__turn_off()
                return
        else:
            if not self._first_cycle and (
                    self.target_humidity +
                    self._above_tolerance) <= sensor_value:
                self.__turn_off()
                return
            if not self._first_cycle and (
                    self.target_humidity -
                    self._below_tolerance) <= sensor_value:
                return

        self._first_cycle = False

        if self.mode != MODE_AUTO:
            self.__turn_on_mode(self.mode)
        elif self.mode == MODE_AUTO and not self._boot_mode_tether:
            self.__turn_on_mode(MODE_AUTO)
        elif self.mode == MODE_AUTO and self._boot_mode_tether and MODE_BOOST in self._available_modes:
            if self.target_humidity - sensor_value > self._boot_mode_tether:
                self.__turn_on_mode(MODE_BOOST)
            else:
                self.__turn_on_mode(MODE_AUTO)

    def __turn_on_mode(self, mode):
        if mode == self._current_mode:
            return
        self._modes_script[mode].run()
        self._current_mode = mode

    def __turn_off(self):
        if not self._turn_off_script:
            return
        self._turn_off_script.run()
        self._current_mode = None

    @property
    def unique_id(self) -> Optional[str]:
        return self._unique_id

    @property
    def name(self) -> Optional[str]:
        return self._name

    @property
    def device_class(self) -> Optional[str]:
        return DEVICE_CLASS_HUMIDIFIER

    @property
    def is_on(self) -> bool:
        return self._power

    def turn_on(self, **kwargs: Any) -> None:
        self._power = True
        self._first_cycle = True
        self.__handle_mode()

    def turn_off(self, **kwargs: Any) -> None:
        self._power = False
        self.__turn_off()

    @property
    def target_humidity(self) -> Optional[int]:
        return self._humidity

    def set_humidity(self, humidity: int) -> None:
        self._first_cycle = True
        self._humidity = humidity
        self.__handle_mode()

    @property
    def available_modes(self) -> Optional[List[str]]:
        return self._available_modes

    @property
    def mode(self) -> Optional[str]:
        return self._mode

    def set_mode(self, mode: str) -> None:
        self._mode = mode
        self.__handle_mode()

    @property
    def supported_features(self) -> Optional[int]:
        return self._supported_features

    async def async_added_to_hass(self) -> None:
        last_state = await self.async_get_last_state()

        if not last_state:
            return

        last_state_dict = last_state.as_dict().get("attributes", dict())

        if last_state.state == 'off':
            last_state_dict["power"] = False
        else:
            last_state_dict["power"] = True

        self._init_properties(last_state_dict)

        await self.async_update_ha_state(True)

    def _init_properties(self, property_store):
        self._humidity = property_store.get("humidity", 0)
        self._mode = property_store.get("mode", MODE_AUTO)
        self._power = property_store.get("power", False)
예제 #14
0
class SwitchTemplate(SwitchDevice):
    """Representation of a Template switch."""
    def __init__(self, hass, device_id, friendly_name, state_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

        @callback
        def template_switch_state_listener(entity, old_state, new_state):
            """Called when the target device changes state."""
            hass.async_add_job(self.async_update_ha_state(True))

        async_track_state_change(hass, entity_ids,
                                 template_switch_state_listener)

    @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):
        """No polling needed."""
        return False

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

    def turn_on(self, **kwargs):
        """Fire the on action."""
        self._on_script.run()

    def turn_off(self, **kwargs):
        """Fire the off action."""
        self._off_script.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
예제 #15
0
class SwitchTemplate(SwitchDevice):
    """Representation of a Template switch."""

    def __init__(self, hass, device_id, friendly_name, state_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._entities = entity_ids

    @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._state = state.state == STATE_ON

        @callback
        def template_switch_state_listener(entity, old_state, new_state):
            """Called when the target device changes state."""
            self.hass.async_add_job(self.async_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.hass.async_add_job(self.async_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):
        """No polling needed."""
        return False

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

    def turn_on(self, **kwargs):
        """Fire the on action."""
        self._on_script.run()

    def turn_off(self, **kwargs):
        """Fire the off action."""
        self._off_script.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
예제 #16
0
class WolSwitch(SwitchEntity):
    """Representation of a wake on lan switch."""
    def __init__(
        self,
        hass,
        name,
        host,
        mac_address,
        off_action,
        broadcast_address,
        broadcast_port,
    ):
        """Initialize the WOL switch."""
        self._hass = hass
        self._name = name
        self._host = host
        self._mac_address = mac_address
        self._broadcast_address = broadcast_address
        self._broadcast_port = broadcast_port
        self._off_script = Script(hass, off_action) if off_action else None
        self._state = False

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

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

    def turn_on(self, **kwargs):
        """Turn the device on."""
        service_kwargs = {}
        if self._broadcast_address is not None:
            service_kwargs["ip_address"] = self._broadcast_address
        if self._broadcast_port is not None:
            service_kwargs["port"] = self._broadcast_port

        _LOGGER.info(
            "Send magic packet to mac %s (broadcast: %s, port: %s)",
            self._mac_address,
            self._broadcast_address,
            self._broadcast_port,
        )

        wakeonlan.send_magic_packet(self._mac_address, **service_kwargs)

    def turn_off(self, **kwargs):
        """Turn the device off if an off action is present."""
        if self._off_script is not None:
            self._off_script.run()

    def update(self):
        """Check if device is on and update the state."""
        if platform.system().lower() == "windows":
            ping_cmd = [
                "ping",
                "-n",
                "1",
                "-w",
                str(DEFAULT_PING_TIMEOUT * 1000),
                str(self._host),
            ]
        else:
            ping_cmd = [
                "ping",
                "-c",
                "1",
                "-W",
                str(DEFAULT_PING_TIMEOUT),
                str(self._host),
            ]

        status = sp.call(ping_cmd, stdout=sp.DEVNULL, stderr=sp.DEVNULL)
        self._state = not bool(status)
예제 #17
0
class SwitchTemplate(SwitchDevice):
    """Representation of a Template switch."""

    def __init__(self, hass, device_id, friendly_name, state_template,
                 icon_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._icon = None
        self._entities = entity_ids

    @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._state = state.state == STATE_ON

        @callback
        def template_switch_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_switch_startup(event):
            """Update template on startup."""
            async_track_state_change(
                self.hass, self._entities, template_switch_state_listener)

            self.hass.async_add_job(self.async_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

    def turn_on(self, **kwargs):
        """Fire the on action."""
        self._on_script.run()

    def turn_off(self, **kwargs):
        """Fire the off action."""
        self._off_script.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

        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)
예제 #18
0
class SwitchTemplate(SwitchDevice):
    """Representation of a Template switch."""

    # pylint: disable=too-many-arguments
    def __init__(self, hass, device_id, friendly_name, state_template,
                 on_action, off_action, entity_ids):
        """Initialize the Template switch."""
        self.hass = hass
        self.entity_id = 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.update()

        def template_switch_state_listener(entity, old_state, new_state):
            """Called when the target device changes state."""
            self.update_ha_state(True)

        track_state_change(hass, entity_ids, template_switch_state_listener)

    @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):
        """No polling needed."""
        return False

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

    def turn_on(self, **kwargs):
        """Fire the on action."""
        self._on_script.run()

    def turn_off(self, **kwargs):
        """Fire the off action."""
        self._off_script.run()

    def update(self):
        """Update the state from the template."""
        try:
            state = template.render(self.hass, self._template).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
예제 #19
0
class LgWebOSDevice(MediaPlayerDevice):
    """Representation of a LG WebOS TV."""
    def __init__(self, host, name, customize, config, timeout, hass,
                 on_action):
        """Initialize the webos device."""
        from pylgtv import WebOsClient
        self._client = WebOsClient(host, config, timeout)
        self._on_script = Script(hass, on_action) if on_action else None
        self._customize = customize

        self._name = name
        # Assume that the TV is not muted
        self._muted = False
        # Assume that the TV is in Play mode
        self._playing = True
        self._volume = 0
        self._current_source = None
        self._current_source_id = None
        self._state = STATE_UNKNOWN
        self._source_list = {}
        self._app_list = {}
        self._channel = None

    @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS)
    def update(self):
        """Retrieve the latest data."""
        from websockets.exceptions import ConnectionClosed
        try:
            current_input = self._client.get_input()
            if current_input is not None:
                self._current_source_id = current_input
                if self._state in (STATE_UNKNOWN, STATE_OFF):
                    self._state = STATE_PLAYING
            else:
                self._state = STATE_OFF
                self._current_source = None
                self._current_source_id = None
                self._channel = None

            if self._state is not STATE_OFF:
                self._muted = self._client.get_muted()
                self._volume = self._client.get_volume()
                self._channel = self._client.get_current_channel()

                self._source_list = {}
                self._app_list = {}
                conf_sources = self._customize.get(CONF_SOURCES, [])

                for app in self._client.get_apps():
                    self._app_list[app['id']] = app
                    if app['id'] == self._current_source_id:
                        self._current_source = app['title']
                        self._source_list[app['title']] = app
                    elif (not conf_sources or app['id'] in conf_sources
                          or any(word in app['title'] for word in conf_sources)
                          or any(word in app['id'] for word in conf_sources)):
                        self._source_list[app['title']] = app

                for source in self._client.get_inputs():
                    if source['id'] == self._current_source_id:
                        self._current_source = source['label']
                        self._source_list[source['label']] = source
                    elif (not conf_sources or source['label'] in conf_sources
                          or any(source['label'].find(word) != -1
                                 for word in conf_sources)):
                        self._source_list[source['label']] = source
        except (OSError, ConnectionClosed, TypeError, asyncio.TimeoutError):
            self._state = STATE_OFF
            self._current_source = None
            self._current_source_id = None
            self._channel = None

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

    @property
    def state(self):
        """Return the state of the device."""
        return self._state

    @property
    def is_volume_muted(self):
        """Boolean if volume is currently muted."""
        return self._muted

    @property
    def volume_level(self):
        """Volume level of the media player (0..1)."""
        return self._volume / 100.0

    @property
    def source(self):
        """Return the current input source."""
        return self._current_source

    @property
    def source_list(self):
        """List of available input sources."""
        return sorted(self._source_list.keys())

    @property
    def media_content_type(self):
        """Content type of current playing media."""
        return MEDIA_TYPE_CHANNEL

    @property
    def media_title(self):
        """Title of current playing media."""
        if (self._channel is not None) and ('channelName' in self._channel):
            return self._channel['channelName']
        return None

    @property
    def media_image_url(self):
        """Image url of current playing media."""
        if self._current_source_id in self._app_list:
            icon = self._app_list[self._current_source_id]['largeIcon']
            if not icon.startswith('http'):
                icon = self._app_list[self._current_source_id]['icon']
            return icon
        return None

    @property
    def supported_features(self):
        """Flag media player features that are supported."""
        if self._on_script:
            return SUPPORT_WEBOSTV | SUPPORT_TURN_ON
        return SUPPORT_WEBOSTV

    def turn_off(self):
        """Turn off media player."""
        from websockets.exceptions import ConnectionClosed
        self._state = STATE_OFF
        try:
            self._client.power_off()
        except (OSError, ConnectionClosed, TypeError, asyncio.TimeoutError):
            pass

    def turn_on(self):
        """Turn on the media player."""
        if self._on_script:
            self._on_script.run()

    def volume_up(self):
        """Volume up the media player."""
        self._client.volume_up()

    def volume_down(self):
        """Volume down media player."""
        self._client.volume_down()

    def set_volume_level(self, volume):
        """Set volume level, range 0..1."""
        tv_volume = volume * 100
        self._client.set_volume(tv_volume)

    def mute_volume(self, mute):
        """Send mute command."""
        self._muted = mute
        self._client.set_mute(mute)

    def media_play_pause(self):
        """Simulate play pause media player."""
        if self._playing:
            self.media_pause()
        else:
            self.media_play()

    def select_source(self, source):
        """Select input source."""
        source_dict = self._source_list.get(source)
        if source_dict is None:
            _LOGGER.warning("Source %s not found for %s", source, self.name)
            return
        self._current_source_id = source_dict['id']
        if source_dict.get('title'):
            self._current_source = source_dict['title']
            self._client.launch_app(source_dict['id'])
        elif source_dict.get('label'):
            self._current_source = source_dict['label']
            self._client.set_input(source_dict['id'])

    def media_play(self):
        """Send play command."""
        self._playing = True
        self._state = STATE_PLAYING
        self._client.play()

    def media_pause(self):
        """Send media pause command to media player."""
        self._playing = False
        self._state = STATE_PAUSED
        self._client.pause()

    def media_next_track(self):
        """Send next track command."""
        self._client.fast_forward()

    def media_previous_track(self):
        """Send the previous track command."""
        self._client.rewind()
예제 #20
0
class SwitchTemplate(SwitchDevice):
    """Representation of a Template switch."""
    def __init__(self, hass, device_id, friendly_name, state_template,
                 icon_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._icon = None
        self._entities = entity_ids

    @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._state = state.state == STATE_ON

        @callback
        def template_switch_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_switch_startup(event):
            """Update template on startup."""
            async_track_state_change(self.hass, self._entities,
                                     template_switch_state_listener)

            self.hass.async_add_job(self.async_update_ha_state(True))

        if self._template:
            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 assumed_state(self):
        """Return true if we do internal state tracking."""
        return self._template is None

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

    def turn_on(self, **kwargs):
        """Fire the on action."""
        self._on_script.run()

        if not self._template:
            self._state = True
            self.schedule_update_ha_state()

    def turn_off(self, **kwargs):
        """Fire the off action."""
        self._off_script.run()

        if not self._template:
            self._state = False
            self.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()

                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

        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)