core/homeassistant/components/pilight/switch.py

197 lines
6.5 KiB
Python
Raw Normal View History

"""
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
import voluptuous as vol
import homeassistant.helpers.config_validation as cv
from homeassistant.components import pilight
from homeassistant.components.switch import (SwitchDevice, PLATFORM_SCHEMA)
from homeassistant.const import (CONF_NAME, CONF_ID, CONF_SWITCHES, CONF_STATE,
CONF_PROTOCOL, STATE_ON)
from homeassistant.helpers.restore_state import RestoreEntity
_LOGGER = logging.getLogger(__name__)
CONF_OFF_CODE = 'off_code'
CONF_OFF_CODE_RECEIVE = 'off_code_receive'
CONF_ON_CODE = 'on_code'
CONF_ON_CODE_RECEIVE = 'on_code_receive'
CONF_SYSTEMCODE = 'systemcode'
CONF_UNIT = 'unit'
CONF_UNITCODE = 'unitcode'
CONF_ECHO = 'echo'
DEPENDENCIES = ['pilight']
COMMAND_SCHEMA = vol.Schema({
vol.Optional(CONF_PROTOCOL): cv.string,
vol.Optional('on'): cv.positive_int,
vol.Optional('off'): cv.positive_int,
vol.Optional(CONF_UNIT): cv.positive_int,
vol.Optional(CONF_UNITCODE): cv.positive_int,
vol.Optional(CONF_ID): vol.Any(cv.positive_int, cv.string),
vol.Optional(CONF_STATE): cv.string,
vol.Optional(CONF_SYSTEMCODE): cv.positive_int,
2016-12-12 01:38:33 +00:00
}, extra=vol.ALLOW_EXTRA)
RECEIVE_SCHEMA = COMMAND_SCHEMA.extend({
vol.Optional(CONF_ECHO): cv.boolean
})
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_RECEIVE, default=[]): vol.All(cv.ensure_list,
2016-11-07 07:34:32 +00:00
[COMMAND_SCHEMA]),
vol.Optional(CONF_ON_CODE_RECEIVE, default=[]): vol.All(cv.ensure_list,
2016-11-07 07:34:32 +00:00
[COMMAND_SCHEMA])
})
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_SWITCHES):
vol.Schema({cv.string: SWITCHES_SCHEMA}),
})
def setup_platform(hass, config, add_entities, 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(CONF_NAME, dev_name),
properties.get(CONF_ON_CODE),
properties.get(CONF_OFF_CODE),
properties.get(CONF_ON_CODE_RECEIVE),
properties.get(CONF_OFF_CODE_RECEIVE)
)
)
add_entities(devices)
class _ReceiveHandle:
def __init__(self, config, echo):
"""Initialize the handle."""
self.config_items = config.items()
self.echo = echo
def match(self, code):
"""Test if the received code matches the configured values.
The received values have to be a subset of the configured options.
"""
return self.config_items <= code.items()
def run(self, switch, turn_on):
"""Change the state of the switch."""
switch.set_state(turn_on=turn_on, send_code=self.echo)
class PilightSwitch(SwitchDevice, RestoreEntity):
"""Representation of a Pilight switch."""
def __init__(self, hass, name, code_on, code_off, code_on_receive,
code_off_receive):
"""Initialize the switch."""
self._hass = hass
self._name = name
self._state = False
self._code_on = code_on
self._code_off = code_off
self._code_on_receive = []
self._code_off_receive = []
for code_list, conf in ((self._code_on_receive, code_on_receive),
(self._code_off_receive, code_off_receive)):
for code in conf:
echo = code.pop(CONF_ECHO, True)
code_list.append(_ReceiveHandle(code, echo))
if any(self._code_on_receive) or any(self._code_off_receive):
hass.bus.listen(pilight.EVENT, self._handle_code)
async def async_added_to_hass(self):
"""Call when entity about to be added to hass."""
await super().async_added_to_hass()
state = await self.async_get_last_state()
if state:
self._state = state.state == STATE_ON
@property
def name(self):
"""Get the name of the switch."""
return self._name
@property
def should_poll(self):
"""No polling needed, state set when correct code is received."""
return False
@property
def assumed_state(self):
"""Return True if unable to access real state of the entity."""
return True
@property
def is_on(self):
"""Return true if switch is on."""
return self._state
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.
"""
# - 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:
if on_code.match(call.data):
on_code.run(switch=self, turn_on=True)
break
if any(self._code_off_receive):
for off_code in self._code_off_receive:
if off_code.match(call.data):
off_code.run(switch=self, turn_on=False)
break
def set_state(self, turn_on, send_code=True):
"""Set the state of the switch.
This sets the state of the switch. If send_code is set to True, then
it will call the pilight.send service to actually send the codes
to the pilight daemon.
"""
if send_code:
if turn_on:
self._hass.services.call(pilight.DOMAIN, pilight.SERVICE_NAME,
self._code_on, blocking=True)
else:
self._hass.services.call(pilight.DOMAIN, pilight.SERVICE_NAME,
self._code_off, blocking=True)
self._state = turn_on
self.schedule_update_ha_state()
def turn_on(self, **kwargs):
"""Turn the switch on by calling pilight.send service with on code."""
self.set_state(turn_on=True)
def turn_off(self, **kwargs):
"""Turn the switch on by calling pilight.send service with off code."""
self.set_state(turn_on=False)