8000 Cover component for RFlink by passie · Pull Request #9432 · home-assistant/core · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Cover component for RFlink #9432

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Sep 28, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 116 additions & 0 deletions homeassistant/components/cover/rflink.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
"""
Support for Rflink Cover devices.

For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/cover.rflink/
"""
import asyncio
import logging

import voluptuous as vol

from homeassistant.components.rflink import (
DATA_ENTITY_GROUP_LOOKUP, DATA_ENTITY_LOOKUP,
DEVICE_DEFAULTS_SCHEMA, EVENT_KEY_COMMAND, RflinkCommand)
from homeassistant.components.cover import (
CoverDevice, PLATFORM_SCHEMA)
import homeassistant.helpers.config_validation as cv
from homeassistant.const import CONF_NAME


DEPENDENCIES = ['rflink']

_LOGGER = logging.getLogger(__name__)


CONF_ALIASES = 'aliases'
CONF_GROUP_ALIASES = 'group_aliases'
CONF_GROUP = 'group'
CONF_NOGROUP_ALIASES = 'nogroup_aliases'
CONF_DEVICE_DEFAULTS = 'device_defaults'
CONF_DEVICES = 'devices'
CONF_AUTOMATIC_ADD = 'automatic_add'
CONF_FIRE_EVENT = 'fire_event'
CONF_IGNORE_DEVICES = 'ignore_devices'
CONF_RECONNECT_INTERVAL = 'reconnect_interval'
CONF_SIGNAL_REPETITIONS = 'signal_repetitions'
CONF_WAIT_FOR_ACK = 'wait_for_ack'

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_DEVICE_DEFAULTS, default=DEVICE_DEFAULTS_SCHEMA({})):
DEVICE_DEFAULTS_SCHEMA,
vol.Optional(CONF_DEVICES, default={}): vol.Schema({
cv.string: {
vol.Optional(CONF_NAME): cv.string,
vol.Optional(CONF_ALIASES, default=[]):
vol.All(cv.ensure_list, [cv.string]),
vol.Optional(CONF_GROUP_ALIASES, default=[]):
vol.All(cv.ensure_list, [cv.string]),
vol.Optional(CONF_NOGROUP_ALIASES, default=[]):
vol.All(cv.ensure_list, [cv.string]),
vol.Optional(CONF_FIRE_EVENT, default=False): cv.boolean,
vol.Optional(CONF_SIGNAL_REPETITIONS): vol.Coerce(int),
vol.Optional(CONF_GROUP, default=True): cv.boolean,
},
}),
})


def devices_from_config(domain_config, hass=None):
"""Parse configuration and add Rflink cover devices."""
devices = []
for device_id, config in domain_config[CONF_DEVICES].items():
device_config = dict(domain_config[CONF_DEVICE_DEFAULTS], **config)
device = RflinkCover(device_id, hass, **device_config)
devices.append(device)

# Register entity (and aliases) to listen to incoming rflink events
# Device id and normal aliases respond to normal and group command
hass.data[DATA_ENTITY_LOOKUP][
EVENT_KEY_COMMAND][device_id].append(device)
if config[CONF_GROUP]:
hass.data[DATA_ENTITY_GROUP_LOOKUP][
EVENT_KEY_COMMAND][device_id].append(device)
for _id in config[CONF_ALIASES]:
hass.data[DATA_ENTITY_LOOKUP][
EVENT_KEY_COMMAND][_id].append(device)
hass.data[DATA_ENTITY_GROUP_LOOKUP][
EVENT_KEY_COMMAND][_id].append(device)
return devices


@asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
"""Set up the Rflink cover platform."""
async_add_devices(devices_from_config(config, hass))


class RflinkCover(RflinkCommand, CoverDevice):
"""Rflink entity which can switch on/stop/off (eg: cover)."""

def _handle_event(self, event):
"""Adjust state if Rflink picks up a remote command for this device."""
self.cancel_queued_send_commands()

command = event['command']
if command in ['on', 'allon']:
self._state = True
elif command in ['off', 'alloff']:
self._state = False

@property
def should_poll(self):
"""No polling available in RFlink cover."""
return False

def async_close_cover(self, **kwargs):
"""Turn the device close."""
return self._async_handle_command("close_cover")

def async_open_cover(self, **kwargs):
"""Turn the device open."""
return self._async_handle_command("open_cover")

def async_stop_cover(self, **kwargs):
"""Turn the device stop."""
return self._async_handle_command("stop_cover")
15 changes: 15 additions & 0 deletions homeassistant/components/rflink.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import os

import async_timeout

from homeassistant.config import load_yaml_config_file
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some specific reason for the newline? I think it's usual to group "import" statements separatedly from "from X import Y"s though.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fix this 👍

from homeassistant.const import (
ATTR_ENTITY_ID, CONF_COMMAND, CONF_HOST, CONF_PORT,
Expand All @@ -22,6 +23,7 @@
from homeassistant.helpers.entity import Entity
import voluptuous as vol


REQUIREMENTS = ['rflink==0.0.34']

_LOGGER = logging.getLogger(__name__)
Expand Down Expand Up @@ -370,6 +372,19 @@ def _async_handle_command(self, command, *args):
# if the state is true, it gets set as false
self._state = self._state in [STATE_UNKNOWN, False]

# Cover options for RFlink
elif command == 'close_cover':
cmd = 'DOWN'
self._state = False

elif command == 'open_cover':
cmd = 'UP'
self._state = True

elif command == 'stop_cover':
cmd = 'STOP'
self._state = True

# Send initial command and queue repetitions.
# This allows the entity state to be updated quickly and not having to
# wait for all repetitions to be sent
Expand Down
35 changes: 34 additions & 1 deletion tests/components/test_rflink.py
0
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
from homeassistant.bootstrap import async_setup_component
from homeassistant.components.rflink import (
CONF_RECONNECT_INTERVAL, SERVICE_SEND_COMMAND)
from homeassistant.const import ATTR_ENTITY_ID, SERVICE_TURN_OFF
from homeassistant.const import (
ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_STOP_COVER)
from tests.common import assert_setup_component


Expand Down Expand Up @@ -119,6 +120,38 @@ def test_send_no_wait(hass, monkeypatch):
assert protocol.send_command.call_args_list[0][0][1] == 'off'


@asyncio.coroutine
def test_cover_send_no_wait(hass, monkeypatch):
"""Test command sending to a cover device without ack."""
domain = 'cover'
config = {
'rflink': {
'port': '/dev/ttyABC0',
'wait_for_ack': False,
},
domain: {
'platform': 'rflink',
'devices': {
'RTS_0100F2_0': {
'name': 'test',
'aliases': ['test_alias_0_0'],
},
},
},
}

# setup mocking rflink module
_, _, protocol, _ = yield from mock_rflink(
hass, config, domain, monkeypatch)

hass.async_add_job(
hass.services.async_call(domain, SERVICE_STOP_COVER,
{ATTR_ENTITY_ID: 'cover.test'}))
yield from hass.async_block_till_done()
assert protocol.send_command.call_args_list[0][0][0] == 'RTS_0100F2_0'
assert protocol.send_command.call_args_list[0][0][1] == 'STOP'


@asyncio.coroutine
def test_send_command(hass, monkeypatch):
"""Test send_command service."""
Expand Down