Skip to content

Commit

Permalink
Added HassOpenCover and HassCloseCover intents (#13372)
Browse files Browse the repository at this point in the history
* Added intents to cover

* Added test for cover intents

* Style fixes

* Reverted reversions

* Async fixes

* Woof

* Added conditional loading

* Added conditional loading

* Added conditional loading

* Moved tests, fixed logic

* Moved tests, fixed logic

* Pylint

* Pylint

* Refactored componenet registration

* Refactored componenet registration

* Lint
  • Loading branch information
tschmidty69 authored and balloob committed Mar 31, 2018
1 parent bf58945 commit bf44dc4
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 81 deletions.
32 changes: 31 additions & 1 deletion homeassistant/components/conversation.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@
from homeassistant.components import http
from homeassistant.components.http.data_validator import (
RequestDataValidator)
from homeassistant.components.cover import (INTENT_OPEN_COVER,
INTENT_CLOSE_COVER)
from homeassistant.const import EVENT_COMPONENT_LOADED
from homeassistant.core import callback
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers import intent

from homeassistant.loader import bind_hass
from homeassistant.setup import (ATTR_COMPONENT)

_LOGGER = logging.getLogger(__name__)

Expand All @@ -28,6 +32,13 @@
REGEX_TURN_COMMAND = re.compile(r'turn (?P<name>(?: |\w)+) (?P<command>\w+)')
REGEX_TYPE = type(re.compile(''))

UTTERANCES = {
'cover': {
INTENT_OPEN_COVER: ['Open [the] [a] [an] {name}[s]'],
INTENT_CLOSE_COVER: ['Close [the] [a] [an] {name}[s]']
}
}

SERVICE_PROCESS = 'process'

SERVICE_PROCESS_SCHEMA = vol.Schema({
Expand Down Expand Up @@ -112,6 +123,25 @@ async def process(service):
'[the] [a] [an] {name}[s] toggle',
])

@callback
def register_utterances(component):
"""Register utterances for a component."""
if component not in UTTERANCES:
return
for intent_type, sentences in UTTERANCES[component].items():
async_register(hass, intent_type, sentences)

@callback
def component_loaded(event):
"""Handle a new component loaded."""
register_utterances(event.data[ATTR_COMPONENT])

hass.bus.async_listen(EVENT_COMPONENT_LOADED, component_loaded)

# Check already loaded components.
for component in hass.config.components:
register_utterances(component)

return True


Expand Down
10 changes: 10 additions & 0 deletions homeassistant/components/cover/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from homeassistant.helpers.config_validation import PLATFORM_SCHEMA # noqa
import homeassistant.helpers.config_validation as cv
from homeassistant.components import group
from homeassistant.helpers import intent
from homeassistant.const import (
SERVICE_OPEN_COVER, SERVICE_CLOSE_COVER, SERVICE_SET_COVER_POSITION,
SERVICE_STOP_COVER, SERVICE_OPEN_COVER_TILT, SERVICE_CLOSE_COVER_TILT,
Expand Down Expand Up @@ -55,6 +56,9 @@
ATTR_POSITION = 'position'
ATTR_TILT_POSITION = 'tilt_position'

INTENT_OPEN_COVER = 'HassOpenCover'
INTENT_CLOSE_COVER = 'HassCloseCover'

COVER_SERVICE_SCHEMA = vol.Schema({
vol.Optional(ATTR_ENTITY_ID): cv.entity_ids,
})
Expand Down Expand Up @@ -181,6 +185,12 @@ async def async_handle_cover_service(service):
hass.services.async_register(
DOMAIN, service_name, async_handle_cover_service,
schema=schema)
hass.helpers.intent.async_register(intent.ServiceIntentHandler(
INTENT_OPEN_COVER, DOMAIN, SERVICE_OPEN_COVER,
"Opened {}"))
hass.helpers.intent.async_register(intent.ServiceIntentHandler(
INTENT_CLOSE_COVER, DOMAIN, SERVICE_CLOSE_COVER,
"Closed {}"))

return True

Expand Down
49 changes: 49 additions & 0 deletions tests/components/cover/test_init.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"""The tests for the cover platform."""

from homeassistant.components.cover import (SERVICE_OPEN_COVER,
SERVICE_CLOSE_COVER)
from homeassistant.components import intent
import homeassistant.components as comps
from tests.common import async_mock_service


async def test_open_cover_intent(hass):
"""Test HassOpenCover intent."""
result = await comps.cover.async_setup(hass, {})
assert result

hass.states.async_set('cover.garage_door', 'closed')
calls = async_mock_service(hass, 'cover', SERVICE_OPEN_COVER)

response = await intent.async_handle(
hass, 'test', 'HassOpenCover', {'name': {'value': 'garage door'}}
)
await hass.async_block_till_done()

assert response.speech['plain']['speech'] == 'Opened garage door'
assert len(calls) == 1
call = calls[0]
assert call.domain == 'cover'
assert call.service == 'open_cover'
assert call.data == {'entity_id': 'cover.garage_door'}


async def test_close_cover_intent(hass):
"""Test HassCloseCover intent."""
result = await comps.cover.async_setup(hass, {})
assert result

hass.states.async_set('cover.garage_door', 'open')
calls = async_mock_service(hass, 'cover', SERVICE_CLOSE_COVER)

response = await intent.async_handle(
hass, 'test', 'HassCloseCover', {'name': {'value': 'garage door'}}
)
await hass.async_block_till_done()

assert response.speech['plain']['speech'] == 'Closed garage door'
assert len(calls) == 1
call = calls[0]
assert call.domain == 'cover'
assert call.service == 'close_cover'
assert call.data == {'entity_id': 'cover.garage_door'}
Loading

0 comments on commit bf44dc4

Please sign in to comment.