Anonym-tsk / home-assistant-components

Custom components for Home Assistant
29 stars 5 forks source link

Remote IR switch #8

Open CooleRnax opened 5 years ago

CooleRnax commented 5 years ago

Wanted to share my work, ir switch with template or ping. I use it mainly for TV.

import asyncio
from functools import partial
import logging
import time
import datetime

import voluptuous as vol

from homeassistant.components.switch import (SwitchDevice, PLATFORM_SCHEMA)
from homeassistant.components.binary_sensor.ping import (PingData)
from homeassistant.components.remote import (
    ATTR_COMMAND, DOMAIN, SERVICE_SEND_COMMAND)
from homeassistant.const import (
    ATTR_ENTITY_ID, CONF_HOST, CONF_NAME, CONF_TOKEN, STATE_OFF, STATE_ON)
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.util import Throttle
from homeassistant.helpers.event import async_track_state_change
from homeassistant.core import callback
from homeassistant.exceptions import TemplateError

DEPENDENCIES = ['remote']

_LOGGER = logging.getLogger(__name__)

DEFAULT_NAME = 'IR Switch'

CONF_REMOTE = 'remote'
CONF_PING = 'ping'
CONF_POWER_TEMPLATE = 'power_template'
CONF_COMMANDS = 'commands'

COMMAND_TURN_OFF = 'turn_off'
COMMAND_TURN_ON = 'turn_on'

COMMANDS_SCHEMA = vol.Schema({
    vol.Required(COMMAND_TURN_OFF): cv.string,
    vol.Required(COMMAND_TURN_ON): cv.string,
}, extra=vol.ALLOW_EXTRA)

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
    vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
    vol.Required(CONF_REMOTE): cv.entity_id,
    vol.Optional(CONF_PING): cv.string,
    vol.Optional(CONF_POWER_TEMPLATE): cv.template,
    vol.Required(CONF_COMMANDS): COMMANDS_SCHEMA
})

MIN_TIME_BETWEEN_UPDATES = datetime.timedelta(seconds=10)

async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
    """Set up the xiaomi remote climate platform."""
    name = config.get(CONF_NAME)
    remote_entity_id = config.get(CONF_REMOTE)

    ping = config.get(CONF_PING)
    power_template = config.get(CONF_POWER_TEMPLATE)

    commands = config.get(CONF_COMMANDS)

    if ping:
        async_add_entities([
            RemoteSwitch(hass, name, remote_entity_id, commands, power_template, PingData(ping, 1))
        ])
    else:
        async_add_entities([
            RemoteSwitch(hass, name, remote_entity_id, commands, power_template, ping)
        ])

class RemoteSwitch(SwitchDevice, RestoreEntity):
    def __init__(self, hass, name, remote_entity_id, commands, power_template, ping):
        self.hass = hass
        self._name = name

        self._remote_entity_id = remote_entity_id
        self._commands = commands

        self._state = None

        self._skip_update = False

        self._power_template = power_template
        if power_template:
            self._power_template.hass = hass

        self._ping = ping

        # if power_template:
        #     power_template.hass = hass
        #     power_entity_ids = power_template.extract_entities()
        #     async_track_state_change(hass, power_entity_ids, self._async_power_changed)

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

    @property
    def is_on(self):
        if self._ping:
            return self._ping.available
        else:
            return self._state

    @property
    def available(self) -> bool:
        return True

    def _send_command(self, command_name):
        if command_name in self._commands:
            command = self._commands[command_name]
            if command is not None:
                self.hass.services.call(DOMAIN, SERVICE_SEND_COMMAND, {
                    ATTR_COMMAND: 'raw:' + command,
                    ATTR_ENTITY_ID: self._remote_entity_id
                })

    def turn_on(self):
        if not self.is_on:
            self._send_command('turn_on')
            self._state = True
            if self._ping:
                self._ping.available = True
            self._skip_update = True
            self.schedule_update_ha_state()

    def turn_off(self):
        if self.is_on:
            self._send_command('turn_off')
            self._state = False
            if self._ping:
                self._ping.available = False
            self._skip_update = True
            self.schedule_update_ha_state()

    @callback
    def _async_update_power(self):
        try:
            if self._power_template.async_render().lower() not in ('true', 'on', '1'):
                self._state = False
            else:
                self._state = True
        except TemplateError as ex:
            _LOGGER.warning('Unable to update power from template: %s', ex)

    @Throttle(MIN_TIME_BETWEEN_UPDATES)
    async def async_update(self):
        if self._skip_update:
            self._skip_update = False
            return

        if self._ping:
            self._ping.update()
        elif self._power_template:
            self._async_update_power()

Here you can find ir codes example: https://www.dropbox.com/s/texllwcvx3sxnqe/ir_remote_codes.rar?dl=0&file_subpath=%2Fir_remote_codes%2Fswitch

thundergreen commented 5 years ago

@CooleRnax do you think you would be able to create a media_player custom component here? Would like to have those for some devices.