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