Skip to content
Closed
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
18 changes: 18 additions & 0 deletions homeassistant/components/homekit/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
CONF_ENTITY_CONFIG = "entity_config"
CONF_FEATURE = "feature"
CONF_FEATURE_LIST = "feature_list"
CONF_REMOTE = "remote"
CONF_REMOTE_ID = "remote_id"
CONF_KEY_MAP = "key_map"
CONF_FILTER = "filter"
CONF_LINKED_BATTERY_SENSOR = "linked_battery_sensor"
CONF_LINKED_BATTERY_CHARGING_SENSOR = "linked_battery_charging_sensor"
Expand All @@ -39,6 +42,21 @@
FEATURE_PLAY_STOP = "play_stop"
FEATURE_TOGGLE_MUTE = "toggle_mute"

# #### Keys ####
KEY_REWIND = "rewind"
KEY_FAST_FORWARD = "fast_forward"
KEY_NEXT_TRACK = "next_track"
KEY_PREVIOUS_TRACK = "previous_track"
KEY_UP = "up"
KEY_DOWN = "down"
KEY_LEFT = "left"
KEY_RIGHT = "right"
KEY_SELECT = "select"
KEY_BACK = "back"
KEY_EXIT = "exit"
KEY_PLAY_PAUSE = "play_pause"
KEY_INFO = "info"

# #### HomeKit Component Event ####
EVENT_HOMEKIT_CHANGED = "homekit_state_change"

Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/homekit/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "HomeKit",
"documentation": "https://www.home-assistant.io/integrations/homekit",
"requirements": ["HAP-python==2.8.2","fnvhash==0.1.0","PyQRCode==1.2.1","base36==0.1.1"],
"dependencies": ["http"],
"dependencies": ["http", "remote"],
"after_dependencies": ["logbook"],
"codeowners": ["@bdraco"]
}
110 changes: 91 additions & 19 deletions homeassistant/components/homekit/type_media_players.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Class to hold all media player accessories."""
from copy import copy
import logging

from pyhap.const import CATEGORY_SWITCH, CATEGORY_TELEVISION
Expand All @@ -17,6 +18,11 @@
SUPPORT_VOLUME_SET,
SUPPORT_VOLUME_STEP,
)
from homeassistant.components.remote import (
ATTR_COMMAND,
DOMAIN as REMOTE_DOMAIN,
SERVICE_SEND_COMMAND,
)
from homeassistant.const import (
ATTR_ENTITY_ID,
ATTR_SUPPORTED_FEATURES,
Expand All @@ -36,6 +42,7 @@
STATE_STANDBY,
STATE_UNKNOWN,
)
from homeassistant.helpers.script import Script

from . import TYPES
from .accessories import HomeAccessory
Expand All @@ -56,10 +63,26 @@
CHAR_VOLUME_CONTROL_TYPE,
CHAR_VOLUME_SELECTOR,
CONF_FEATURE_LIST,
CONF_KEY_MAP,
CONF_REMOTE,
CONF_REMOTE_ID,
FEATURE_ON_OFF,
FEATURE_PLAY_PAUSE,
FEATURE_PLAY_STOP,
FEATURE_TOGGLE_MUTE,
KEY_BACK,
KEY_DOWN,
KEY_EXIT,
KEY_FAST_FORWARD,
KEY_INFO,
KEY_LEFT,
KEY_NEXT_TRACK,
KEY_PLAY_PAUSE,
KEY_PREVIOUS_TRACK,
KEY_REWIND,
KEY_RIGHT,
KEY_SELECT,
KEY_UP,
SERV_INPUT_SOURCE,
SERV_SWITCH,
SERV_TELEVISION,
Expand All @@ -68,22 +91,39 @@

_LOGGER = logging.getLogger(__name__)

MEDIA_PLAYER_KEYS = {
# 0: "Rewind",
# 1: "FastForward",
# 2: "NextTrack",
# 3: "PreviousTrack",
# 4: "ArrowUp",
# 5: "ArrowDown",
# 6: "ArrowLeft",
# 7: "ArrowRight",
# 8: "Select",
# 9: "Back",
# 10: "Exit",
REMOTE_KEYS = {
0: "rewind",
1: "fast_forward",
2: "next_track",
3: "previous_track",
4: "up",
5: "down",
6: "left",
7: "right",
8: "select",
9: "back",
10: "exit",
11: SERVICE_MEDIA_PLAY_PAUSE,
# 15: "Information",
15: "info",
}

REMOTE_KEY_TO_NUMBER = {
KEY_REWIND: 0,
KEY_FAST_FORWARD: 1,
KEY_NEXT_TRACK: 2,
KEY_PREVIOUS_TRACK: 3,
KEY_UP: 4,
KEY_DOWN: 5,
KEY_LEFT: 6,
KEY_RIGHT: 7,
KEY_SELECT: 8,
KEY_BACK: 9,
KEY_EXIT: 10,
KEY_PLAY_PAUSE: 11,
KEY_INFO: 15,
}


MODE_FRIENDLY_NAME = {
FEATURE_ON_OFF: "Power",
FEATURE_PLAY_PAUSE: "Play/Pause",
Expand Down Expand Up @@ -269,6 +309,23 @@ def __init__(self, *args):
CHAR_REMOTE_KEY, setter_callback=self.set_remote_key
)

self._remote = None
if CONF_REMOTE in self.config:
self._remote = (
self.config[CONF_REMOTE]
if isinstance(self.config[CONF_REMOTE], str)
else self.config[CONF_REMOTE][CONF_REMOTE_ID]
)

self._keys = copy(REMOTE_KEYS)
if CONF_KEY_MAP in self.config[CONF_REMOTE]:
for key, value in self.config[CONF_REMOTE][CONF_KEY_MAP].items():
self._keys[REMOTE_KEY_TO_NUMBER[key]] = (
value
if isinstance(value, str)
else Script(self.hass, value)
)

if CHAR_VOLUME_SELECTOR in self.chars_speaker:
serv_speaker = self.add_preload_service(
SERV_TELEVISION_SPEAKER, self.chars_speaker
Expand Down Expand Up @@ -358,19 +415,34 @@ def set_input_source(self, value):
def set_remote_key(self, value):
"""Send remote key value if call came from HomeKit."""
_LOGGER.debug("%s: Set remote key to %s", self.entity_id, value)
service = MEDIA_PLAYER_KEYS.get(value)
if service:
# Handle Play Pause
if service == SERVICE_MEDIA_PLAY_PAUSE:
key = REMOTE_KEYS.get(value)

if key:
# Handle play/pause
if key == SERVICE_MEDIA_PLAY_PAUSE:
state = self.hass.states.get(self.entity_id).state
if state in (STATE_PLAYING, STATE_PAUSED):
service = (
SERVICE_MEDIA_PLAY
if state == STATE_PAUSED
else SERVICE_MEDIA_PAUSE
)
params = {ATTR_ENTITY_ID: self.entity_id}
self.call_service(DOMAIN, service, params)

params = {ATTR_ENTITY_ID: self.entity_id}
self.call_service(DOMAIN, service, params)
return
if isinstance(key, str):
if self._remote is not None:
params = {ATTR_ENTITY_ID: self._remote, ATTR_COMMAND: key}
self.call_service(REMOTE_DOMAIN, SERVICE_SEND_COMMAND, params)
return
else:
key.run()
return

_LOGGER.debug(
"Remote entity undefined or script not specified for this key"
)

def update_state(self, new_state):
"""Update Television state after state changed."""
Expand Down
60 changes: 54 additions & 6 deletions homeassistant/components/homekit/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import pyqrcode
import voluptuous as vol

from homeassistant.components import fan, media_player, sensor
from homeassistant.components import fan, media_player, remote, sensor
from homeassistant.const import (
ATTR_CODE,
ATTR_SUPPORTED_FEATURES,
Expand All @@ -22,8 +22,11 @@
from .const import (
CONF_FEATURE,
CONF_FEATURE_LIST,
CONF_KEY_MAP,
CONF_LINKED_BATTERY_SENSOR,
CONF_LOW_BATTERY_THRESHOLD,
CONF_REMOTE,
CONF_REMOTE_ID,
DEFAULT_LOW_BATTERY_THRESHOLD,
FEATURE_ON_OFF,
FEATURE_PLAY_PAUSE,
Expand All @@ -32,6 +35,19 @@
HOMEKIT_NOTIFY_ID,
HOMEKIT_PAIRING_QR,
HOMEKIT_PAIRING_QR_SECRET,
KEY_BACK,
KEY_DOWN,
KEY_EXIT,
KEY_FAST_FORWARD,
KEY_INFO,
KEY_LEFT,
KEY_NEXT_TRACK,
KEY_PLAY_PAUSE,
KEY_PREVIOUS_TRACK,
KEY_REWIND,
KEY_RIGHT,
KEY_SELECT,
KEY_UP,
TYPE_FAUCET,
TYPE_OUTLET,
TYPE_SHOWER,
Expand All @@ -53,15 +69,11 @@
}
)

FEATURE_SCHEMA = BASIC_INFO_SCHEMA.extend(
{vol.Optional(CONF_FEATURE_LIST, default=None): cv.ensure_list}
)

CODE_SCHEMA = BASIC_INFO_SCHEMA.extend(
{vol.Optional(ATTR_CODE, default=None): vol.Any(None, cv.string)}
)

MEDIA_PLAYER_SCHEMA = vol.Schema(
FEATURE_SCHEMA = vol.Schema(
{
vol.Required(CONF_FEATURE): vol.All(
cv.string,
Expand All @@ -77,6 +89,42 @@
}
)

KEY_MAP_SCHEMA = vol.All(
{
vol.Optional(KEY_REWIND): vol.Any(cv.SCRIPT_SCHEMA, cv.string),
vol.Optional(KEY_FAST_FORWARD): vol.Any(cv.SCRIPT_SCHEMA, cv.string),
vol.Optional(KEY_NEXT_TRACK): vol.Any(cv.SCRIPT_SCHEMA, cv.string),
vol.Optional(KEY_PREVIOUS_TRACK): vol.Any(cv.SCRIPT_SCHEMA, cv.string),
vol.Optional(KEY_UP): vol.Any(cv.SCRIPT_SCHEMA, cv.string),
vol.Optional(KEY_DOWN): vol.Any(cv.SCRIPT_SCHEMA, cv.string),
vol.Optional(KEY_LEFT): vol.Any(cv.SCRIPT_SCHEMA, cv.string),
vol.Optional(KEY_RIGHT): vol.Any(cv.SCRIPT_SCHEMA, cv.string),
vol.Optional(KEY_SELECT): vol.Any(cv.SCRIPT_SCHEMA, cv.string),
vol.Optional(KEY_BACK): vol.Any(cv.SCRIPT_SCHEMA, cv.string),
vol.Optional(KEY_EXIT): vol.Any(cv.SCRIPT_SCHEMA, cv.string),
vol.Optional(KEY_PLAY_PAUSE): vol.Any(cv.SCRIPT_SCHEMA, cv.string),
vol.Optional(KEY_INFO): vol.Any(cv.SCRIPT_SCHEMA, cv.string),
}
)

REMOTE_SCHEMA = vol.All(
{
vol.Optional(CONF_REMOTE_ID, default=None): vol.Any(
None, cv.entity_domain(remote.DOMAIN)
),
vol.Optional(CONF_KEY_MAP): KEY_MAP_SCHEMA,
}
)

MEDIA_PLAYER_SCHEMA = BASIC_INFO_SCHEMA.extend(
{
vol.Optional(CONF_FEATURE_LIST, default=None): cv.ensure_list,
vol.Optional(CONF_REMOTE, default=None): vol.Any(
cv.entity_domain(remote.DOMAIN), REMOTE_SCHEMA
),
}
)

SWITCH_TYPE_SCHEMA = BASIC_INFO_SCHEMA.extend(
{
vol.Optional(CONF_TYPE, default=TYPE_SWITCH): vol.All(
Expand Down