diff --git a/homeassistant/components/pilight.py b/homeassistant/components/pilight.py index 2cfbc0063a1d69e41be712955819e2df649fbc62..de4e56c925f46e88583a0c960b790f7bd7909bba 100644 --- a/homeassistant/components/pilight.py +++ b/homeassistant/components/pilight.py @@ -1,5 +1,5 @@ """ -Component to create an interface to a Pilight daemon (https://pilight.org/). +Component to create an interface to a Pilight daemon. For more details about this component, please refer to the documentation at https://home-assistant.io/components/pilight/ @@ -12,40 +12,38 @@ import voluptuous as vol import homeassistant.helpers.config_validation as cv from homeassistant.const import ( EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP, CONF_HOST, CONF_PORT, - CONF_WHITELIST) + CONF_WHITELIST, CONF_PROTOCOL) REQUIREMENTS = ['pilight==0.1.1'] _LOGGER = logging.getLogger(__name__) -ATTR_PROTOCOL = 'protocol' - DEFAULT_HOST = '127.0.0.1' DEFAULT_PORT = 5000 DOMAIN = 'pilight' EVENT = 'pilight_received' -# The pilight code schema depends on the protocol -# Thus only require to have the protocol information -# Ensure that protocol is in a list otherwise segfault in pilight-daemon -# https://github.com/pilight/pilight/issues/296 -RF_CODE_SCHEMA = vol.Schema({vol.Required(ATTR_PROTOCOL): - vol.All(cv.ensure_list, [cv.string])}, - extra=vol.ALLOW_EXTRA) +# The Pilight code schema depends on the protocol. Thus only require to have +# the protocol information. Ensure that protocol is in a list otherwise +# segfault in pilight-daemon, https://github.com/pilight/pilight/issues/296 +RF_CODE_SCHEMA = vol.Schema({ + vol.Required(CONF_PROTOCOL): vol.All(cv.ensure_list, [cv.string]), +}, extra=vol.ALLOW_EXTRA) + SERVICE_NAME = 'send' CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({ - vol.Required(CONF_HOST, default=DEFAULT_HOST): cv.string, - vol.Required(CONF_PORT, default=DEFAULT_PORT): cv.port, + vol.Optional(CONF_HOST, default=DEFAULT_HOST): cv.string, + vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, vol.Optional(CONF_WHITELIST, default={}): {cv.string: [cv.string]} }), }, extra=vol.ALLOW_EXTRA) def setup(hass, config): - """Setup the pilight component.""" + """Setup the Pilight component.""" from pilight import pilight host = config[DOMAIN][CONF_HOST] @@ -58,23 +56,22 @@ def setup(hass, config): host, port, err) return False - # Start / stop pilight-daemon connection with HA start/stop def start_pilight_client(_): - """Called once when home assistant starts.""" + """Called once when Home Assistant starts.""" pilight_client.start() hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_pilight_client) def stop_pilight_client(_): - """Called once when home assistant stops.""" + """Called once when Home Assistant stops.""" pilight_client.stop() hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_pilight_client) def send_code(call): """Send RF code to the pilight-daemon.""" - # Change type to dict from mappingproxy - # since data has to be JSON serializable + # Change type to dict from mappingproxy since data has to be JSON + # serializable message_data = dict(call.data) try: @@ -82,8 +79,8 @@ def setup(hass, config): except IOError: _LOGGER.error('Pilight send failed for %s', str(message_data)) - hass.services.register(DOMAIN, SERVICE_NAME, - send_code, schema=RF_CODE_SCHEMA) + hass.services.register( + DOMAIN, SERVICE_NAME, send_code, schema=RF_CODE_SCHEMA) # Publish received codes on the HA event bus # A whitelist of codes to be published in the event bus @@ -93,10 +90,8 @@ def setup(hass, config): """Called when RF codes are received.""" # Unravel dict of dicts to make event_data cut in automation rule # possible - data = dict( - {'protocol': data['protocol'], - 'uuid': data['uuid']}, - **data['message']) + data = dict({'protocol': data['protocol'], 'uuid': data['uuid']}, + **data['message']) # No whitelist defined, put data on event bus if not whitelist: diff --git a/homeassistant/components/sensor/pilight.py b/homeassistant/components/sensor/pilight.py index 0266862d529715207953c187c86d23b16d655f35..8a403b4adbfcf09f7e0df01e3c937b913689ad56 100644 --- a/homeassistant/components/sensor/pilight.py +++ b/homeassistant/components/sensor/pilight.py @@ -1,5 +1,5 @@ """ -Support for pilight sensors. +Support for Pilight sensors. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/sensor.pilight/ @@ -9,8 +9,7 @@ import logging import voluptuous as vol from homeassistant.const import ( - CONF_NAME, STATE_UNKNOWN, CONF_UNIT_OF_MEASUREMENT, - CONF_PAYLOAD) + CONF_NAME, STATE_UNKNOWN, CONF_UNIT_OF_MEASUREMENT, CONF_PAYLOAD) from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.helpers.entity import Entity import homeassistant.components.pilight as pilight @@ -18,11 +17,13 @@ import homeassistant.helpers.config_validation as cv _LOGGER = logging.getLogger(__name__) +CONF_VARIABLE = 'variable' + DEFAULT_NAME = 'Pilight Sensor' DEPENDENCIES = ['pilight'] PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Required("variable"): cv.string, + vol.Required(CONF_VARIABLE): cv.string, vol.Required(CONF_PAYLOAD): vol.Schema(dict), vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_UNIT_OF_MEASUREMENT, default=None): cv.string, @@ -31,18 +32,18 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ # pylint: disable=unused-argument def setup_platform(hass, config, add_devices, discovery_info=None): - """Setup pilight Sensor.""" + """Set up Pilight Sensor.""" add_devices([PilightSensor( hass=hass, name=config.get(CONF_NAME), - variable=config.get("variable"), + variable=config.get(CONF_VARIABLE), payload=config.get(CONF_PAYLOAD), unit_of_measurement=config.get(CONF_UNIT_OF_MEASUREMENT) )]) class PilightSensor(Entity): - """Representation of a sensor that can be updated using pilight.""" + """Representation of a sensor that can be updated using Pilight.""" def __init__(self, hass, name, variable, payload, unit_of_measurement): """Initialize the sensor.""" diff --git a/homeassistant/components/switch/pilight.py b/homeassistant/components/switch/pilight.py index c143ae5c887875d7d96e1e4c3d578ec80f55ef1b..1818372f1dc6b5bd649cc8c170ecc687e50c6b08 100644 --- a/homeassistant/components/switch/pilight.py +++ b/homeassistant/components/switch/pilight.py @@ -1,44 +1,77 @@ """ -Support for switching devices via pilight to on and off. +Support for switching devices via Pilight to on and off. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/switch.pilight/ """ import logging -from homeassistant.helpers.config_validation import ensure_list -import homeassistant.components.pilight as pilight -from homeassistant.components.switch import SwitchDevice +import voluptuous as vol -DEPENDENCIES = ['pilight'] +import homeassistant.helpers.config_validation as cv +import homeassistant.components.pilight as pilight +from homeassistant.components.switch import (SwitchDevice, PLATFORM_SCHEMA) +from homeassistant.const import (CONF_NAME, CONF_ID, CONF_SWITCHES, CONF_STATE) _LOGGER = logging.getLogger(__name__) +CONF_OFF_CODE = 'off_code' +CONF_OFF_CODE_RECIEVE = 'off_code_receive' +CONF_ON_CODE = 'on_code' +CONF_ON_CODE_RECIEVE = 'on_code_receive' +CONF_SYSTEMCODE = 'systemcode' +CONF_UNIT = 'unit' + +DEPENDENCIES = ['pilight'] -def setup_platform(hass, config, add_devices_callback, discovery_info=None): - """Setup the pilight platform.""" - # Find and return switches controlled by pilight - switches = config.get('switches', {}) +COMMAND_SCHEMA = pilight.RF_CODE_SCHEMA.extend({ + vol.Optional('on'): cv.positive_int, + vol.Optional('off'): cv.positive_int, + vol.Optional(CONF_UNIT): cv.string, + vol.Optional(CONF_ID): cv.positive_int, + vol.Optional(CONF_STATE): cv.string, + vol.Optional(CONF_SYSTEMCODE): cv.string, +}) + +SWITCHES_SCHEMA = vol.Schema({ + vol.Required(CONF_ON_CODE): COMMAND_SCHEMA, + vol.Required(CONF_OFF_CODE): COMMAND_SCHEMA, + vol.Optional(CONF_NAME): cv.string, + vol.Optional(CONF_OFF_CODE_RECIEVE): COMMAND_SCHEMA, + vol.Optional(CONF_ON_CODE_RECIEVE): COMMAND_SCHEMA, +}) + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_SWITCHES): + vol.Schema({cv.string: SWITCHES_SCHEMA}), +}) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Set up the Pilight platform.""" + switches = config.get(CONF_SWITCHES) devices = [] for dev_name, properties in switches.items(): devices.append( PilightSwitch( hass, - properties.get('name', dev_name), - properties.get('on_code'), - properties.get('off_code'), - ensure_list(properties.get('on_code_receive', False)), - ensure_list(properties.get('off_code_receive', False)))) + properties.get(CONF_NAME, dev_name), + properties.get(CONF_ON_CODE), + properties.get(CONF_OFF_CODE), + properties.get(CONF_ON_CODE_RECIEVE), + properties.get(CONF_OFF_CODE_RECIEVE) + ) + ) - add_devices_callback(devices) + add_devices(devices) class PilightSwitch(SwitchDevice): - """Representation of a pilight switch.""" + """Representation of a Pilight switch.""" - def __init__(self, hass, name, code_on, code_off, - code_on_receive, code_off_receive): + def __init__(self, hass, name, code_on, code_off, code_on_receive, + code_off_receive): """Initialize the switch.""" self._hass = hass self._name = name @@ -69,29 +102,22 @@ class PilightSwitch(SwitchDevice): def _handle_code(self, call): """Check if received code by the pilight-daemon. - If the code matches the receive on / off codes of this switch - the switch state is changed accordingly. + If the code matches the receive on/off codes of this switch the switch + state is changed accordingly. """ - # Check if a on code is defined to turn this switch on + # - True if off_code/on_code is contained in received code dict, not + # all items have to match. + # - Call turn on/off only once, even if more than one code is received if any(self._code_on_receive): - for on_code in self._code_on_receive: # Loop through codes - # True if on_code is contained in received code dict, not - # all items have to match + for on_code in self._code_on_receive: if on_code.items() <= call.data.items(): self.turn_on() - # Call turn on only once, even when more than one on - # code is received break - # Check if a off code is defined to turn this switch off if any(self._code_off_receive): - for off_code in self._code_off_receive: # Loop through codes - # True if off_code is contained in received code dict, not - # all items have to match + for off_code in self._code_off_receive: if off_code.items() <= call.data.items(): self.turn_off() - # Call turn off only once, even when more than one off - # code is received break def turn_on(self): diff --git a/homeassistant/const.py b/homeassistant/const.py index 69c340db3db0f277c8e12b572a6f7d777573ed41..fcba511fe1053d673a3992950898470a0b12453b 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -114,6 +114,7 @@ CONF_PIN = 'pin' CONF_PLATFORM = 'platform' CONF_PORT = 'port' CONF_PREFIX = 'prefix' +CONF_PROTOCOL = 'protocol' CONF_QUOTE = 'quote' CONF_RECIPIENT = 'recipient' CONF_RESOURCE = 'resource' diff --git a/tests/components/sensor/test_pilight.py b/tests/components/sensor/test_pilight.py index 08e174df4cc07e04c5114bf2e33716dda965db7b..943369f209cd85c1fa16abc2c1c07d36943a4353 100644 --- a/tests/components/sensor/test_pilight.py +++ b/tests/components/sensor/test_pilight.py @@ -11,8 +11,8 @@ HASS = None def fire_pilight_message(protocol, data): - """Fire the fake pilight message.""" - message = {pilight.ATTR_PROTOCOL: protocol} + """Fire the fake Pilight message.""" + message = {pilight.CONF_PROTOCOL: protocol} message.update(data) HASS.bus.fire(pilight.EVENT, message) @@ -67,23 +67,23 @@ def test_disregard_wrong_payload(): 'platform': 'pilight', 'name': 'test_2', 'variable': 'test', - 'payload': {'uuid': '1-2-3-4', - 'protocol': 'test-protocol_2'} + 'payload': { + 'uuid': '1-2-3-4', + 'protocol': 'test-protocol_2' + } } }) # Try set value from data with incorrect payload fire_pilight_message(protocol='test-protocol_2', - data={'test': 'data', - 'uuid': '0-0-0-0'}) + data={'test': 'data', 'uuid': '0-0-0-0'}) HASS.block_till_done() state = HASS.states.get('sensor.test_2') assert state.state == 'unknown' # Try set value from data with partially matched payload fire_pilight_message(protocol='wrong-protocol', - data={'test': 'data', - 'uuid': '1-2-3-4'}) + data={'test': 'data', 'uuid': '1-2-3-4'}) HASS.block_till_done() state = HASS.states.get('sensor.test_2') assert state.state == 'unknown' @@ -113,8 +113,7 @@ def test_variable_missing(caplog): # Create code without sensor variable fire_pilight_message(protocol='test-protocol', - data={'uuid': '1-2-3-4', - 'other_variable': 3.141}) + data={'uuid': '1-2-3-4', 'other_variable': 3.141}) HASS.block_till_done() logs = caplog.text