diff --git a/homeassistant/components/sensor/lirc.py b/homeassistant/components/sensor/lirc.py new file mode 100644 index 000000000000..e3096fd8762e --- /dev/null +++ b/homeassistant/components/sensor/lirc.py @@ -0,0 +1,109 @@ +""" +LIRC interface to receive signals from a infrared remote control. + +This sensor will momentarily set state to various values as defined +in the .lintrc file which can be interpreted in home-assistant to +trigger various actions. + +Sending signals to other IR receivers can be accomplished with the +shell_command component and the irsend command. +""" + +import threading +import time +import logging + +from homeassistant.helpers.entity import Entity +from homeassistant.const import EVENT_HOMEASSISTANT_STOP + +LIRC = None + +REQUIREMENTS = ['python-lirc==1.2.1'] +_LOGGER = logging.getLogger(__name__) +ICON = 'mdi:remote' + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Setup LIRC capability.""" + # Perform safe import of third-party python-lirc module + try: + import lirc + global LIRC + LIRC = lirc + except ImportError: + _LOGGER.error("You are missing a required dependency: python-lirc.") + return False + + LIRC.init('home-assistant', blocking=False) + sensor = LircSensor() + add_devices([sensor]) + + hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, sensor.stop) + + +class LircSensor(Entity): + """Sensor entity for LIRC.""" + + def __init__(self, *args, **kwargs): + """Contruct a LircSensor entity.""" + _LOGGER.info('Initializing LIRC sensor') + Entity.__init__(self, *args, **kwargs) + self.last_key_pressed = '' + self._lirc_interface = LircInterface(self) + self._lirc_interface.start() + + @property + def name(self): + """Name of lirc sensor.""" + return 'lirc' + + @property + def state(self): + """State of LIRC sensor.""" + return self.last_key_pressed + + def update_state(self, new_state): + """Inform system of update when they occur.""" + self.last_key_pressed = new_state + self.update_ha_state() + + def stop(self, event): + """Kill the helper thread on stop.""" + _LOGGER.info('Ending LIRC interface thread') + self._lirc_interface.stopped.set() + + +class LircInterface(threading.Thread): + """ + This interfaces with the lirc daemon to read IR commands. + + When using lirc in blocking mode, sometimes repeated commands get produced + in the next read of a command so we use a thread here to just wait + around until a non-empty response is obtained from lirc. + """ + + def __init__(self, parent): + """Construct a LIRC interface object.""" + threading.Thread.__init__(self) + self.stopped = threading.Event() + self._parent = parent + + def run(self): + """Main loop of LIRC interface thread.""" + while not self.stopped.isSet(): + code = LIRC.nextcode() # list; empty if no buttons pressed + + # interpret result from python-lirc + if code: + code = code[0] + else: + code = '' + + # update if changed. + if code != self._parent.state: + _LOGGER.info('Got new LIRC code %s', code) + self._parent.update_state(code) + else: + time.sleep(0.1) # avoid high CPU in this thread + + _LOGGER.info('LIRC interface thread stopped') diff --git a/requirements_all.txt b/requirements_all.txt index 92c9b735b2c9..bca754e110e2 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -262,6 +262,9 @@ pysnmp==4.2.5 # homeassistant.components.sensor.forecast python-forecastio==1.3.4 +# homeassistant.components.sensor.lirc +python-lirc==1.2.1 + # homeassistant.components.media_player.mpd python-mpd2==0.5.5