Merge remote-tracking branch 'upstream/dev' into igd

This commit is contained in:
Steven Looman 2018-08-29 21:19:27 +02:00
commit 3db766e2ec
974 changed files with 6103 additions and 3081 deletions

View File

@ -116,6 +116,9 @@ omit =
homeassistant/components/google.py
homeassistant/components/*/google.py
homeassistant/components/habitica/*
homeassistant/components/*/habitica.py
homeassistant/components/hangouts/__init__.py
homeassistant/components/hangouts/const.py
homeassistant/components/hangouts/hangouts_bot.py
@ -759,6 +762,7 @@ omit =
homeassistant/components/sensor/uscis.py
homeassistant/components/sensor/vasttrafik.py
homeassistant/components/sensor/viaggiatreno.py
homeassistant/components/sensor/volkszaehler.py
homeassistant/components/sensor/waqi.py
homeassistant/components/sensor/waze_travel_time.py
homeassistant/components/sensor/whois.py
@ -789,6 +793,7 @@ omit =
homeassistant/components/switch/rest.py
homeassistant/components/switch/rpi_rf.py
homeassistant/components/switch/snmp.py
homeassistant/components/switch/switchmate.py
homeassistant/components/switch/telnet.py
homeassistant/components/switch/tplink.py
homeassistant/components/switch/transmission.py

View File

@ -6,8 +6,6 @@ from typing import Any, Dict, List, Optional, Tuple, cast
import jwt
import voluptuous as vol
from homeassistant import data_entry_flow
from homeassistant.core import callback, HomeAssistant
from homeassistant.util import dt as dt_util
@ -26,7 +24,11 @@ async def auth_manager_from_config(
hass: HomeAssistant,
provider_configs: List[Dict[str, Any]],
module_configs: List[Dict[str, Any]]) -> 'AuthManager':
"""Initialize an auth manager from config."""
"""Initialize an auth manager from config.
CORE_CONFIG_SCHEMA will make sure do duplicated auth providers or
mfa modules exist in configs.
"""
store = auth_store.AuthStore(hass)
if provider_configs:
providers = await asyncio.gather(
@ -37,17 +39,7 @@ async def auth_manager_from_config(
# So returned auth providers are in same order as config
provider_hash = OrderedDict() # type: _ProviderDict
for provider in providers:
if provider is None:
continue
key = (provider.type, provider.id)
if key in provider_hash:
_LOGGER.error(
'Found duplicate provider: %s. Please add unique IDs if you '
'want to have the same provider twice.', key)
continue
provider_hash[key] = provider
if module_configs:
@ -59,15 +51,6 @@ async def auth_manager_from_config(
# So returned auth modules are in same order as config
module_hash = OrderedDict() # type: _MfaModuleDict
for module in modules:
if module is None:
continue
if module.id in module_hash:
_LOGGER.error(
'Found duplicate multi-factor module: %s. Please add unique '
'IDs if you want to have the same module twice.', module.id)
continue
module_hash[module.id] = module
manager = AuthManager(hass, store, provider_hash, module_hash)
@ -235,13 +218,6 @@ class AuthManager:
raise ValueError('Unable find multi-factor auth module: {}'
.format(mfa_module_id))
if module.setup_schema is not None:
try:
# pylint: disable=not-callable
data = module.setup_schema(data)
except vol.Invalid as err:
raise ValueError('Data does not match schema: {}'.format(err))
await module.async_setup_user(user.id, data)
async def async_disable_user_mfa(self, user: models.User,
@ -258,13 +234,13 @@ class AuthManager:
await module.async_depose_user(user.id)
async def async_get_enabled_mfa(self, user: models.User) -> List[str]:
async def async_get_enabled_mfa(self, user: models.User) -> Dict[str, str]:
"""List enabled mfa modules for user."""
module_ids = []
modules = OrderedDict() # type: Dict[str, str]
for module_id, module in self._mfa_modules.items():
if await module.async_is_user_setup(user.id):
module_ids.append(module_id)
return module_ids
modules[module_id] = module.name
return modules
async def async_create_refresh_token(self, user: models.User,
client_id: Optional[str] = None) \

View File

@ -8,9 +8,10 @@ from typing import Any, Dict, Optional
import voluptuous as vol
from voluptuous.humanize import humanize_error
from homeassistant import requirements
from homeassistant import requirements, data_entry_flow
from homeassistant.const import CONF_ID, CONF_NAME, CONF_TYPE
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.util.decorator import Registry
MULTI_FACTOR_AUTH_MODULES = Registry()
@ -64,15 +65,14 @@ class MultiFactorAuthModule:
"""Return a voluptuous schema to define mfa auth module's input."""
raise NotImplementedError
@property
def setup_schema(self) -> Optional[vol.Schema]:
"""Return a vol schema to validate mfa auth module's setup input.
async def async_setup_flow(self, user_id: str) -> 'SetupFlow':
"""Return a data entry flow handler for setup module.
Optional
Mfa module should extend SetupFlow
"""
return None
raise NotImplementedError
async def async_setup_user(self, user_id: str, setup_data: Any) -> None:
async def async_setup_user(self, user_id: str, setup_data: Any) -> Any:
"""Set up user for mfa auth module."""
raise NotImplementedError
@ -90,36 +90,70 @@ class MultiFactorAuthModule:
raise NotImplementedError
class SetupFlow(data_entry_flow.FlowHandler):
"""Handler for the setup flow."""
def __init__(self, auth_module: MultiFactorAuthModule,
setup_schema: vol.Schema,
user_id: str) -> None:
"""Initialize the setup flow."""
self._auth_module = auth_module
self._setup_schema = setup_schema
self._user_id = user_id
async def async_step_init(
self, user_input: Optional[Dict[str, str]] = None) \
-> Dict[str, Any]:
"""Handle the first step of setup flow.
Return self.async_show_form(step_id='init') if user_input == None.
Return self.async_create_entry(data={'result': result}) if finish.
"""
errors = {} # type: Dict[str, str]
if user_input:
result = await self._auth_module.async_setup_user(
self._user_id, user_input)
return self.async_create_entry(
title=self._auth_module.name,
data={'result': result}
)
return self.async_show_form(
step_id='init',
data_schema=self._setup_schema,
errors=errors
)
async def auth_mfa_module_from_config(
hass: HomeAssistant, config: Dict[str, Any]) \
-> Optional[MultiFactorAuthModule]:
-> MultiFactorAuthModule:
"""Initialize an auth module from a config."""
module_name = config[CONF_TYPE]
module = await _load_mfa_module(hass, module_name)
if module is None:
return None
try:
config = module.CONFIG_SCHEMA(config) # type: ignore
except vol.Invalid as err:
_LOGGER.error('Invalid configuration for multi-factor module %s: %s',
module_name, humanize_error(config, err))
return None
raise
return MULTI_FACTOR_AUTH_MODULES[module_name](hass, config) # type: ignore
async def _load_mfa_module(hass: HomeAssistant, module_name: str) \
-> Optional[types.ModuleType]:
-> types.ModuleType:
"""Load an mfa auth module."""
module_path = 'homeassistant.auth.mfa_modules.{}'.format(module_name)
try:
module = importlib.import_module(module_path)
except ImportError:
_LOGGER.warning('Unable to find %s', module_path)
return None
except ImportError as err:
_LOGGER.error('Unable to load mfa module %s: %s', module_name, err)
raise HomeAssistantError('Unable to load mfa module {}: {}'.format(
module_name, err))
if hass.config.skip_pip or not hasattr(module, 'REQUIREMENTS'):
return module
@ -135,7 +169,9 @@ async def _load_mfa_module(hass: HomeAssistant, module_name: str) \
hass, module_path, module.REQUIREMENTS) # type: ignore
if not req_success:
return None
raise HomeAssistantError(
'Unable to process requirements of mfa module {}'.format(
module_name))
processed.add(module_name)
return module

View File

@ -1,13 +1,13 @@
"""Example auth module."""
import logging
from typing import Any, Dict, Optional
from typing import Any, Dict
import voluptuous as vol
from homeassistant.core import HomeAssistant
from . import MultiFactorAuthModule, MULTI_FACTOR_AUTH_MODULES, \
MULTI_FACTOR_AUTH_MODULE_SCHEMA
MULTI_FACTOR_AUTH_MODULE_SCHEMA, SetupFlow
CONFIG_SCHEMA = MULTI_FACTOR_AUTH_MODULE_SCHEMA.extend({
vol.Required('data'): [vol.Schema({
@ -36,11 +36,18 @@ class InsecureExampleModule(MultiFactorAuthModule):
return vol.Schema({'pin': str})
@property
def setup_schema(self) -> Optional[vol.Schema]:
def setup_schema(self) -> vol.Schema:
"""Validate async_setup_user input data."""
return vol.Schema({'pin': str})
async def async_setup_user(self, user_id: str, setup_data: Any) -> None:
async def async_setup_flow(self, user_id: str) -> SetupFlow:
"""Return a data entry flow handler for setup module.
Mfa module should extend SetupFlow
"""
return SetupFlow(self, self.setup_schema, user_id)
async def async_setup_user(self, user_id: str, setup_data: Any) -> Any:
"""Set up user to use mfa module."""
# data shall has been validate in caller
pin = setup_data['pin']

View File

@ -0,0 +1,213 @@
"""Time-based One Time Password auth module."""
import logging
from io import BytesIO
from typing import Any, Dict, Optional, Tuple # noqa: F401
import voluptuous as vol
from homeassistant.auth.models import User
from homeassistant.core import HomeAssistant
from . import MultiFactorAuthModule, MULTI_FACTOR_AUTH_MODULES, \
MULTI_FACTOR_AUTH_MODULE_SCHEMA, SetupFlow
REQUIREMENTS = ['pyotp==2.2.6', 'PyQRCode==1.2.1']
CONFIG_SCHEMA = MULTI_FACTOR_AUTH_MODULE_SCHEMA.extend({
}, extra=vol.PREVENT_EXTRA)
STORAGE_VERSION = 1
STORAGE_KEY = 'auth_module.totp'
STORAGE_USERS = 'users'
STORAGE_USER_ID = 'user_id'
STORAGE_OTA_SECRET = 'ota_secret'
INPUT_FIELD_CODE = 'code'
DUMMY_SECRET = 'FPPTH34D4E3MI2HG'
_LOGGER = logging.getLogger(__name__)
def _generate_qr_code(data: str) -> str:
"""Generate a base64 PNG string represent QR Code image of data."""
import pyqrcode
qr_code = pyqrcode.create(data)
with BytesIO() as buffer:
qr_code.svg(file=buffer, scale=4)
return '{}'.format(
buffer.getvalue().decode("ascii").replace('\n', '')
.replace('<?xml version="1.0" encoding="UTF-8"?>'
'<svg xmlns="http://www.w3.org/2000/svg"', '<svg')
)
def _generate_secret_and_qr_code(username: str) -> Tuple[str, str, str]:
"""Generate a secret, url, and QR code."""
import pyotp
ota_secret = pyotp.random_base32()
url = pyotp.totp.TOTP(ota_secret).provisioning_uri(
username, issuer_name="Home Assistant")
image = _generate_qr_code(url)
return ota_secret, url, image
@MULTI_FACTOR_AUTH_MODULES.register('totp')
class TotpAuthModule(MultiFactorAuthModule):
"""Auth module validate time-based one time password."""
DEFAULT_TITLE = 'Time-based One Time Password'
def __init__(self, hass: HomeAssistant, config: Dict[str, Any]) -> None:
"""Initialize the user data store."""
super().__init__(hass, config)
self._users = None # type: Optional[Dict[str, str]]
self._user_store = hass.helpers.storage.Store(
STORAGE_VERSION, STORAGE_KEY)
@property
def input_schema(self) -> vol.Schema:
"""Validate login flow input data."""
return vol.Schema({INPUT_FIELD_CODE: str})
async def _async_load(self) -> None:
"""Load stored data."""
data = await self._user_store.async_load()
if data is None:
data = {STORAGE_USERS: {}}
self._users = data.get(STORAGE_USERS, {})
async def _async_save(self) -> None:
"""Save data."""
await self._user_store.async_save({STORAGE_USERS: self._users})
def _add_ota_secret(self, user_id: str,
secret: Optional[str] = None) -> str:
"""Create a ota_secret for user."""
import pyotp
ota_secret = secret or pyotp.random_base32() # type: str
self._users[user_id] = ota_secret # type: ignore
return ota_secret
async def async_setup_flow(self, user_id: str) -> SetupFlow:
"""Return a data entry flow handler for setup module.
Mfa module should extend SetupFlow
"""
user = await self.hass.auth.async_get_user(user_id) # type: ignore
return TotpSetupFlow(self, self.input_schema, user)
async def async_setup_user(self, user_id: str, setup_data: Any) -> str:
"""Set up auth module for user."""
if self._users is None:
await self._async_load()
result = await self.hass.async_add_executor_job(
self._add_ota_secret, user_id, setup_data.get('secret'))
await self._async_save()
return result
async def async_depose_user(self, user_id: str) -> None:
"""Depose auth module for user."""
if self._users is None:
await self._async_load()
if self._users.pop(user_id, None): # type: ignore
await self._async_save()
async def async_is_user_setup(self, user_id: str) -> bool:
"""Return whether user is setup."""
if self._users is None:
await self._async_load()
return user_id in self._users # type: ignore
async def async_validation(
self, user_id: str, user_input: Dict[str, Any]) -> bool:
"""Return True if validation passed."""
if self._users is None:
await self._async_load()
# user_input has been validate in caller
# set INPUT_FIELD_CODE as vol.Required is not user friendly
return await self.hass.async_add_executor_job(
self._validate_2fa, user_id, user_input.get(INPUT_FIELD_CODE, ''))
def _validate_2fa(self, user_id: str, code: str) -> bool:
"""Validate two factor authentication code."""
import pyotp
ota_secret = self._users.get(user_id) # type: ignore
if ota_secret is None:
# even we cannot find user, we still do verify
# to make timing the same as if user was found.
pyotp.TOTP(DUMMY_SECRET).verify(code)
return False
return bool(pyotp.TOTP(ota_secret).verify(code))
class TotpSetupFlow(SetupFlow):
"""Handler for the setup flow."""
def __init__(self, auth_module: TotpAuthModule,
setup_schema: vol.Schema,
user: User) -> None:
"""Initialize the setup flow."""
super().__init__(auth_module, setup_schema, user.id)
# to fix typing complaint
self._auth_module = auth_module # type: TotpAuthModule
self._user = user
self._ota_secret = None # type: Optional[str]
self._url = None # type Optional[str]
self._image = None # type Optional[str]
async def async_step_init(
self, user_input: Optional[Dict[str, str]] = None) \
-> Dict[str, Any]:
"""Handle the first step of setup flow.
Return self.async_show_form(step_id='init') if user_input == None.
Return self.async_create_entry(data={'result': result}) if finish.
"""
import pyotp
errors = {} # type: Dict[str, str]
if user_input:
verified = await self.hass.async_add_executor_job( # type: ignore
pyotp.TOTP(self._ota_secret).verify, user_input['code'])
if verified:
result = await self._auth_module.async_setup_user(
self._user_id, {'secret': self._ota_secret})
return self.async_create_entry(
title=self._auth_module.name,
data={'result': result}
)
errors['base'] = 'invalid_code'
else:
hass = self._auth_module.hass
self._ota_secret, self._url, self._image = \
await hass.async_add_executor_job( # type: ignore
_generate_secret_and_qr_code, str(self._user.name))
return self.async_show_form(
step_id='init',
data_schema=self._setup_schema,
description_placeholders={
'code': self._ota_secret,
'url': self._url,
'qr_code': self._image
},
errors=errors
)

View File

@ -10,6 +10,7 @@ from voluptuous.humanize import humanize_error
from homeassistant import data_entry_flow, requirements
from homeassistant.core import callback, HomeAssistant
from homeassistant.const import CONF_ID, CONF_NAME, CONF_TYPE
from homeassistant.exceptions import HomeAssistantError
from homeassistant.util import dt as dt_util
from homeassistant.util.decorator import Registry
@ -110,33 +111,31 @@ class AuthProvider:
async def auth_provider_from_config(
hass: HomeAssistant, store: AuthStore,
config: Dict[str, Any]) -> Optional[AuthProvider]:
config: Dict[str, Any]) -> AuthProvider:
"""Initialize an auth provider from a config."""
provider_name = config[CONF_TYPE]
module = await load_auth_provider_module(hass, provider_name)
if module is None:
return None
try:
config = module.CONFIG_SCHEMA(config) # type: ignore
except vol.Invalid as err:
_LOGGER.error('Invalid configuration for auth provider %s: %s',
provider_name, humanize_error(config, err))
return None
raise
return AUTH_PROVIDERS[provider_name](hass, store, config) # type: ignore
async def load_auth_provider_module(
hass: HomeAssistant, provider: str) -> Optional[types.ModuleType]:
hass: HomeAssistant, provider: str) -> types.ModuleType:
"""Load an auth provider."""
try:
module = importlib.import_module(
'homeassistant.auth.providers.{}'.format(provider))
except ImportError:
_LOGGER.warning('Unable to find auth provider %s', provider)
return None
except ImportError as err:
_LOGGER.error('Unable to load auth provider %s: %s', provider, err)
raise HomeAssistantError('Unable to load auth provider {}: {}'.format(
provider, err))
if hass.config.skip_pip or not hasattr(module, 'REQUIREMENTS'):
return module
@ -154,7 +153,9 @@ async def load_auth_provider_module(
hass, 'auth provider {}'.format(provider), reqs)
if not req_success:
return None
raise HomeAssistantError(
'Unable to process requirements of auth provider {}'.format(
provider))
processed.add(provider)
return module
@ -168,7 +169,7 @@ class LoginFlow(data_entry_flow.FlowHandler):
self._auth_provider = auth_provider
self._auth_module_id = None # type: Optional[str]
self._auth_manager = auth_provider.hass.auth # type: ignore
self.available_mfa_modules = [] # type: List
self.available_mfa_modules = {} # type: Dict[str, str]
self.created_at = dt_util.utcnow()
self.user = None # type: Optional[User]
@ -196,7 +197,7 @@ class LoginFlow(data_entry_flow.FlowHandler):
errors['base'] = 'invalid_auth_module'
if len(self.available_mfa_modules) == 1:
self._auth_module_id = self.available_mfa_modules[0]
self._auth_module_id = list(self.available_mfa_modules.keys())[0]
return await self.async_step_mfa()
return self.async_show_form(
@ -223,19 +224,27 @@ class LoginFlow(data_entry_flow.FlowHandler):
if user_input is not None:
expires = self.created_at + SESSION_EXPIRATION
if dt_util.utcnow() > expires:
errors['base'] = 'login_expired'
else:
result = await auth_module.async_validation(
self.user.id, user_input) # type: ignore
if not result:
errors['base'] = 'invalid_auth'
return self.async_abort(
reason='login_expired'
)
result = await auth_module.async_validation(
self.user.id, user_input) # type: ignore
if not result:
errors['base'] = 'invalid_code'
if not errors:
return await self.async_finish(self.user)
description_placeholders = {
'mfa_module_name': auth_module.name,
'mfa_module_id': auth_module.id
} # type: Dict[str, str]
return self.async_show_form(
step_id='mfa',
data_schema=auth_module.input_schema,
description_placeholders=description_placeholders,
errors=errors,
)

View File

@ -5,13 +5,16 @@ import hashlib
import hmac
from typing import Any, Dict, List, Optional, cast
import bcrypt
import voluptuous as vol
from homeassistant.const import CONF_ID
from homeassistant.core import callback, HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.util.async_ import run_coroutine_threadsafe
from . import AuthProvider, AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS, LoginFlow
from ..models import Credentials, UserMeta
from ..util import generate_secret
@ -74,8 +77,7 @@ class Data:
Raises InvalidAuth if auth invalid.
"""
hashed = self.hash_password(password)
dummy = b'$2b$12$CiuFGszHx9eNHxPuQcwBWez4CwDTOcLTX5CbOpV6gef2nYuXkY7BO'
found = None
# Compare all users to avoid timing attacks.
@ -84,22 +86,55 @@ class Data:
found = user
if found is None:
# Do one more compare to make timing the same as if user was found.
hmac.compare_digest(hashed, hashed)
# check a hash to make timing the same as if user was found
bcrypt.checkpw(b'foo',
dummy)
raise InvalidAuth
if not hmac.compare_digest(hashed,
base64.b64decode(found['password'])):
user_hash = base64.b64decode(found['password'])
# if the hash is not a bcrypt hash...
# provide a transparant upgrade for old pbkdf2 hash format
if not (user_hash.startswith(b'$2a$')
or user_hash.startswith(b'$2b$')
or user_hash.startswith(b'$2x$')
or user_hash.startswith(b'$2y$')):
# IMPORTANT! validate the login, bail if invalid
hashed = self.legacy_hash_password(password)
if not hmac.compare_digest(hashed, user_hash):
raise InvalidAuth
# then re-hash the valid password with bcrypt
self.change_password(found['username'], password)
run_coroutine_threadsafe(
self.async_save(), self.hass.loop
).result()
user_hash = base64.b64decode(found['password'])
# bcrypt.checkpw is timing-safe
if not bcrypt.checkpw(password.encode(),
user_hash):
raise InvalidAuth
def hash_password(self, password: str, for_storage: bool = False) -> bytes:
"""Encode a password."""
def legacy_hash_password(self, password: str,
for_storage: bool = False) -> bytes:
"""LEGACY password encoding."""
# We're no longer storing salts in data, but if one exists we
# should be able to retrieve it.
salt = self._data['salt'].encode() # type: ignore
hashed = hashlib.pbkdf2_hmac('sha512', password.encode(), salt, 100000)
if for_storage:
hashed = base64.b64encode(hashed)
return hashed
# pylint: disable=no-self-use
def hash_password(self, password: str, for_storage: bool = False) -> bytes:
"""Encode a password."""
hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt(rounds=12)) \
# type: bytes
if for_storage:
hashed = base64.b64encode(hashed)
return hashed
def add_auth(self, username: str, password: str) -> None:
"""Add a new authenticated user/pass."""
if any(user['username'] == username for user in self.users):

View File

@ -111,31 +111,19 @@ class TrustedNetworksLoginFlow(LoginFlow):
self, user_input: Optional[Dict[str, str]] = None) \
-> Dict[str, Any]:
"""Handle the step of the form."""
errors = {}
try:
cast(TrustedNetworksAuthProvider, self._auth_provider)\
.async_validate_access(self._ip_address)
except InvalidAuthError:
errors['base'] = 'invalid_auth'
return self.async_show_form(
step_id='init',
data_schema=None,
errors=errors,
return self.async_abort(
reason='not_whitelisted'
)
if user_input is not None:
user_id = user_input['user']
if user_id not in self._available_users:
errors['base'] = 'invalid_auth'
if not errors:
return await self.async_finish(user_input)
schema = {'user': vol.In(self._available_users)}
return await self.async_finish(user_input)
return self.async_show_form(
step_id='init',
data_schema=vol.Schema(schema),
errors=errors,
data_schema=vol.Schema({'user': vol.In(self._available_users)}),
)

View File

@ -61,7 +61,6 @@ def from_config_dict(config: Dict[str, Any],
config, hass, config_dir, enable_log, verbose, skip_pip,
log_rotate_days, log_file, log_no_color)
)
return hass
@ -88,12 +87,19 @@ async def async_from_config_dict(config: Dict[str, Any],
core_config = config.get(core.DOMAIN, {})
has_api_password = bool((config.get('http') or {}).get('api_password'))
has_trusted_networks = bool((config.get('http') or {})
.get('trusted_networks'))
try:
await conf_util.async_process_ha_core_config(
hass, core_config, has_api_password)
except vol.Invalid as ex:
conf_util.async_log_exception(ex, 'homeassistant', core_config, hass)
hass, core_config, has_api_password, has_trusted_networks)
except vol.Invalid as config_err:
conf_util.async_log_exception(
config_err, 'homeassistant', core_config, hass)
return None
except HomeAssistantError:
_LOGGER.error("Home Assistant core failed to initialize. "
"Further initialization aborted")
return None
await hass.async_add_executor_job(
@ -128,7 +134,7 @@ async def async_from_config_dict(config: Dict[str, Any],
res = await core_components.async_setup(hass, config)
if not res:
_LOGGER.error("Home Assistant core failed to initialize. "
"further initialization aborted")
"Further initialization aborted")
return hass
await persistent_notification.async_setup(hass, config)

View File

@ -20,7 +20,7 @@ _LOGGER = logging.getLogger(__name__)
ICON = 'mdi:security'
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up an alarm control panel for an Abode device."""
data = hass.data[ABODE_DOMAIN]
@ -28,7 +28,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
data.devices.extend(alarm_devices)
add_devices(alarm_devices)
add_entities(alarm_devices)
class AbodeAlarm(AbodeDevice, AlarmControlPanel):

View File

@ -26,10 +26,10 @@ ALARM_TOGGLE_CHIME_SCHEMA = vol.Schema({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up for AlarmDecoder alarm panels."""
device = AlarmDecoderAlarmPanel()
add_devices([device])
add_entities([device])
def alarm_toggle_chime_handler(service):
"""Register toggle chime handler."""

View File

@ -33,7 +33,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up a Alarm.com control panel."""
name = config.get(CONF_NAME)
code = config.get(CONF_CODE)
@ -42,7 +43,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
alarmdotcom = AlarmDotCom(hass, name, code, username, password)
yield from alarmdotcom.async_login()
async_add_devices([alarmdotcom])
async_add_entities([alarmdotcom])
class AlarmDotCom(alarm.AlarmControlPanel):

View File

@ -38,7 +38,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Arlo Alarm Control Panels."""
arlo = hass.data[DATA_ARLO]
@ -51,7 +51,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
for base_station in arlo.base_stations:
base_stations.append(ArloBaseStation(base_station, home_mode_name,
away_mode_name))
add_devices(base_stations, True)
add_entities(base_stations, True)
class ArloBaseStation(AlarmControlPanel):

View File

@ -16,7 +16,7 @@ DEPENDENCIES = ['canary']
_LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Canary alarms."""
data = hass.data[DATA_CANARY]
devices = []
@ -24,7 +24,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
for location in data.locations:
devices.append(CanaryAlarm(data, location.location_id))
add_devices(devices, True)
add_entities(devices, True)
class CanaryAlarm(AlarmControlPanel):

View File

@ -35,7 +35,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Concord232 alarm control panel platform."""
name = config.get(CONF_NAME)
host = config.get(CONF_HOST)
@ -44,7 +44,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
url = 'http://{}:{}'.format(host, port)
try:
add_devices([Concord232Alarm(hass, url, name)])
add_entities([Concord232Alarm(hass, url, name)])
except requests.exceptions.ConnectionError as ex:
_LOGGER.error("Unable to connect to Concord232: %s", str(ex))
return

View File

@ -13,9 +13,9 @@ from homeassistant.const import (
CONF_PENDING_TIME, CONF_TRIGGER_TIME)
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Demo alarm control panel platform."""
add_devices([
add_entities([
manual.ManualAlarm(hass, 'Alarm', '1234', None, False, {
STATE_ALARM_ARMED_AWAY: {
CONF_DELAY_TIME: datetime.timedelta(seconds=0),

View File

@ -34,7 +34,7 @@ STATES = {
}
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Egardia platform."""
if discovery_info is None:
return
@ -45,7 +45,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
discovery_info.get(CONF_REPORT_SERVER_CODES),
discovery_info[CONF_REPORT_SERVER_PORT])
# add egardia alarm device
add_devices([device], True)
add_entities([device], True)
class EgardiaAlarm(alarm.AlarmControlPanel):

View File

@ -33,7 +33,8 @@ ALARM_KEYPRESS_SCHEMA = vol.Schema({
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Perform the setup for Envisalink alarm panels."""
configured_partitions = discovery_info['partitions']
code = discovery_info[CONF_CODE]
@ -53,7 +54,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
)
devices.append(device)
async_add_devices(devices)
async_add_entities(devices)
@callback
def alarm_keypress_handler(service):

View File

@ -24,12 +24,12 @@ HMIP_ZONE_HOME = 'INTERNAL'
async def async_setup_platform(
hass, config, async_add_devices, discovery_info=None):
hass, config, async_add_entities, discovery_info=None):
"""Set up the HomematicIP Cloud alarm control devices."""
pass
async def async_setup_entry(hass, config_entry, async_add_devices):
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the HomematicIP alarm control panel from a config entry."""
from homematicip.aio.group import AsyncSecurityZoneGroup
@ -40,7 +40,7 @@ async def async_setup_entry(hass, config_entry, async_add_devices):
devices.append(HomematicipSecurityZone(home, group))
if devices:
async_add_devices(devices)
async_add_entities(devices)
class HomematicipSecurityZone(HomematicipGenericDevice, AlarmControlPanel):

View File

@ -40,7 +40,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up an iAlarm control panel."""
name = config.get(CONF_NAME)
username = config.get(CONF_USERNAME)
@ -49,7 +49,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
url = 'http://{}'.format(host)
ialarm = IAlarmPanel(name, username, password, url)
add_devices([ialarm], True)
add_entities([ialarm], True)
class IAlarmPanel(alarm.AlarmControlPanel):

View File

@ -59,7 +59,7 @@ PUSH_ALARM_STATE_SERVICE_SCHEMA = vol.Schema({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up a control panel managed through IFTTT."""
if DATA_IFTTT_ALARM not in hass.data:
hass.data[DATA_IFTTT_ALARM] = []
@ -75,7 +75,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
alarmpanel = IFTTTAlarmPanel(name, code, event_away, event_home,
event_night, event_disarm, optimistic)
hass.data[DATA_IFTTT_ALARM].append(alarmpanel)
add_devices([alarmpanel])
add_entities([alarmpanel])
async def push_state_update(service):
"""Set the service state as device state attribute."""

View File

@ -103,9 +103,9 @@ PLATFORM_SCHEMA = vol.Schema(vol.All({
}, _state_validator))
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the manual alarm platform."""
add_devices([ManualAlarm(
add_entities([ManualAlarm(
hass,
config[CONF_NAME],
config.get(CONF_CODE),

View File

@ -123,9 +123,9 @@ PLATFORM_SCHEMA = vol.Schema(vol.All(mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend({
}), _state_validator))
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the manual MQTT alarm platform."""
add_devices([ManualMQTTAlarm(
add_entities([ManualMQTTAlarm(
hass,
config[CONF_NAME],
config.get(CONF_CODE),

View File

@ -47,12 +47,13 @@ PLATFORM_SCHEMA = mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend({
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the MQTT Alarm Control Panel platform."""
if discovery_info is not None:
config = PLATFORM_SCHEMA(discovery_info)
async_add_devices([MqttAlarm(
async_add_entities([MqttAlarm(
config.get(CONF_NAME),
config.get(CONF_STATE_TOPIC),
config.get(CONF_COMMAND_TOPIC),

View File

@ -31,7 +31,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the NX584 platform."""
name = config.get(CONF_NAME)
host = config.get(CONF_HOST)
@ -40,7 +40,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
url = 'http://{}:{}'.format(host, port)
try:
add_devices([NX584Alarm(hass, url, name)])
add_entities([NX584Alarm(hass, url, name)])
except requests.exceptions.ConnectionError as ex:
_LOGGER.error("Unable to connect to NX584: %s", str(ex))
return False

View File

@ -19,14 +19,15 @@ DEPENDENCIES = ['satel_integra']
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up for Satel Integra alarm panels."""
if not discovery_info:
return
device = SatelIntegraAlarmPanel(
"Alarm Panel", discovery_info.get(CONF_ARM_HOME_MODE))
async_add_devices([device])
async_add_entities([device])
class SatelIntegraAlarmPanel(alarm.AlarmControlPanel):

View File

@ -34,7 +34,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the SimpliSafe platform."""
from simplipy.api import SimpliSafeApiInterface, SimpliSafeAPIException
name = config.get(CONF_NAME)
@ -53,7 +53,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
for system in simplisafe.get_systems():
systems.append(SimpliSafeAlarm(system, name, code))
add_devices(systems)
add_entities(systems)
class SimpliSafeAlarm(AlarmControlPanel):

View File

@ -29,7 +29,8 @@ def _get_alarm_state(spc_mode):
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the SPC alarm control panel platform."""
if (discovery_info is None or
discovery_info[ATTR_DISCOVER_AREAS] is None):
@ -39,7 +40,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
devices = [SpcAlarm(api, area)
for area in discovery_info[ATTR_DISCOVER_AREAS]]
async_add_devices(devices)
async_add_entities(devices)
class SpcAlarm(alarm.AlarmControlPanel):

View File

@ -31,14 +31,14 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up a TotalConnect control panel."""
name = config.get(CONF_NAME)
username = config.get(CONF_USERNAME)
password = config.get(CONF_PASSWORD)
total_connect = TotalConnect(name, username, password)
add_devices([total_connect], True)
add_entities([total_connect], True)
class TotalConnect(alarm.AlarmControlPanel):

View File

@ -17,13 +17,13 @@ from homeassistant.const import (
_LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Verisure platform."""
alarms = []
if int(hub.config.get(CONF_ALARM, 1)):
hub.update_overview()
alarms.append(VerisureAlarm())
add_devices(alarms)
add_entities(alarms)
def set_arm_state(state, code=None):

View File

@ -20,7 +20,7 @@ DEPENDENCIES = ['wink']
STATE_ALARM_PRIVACY = 'Private'
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Wink platform."""
import pywink
@ -32,7 +32,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
except AttributeError:
_id = camera.object_id() + camera.name()
if _id not in hass.data[DOMAIN]['unique_ids']:
add_devices([WinkCameraDevice(camera, hass)])
add_entities([WinkCameraDevice(camera, hass)])
class WinkCameraDevice(WinkDevice, alarm.AlarmControlPanel):

View File

@ -0,0 +1,16 @@
{
"mfa_setup": {
"totp": {
"error": {
"invalid_code": "Codi no v\u00e0lid, si us plau torni a provar-ho. Si obteniu aquest error repetidament, assegureu-vos que la data i hora de Home Assistant sigui correcta i precisa."
},
"step": {
"init": {
"description": "Per activar la verificaci\u00f3 en dos passos mitjan\u00e7ant contrasenyes d'un sol \u00fas basades en temps, escanegeu el codi QR amb la vostre aplicaci\u00f3 de verificaci\u00f3. Si no en teniu cap, us recomanem [Google Authenticator](https://support.google.com/accounts/answer/1066447) o b\u00e9 [Authy](https://authy.com/). \n\n {qr_code} \n \nDespr\u00e9s d'escanejar el codi QR, introdu\u00efu el codi de sis d\u00edgits proporcionat per l'aplicaci\u00f3. Si teniu problemes per escanejar el codi QR, feu una configuraci\u00f3 manual amb el codi **`{code}`**.",
"title": "Configureu la verificaci\u00f3 en dos passos utilitzant TOTP"
}
},
"title": "TOTP"
}
}
}

View File

@ -0,0 +1,16 @@
{
"mfa_setup": {
"totp": {
"error": {
"invalid_code": "Invalid code, please try again. If you get this error consistently, please make sure the clock of your Home Assistant system is accurate."
},
"step": {
"init": {
"description": "To activate two factor authentication using time-based one-time passwords, scan the QR code with your authentication app. If you don't have one, we recommend either [Google Authenticator](https://support.google.com/accounts/answer/1066447) or [Authy](https://authy.com/).\n\n{qr_code}\n\nAfter scanning the code, enter the six digit code from your app to verify the setup. If you have problems scanning the QR code, do a manual setup with code **`{code}`**.",
"title": "Set up two-factor authentication using TOTP"
}
},
"title": "TOTP"
}
}
}

View File

@ -0,0 +1,16 @@
{
"mfa_setup": {
"totp": {
"error": {
"invalid_code": "\uc798\ubabb\ub41c \ucf54\ub4dc \uc785\ub2c8\ub2e4. \ub2e4\uc2dc \uc2dc\ub3c4\ud574\uc8fc\uc138\uc694. \uc774 \uc624\ub958\uac00 \uc9c0\uc18d\uc801\uc73c\ub85c \ubc1c\uc0dd\ud55c\ub2e4\uba74 Home Assistant \uc758 \uc2dc\uacc4\uac00 \uc815\ud655\ud55c\uc9c0 \ud655\uc778\ud574\ubcf4\uc138\uc694."
},
"step": {
"init": {
"description": "\uc2dc\uac04 \uae30\ubc18\uc758 \uc77c\ud68c\uc6a9 \ube44\ubc00\ubc88\ud638\ub97c \uc0ac\uc6a9\ud558\ub294 2\ub2e8\uacc4 \uc778\uc99d\uc744 \ud558\ub824\uba74 \uc778\uc99d\uc6a9 \uc571\uc744 \uc774\uc6a9\ud574\uc11c QR \ucf54\ub4dc\ub97c \uc2a4\uce94\ud574 \uc8fc\uc138\uc694. \uc778\uc99d\uc6a9 \uc571\uc740 [Google Authenticator](https://support.google.com/accounts/answer/1066447) \ub098 [Authy](https://authy.com/) \ub97c \ucd94\ucc9c\ub4dc\ub9bd\ub2c8\ub2e4.\n\n{qr_code}\n\n\uc2a4\uce94 \ud6c4\uc5d0 \uc0dd\uc131\ub41c 6\uc790\ub9ac \ucf54\ub4dc\ub97c \uc785\ub825\ud574\uc11c \uc124\uc815\uc744 \ud655\uc778\ud558\uc138\uc694. QR \ucf54\ub4dc \uc2a4\uce94\uc5d0 \ubb38\uc81c\uac00 \uc788\ub2e4\uba74, **`{code}`** \ucf54\ub4dc\ub85c \uc9c1\uc811 \uc124\uc815\ud574\ubcf4\uc138\uc694.",
"title": "TOTP \ub97c \uc0ac\uc6a9\ud558\uc5ec 2 \ub2e8\uacc4 \uc778\uc99d \uad6c\uc131"
}
},
"title": "TOTP (\uc2dc\uac04 \uae30\ubc18 OTP)"
}
}
}

View File

@ -0,0 +1,16 @@
{
"mfa_setup": {
"totp": {
"error": {
"invalid_code": "Ong\u00ebltege Login, prob\u00e9iert w.e.g. nach emol. Falls d\u00ebse Feeler Message \u00ebmmer er\u00ebm optr\u00ebtt dann iwwerpr\u00e9ift op d'Z\u00e4it vum Home Assistant System richteg ass."
},
"step": {
"init": {
"description": "Fir d'Zwee-Faktor-Authentifikatioun m\u00ebttels engem Z\u00e4it bas\u00e9ierten eemolege Passwuert z'aktiv\u00e9ieren, scannt de QR Code mat enger Authentifikatioun's App.\nFalls dir keng hutt, recommand\u00e9iere mir entweder [Google Authenticator](https://support.google.com/accounts/answer/1066447) oder [Authy](https://authy.com/).\n\n{qr_code}\n\nNodeems de Code gescannt ass, gitt de sechs stellege Code vun der App a fir d'Konfiguratioun z'iwwerpr\u00e9iwen. Am Fall vu Problemer fir de QR Code ze scannen, gitt de folgende Code **`{code}`** a fir ee manuelle Setup.",
"title": "Zwee Faktor Authentifikatioun mat TOTP konfigur\u00e9ieren"
}
},
"title": "TOTP"
}
}
}

View File

@ -0,0 +1,16 @@
{
"mfa_setup": {
"totp": {
"error": {
"invalid_code": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u043a\u043e\u0434. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0441\u043d\u043e\u0432\u0430. \u0415\u0441\u043b\u0438 \u0432\u044b \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0435 \u044d\u0442\u0443 \u043e\u0448\u0438\u0431\u043a\u0443, \u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u0443\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0447\u0430\u0441\u044b \u0432 \u0432\u0430\u0448\u0435\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 Home Assistant \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f."
},
"step": {
"init": {
"description": "\u0427\u0442\u043e\u0431\u044b \u0430\u043a\u0442\u0438\u0432\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u0432\u0443\u0445\u0444\u0430\u043a\u0442\u043e\u0440\u043d\u0443\u044e \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043e\u0434\u043d\u043e\u0440\u0430\u0437\u043e\u0432\u044b\u0445 \u043f\u0430\u0440\u043e\u043b\u0435\u0439, \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u043e\u0442\u0441\u043a\u0430\u043d\u0438\u0440\u0443\u0439\u0442\u0435 QR-\u043a\u043e\u0434 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043f\u043e\u0434\u043b\u0438\u043d\u043d\u043e\u0441\u0442\u0438. \u0415\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u0435\u0433\u043e \u043d\u0435\u0442, \u043c\u044b \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043b\u0438\u0431\u043e [Google Authenticator] (https://support.google.com/accounts/answer/1066447), \u043b\u0438\u0431\u043e [Authy] (https://authy.com/). \n\n {qr_code} \n \n \u041f\u043e\u0441\u043b\u0435 \u0441\u043a\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f QR-\u043a\u043e\u0434\u0430 \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u0448\u0435\u0441\u0442\u0438\u0437\u043d\u0430\u0447\u043d\u044b\u0439 \u043a\u043e\u0434 \u0438\u0437 \u0432\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443. \u0415\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u0435\u0441\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0441\u043e \u0441\u043a\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c QR-\u043a\u043e\u0434\u0430, \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u0435 \u0440\u0443\u0447\u043d\u0443\u044e \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u0441 \u043a\u043e\u0434\u043e\u043c ** ` {code} ` **.",
"title": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0434\u0432\u0443\u0445\u0444\u0430\u043a\u0442\u043e\u0440\u043d\u043e\u0439 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c TOTP"
}
},
"title": "TOTP"
}
}
}

View File

@ -0,0 +1,16 @@
{
"mfa_setup": {
"totp": {
"error": {
"invalid_code": "\u53e3\u4ee4\u65e0\u6548\uff0c\u8bf7\u91cd\u65b0\u8f93\u5165\u3002\u5982\u679c\u9519\u8bef\u53cd\u590d\u51fa\u73b0\uff0c\u8bf7\u786e\u4fdd Home Assistant \u7cfb\u7edf\u7684\u65f6\u95f4\u51c6\u786e\u65e0\u8bef\u3002"
},
"step": {
"init": {
"description": "\u8981\u6fc0\u6d3b\u57fa\u4e8e\u65f6\u95f4\u52a8\u6001\u53e3\u4ee4\u7684\u53cc\u91cd\u8ba4\u8bc1\uff0c\u8bf7\u7528\u8eab\u4efd\u9a8c\u8bc1\u5e94\u7528\u626b\u63cf\u4ee5\u4e0b\u4e8c\u7ef4\u7801\u3002\u5982\u679c\u60a8\u8fd8\u6ca1\u6709\u8eab\u4efd\u9a8c\u8bc1\u5e94\u7528\uff0c\u63a8\u8350\u4f7f\u7528 [Google \u8eab\u4efd\u9a8c\u8bc1\u5668](https://support.google.com/accounts/answer/1066447) \u6216 [Authy](https://authy.com/)\u3002\n\n{qr_code}\n\n\u626b\u63cf\u4e8c\u7ef4\u7801\u4ee5\u540e\uff0c\u8f93\u5165\u5e94\u7528\u4e0a\u7684\u516d\u4f4d\u6570\u5b57\u53e3\u4ee4\u6765\u9a8c\u8bc1\u914d\u7f6e\u3002\u5982\u679c\u5728\u626b\u63cf\u4e8c\u7ef4\u7801\u65f6\u9047\u5230\u95ee\u9898\uff0c\u8bf7\u4f7f\u7528\u4ee3\u7801 **`{code}`** \u624b\u52a8\u914d\u7f6e\u3002",
"title": "\u7528\u65f6\u95f4\u52a8\u6001\u53e3\u4ee4\u8bbe\u7f6e\u53cc\u91cd\u8ba4\u8bc1"
}
},
"title": "\u65f6\u95f4\u52a8\u6001\u53e3\u4ee4"
}
}
}

View File

@ -0,0 +1,16 @@
{
"mfa_setup": {
"totp": {
"error": {
"invalid_code": "\u9a57\u8b49\u78bc\u7121\u6548\uff0c\u8acb\u518d\u8a66\u4e00\u6b21\u3002\u5047\u5982\u932f\u8aa4\u6301\u7e8c\u767c\u751f\uff0c\u8acb\u5148\u78ba\u5b9a\u60a8\u7684 Home Assistant \u7cfb\u7d71\u4e0a\u7684\u6642\u9593\u8a2d\u5b9a\u6b63\u78ba\u5f8c\uff0c\u518d\u8a66\u4e00\u6b21\u3002"
},
"step": {
"init": {
"description": "\u6b32\u555f\u7528\u4e00\u6b21\u6027\u4e14\u5177\u6642\u6548\u6027\u7684\u5bc6\u78bc\u4e4b\u5169\u6b65\u9a5f\u9a57\u8b49\u529f\u80fd\uff0c\u8acb\u4f7f\u7528\u60a8\u7684\u9a57\u8b49 App \u6383\u7784\u4e0b\u65b9\u7684 QR code \u3002\u5018\u82e5\u60a8\u5c1a\u672a\u5b89\u88dd\u4efb\u4f55 App\uff0c\u63a8\u85a6\u60a8\u4f7f\u7528 [Google Authenticator](https://support.google.com/accounts/answer/1066447) \u6216 [Authy](https://authy.com/)\u3002\n\n{qr_code}\n\n\u65bc\u6383\u63cf\u4e4b\u5f8c\uff0c\u8f38\u5165 App \u4e2d\u7684\u516d\u4f4d\u6578\u5b57\u9032\u884c\u8a2d\u5b9a\u9a57\u8b49\u3002\u5047\u5982\u6383\u63cf\u51fa\u73fe\u554f\u984c\uff0c\u8acb\u624b\u52d5\u8f38\u5165\u4ee5\u4e0b\u9a57\u8b49\u78bc **`{code}`**\u3002",
"title": "\u4f7f\u7528 TOTP \u8a2d\u5b9a\u5169\u6b65\u9a5f\u9a57\u8b49"
}
},
"title": "TOTP"
}
}
}

View File

@ -68,10 +68,12 @@ from homeassistant.components import websocket_api
from homeassistant.components.http.ban import log_invalid_auth
from homeassistant.components.http.data_validator import RequestDataValidator
from homeassistant.components.http.view import HomeAssistantView
from homeassistant.core import callback
from homeassistant.core import callback, HomeAssistant
from homeassistant.util import dt as dt_util
from . import indieauth
from . import login_flow
from . import mfa_setup_flow
DOMAIN = 'auth'
DEPENDENCIES = ['http']
@ -100,6 +102,7 @@ async def async_setup(hass, config):
)
await login_flow.async_setup(hass, store_result)
await mfa_setup_flow.async_setup(hass)
return True
@ -315,21 +318,28 @@ def _create_auth_code_store():
return store_result, retrieve_result
@websocket_api.ws_require_user()
@callback
def websocket_current_user(hass, connection, msg):
def websocket_current_user(
hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg):
"""Return the current user."""
user = connection.request.get('hass_user')
async def async_get_current_user(user):
"""Get current user."""
enabled_modules = await hass.auth.async_get_enabled_mfa(user)
if user is None:
connection.to_write.put_nowait(websocket_api.error_message(
msg['id'], 'no_user', 'Not authenticated as a user'))
return
connection.send_message_outside(
websocket_api.result_message(msg['id'], {
'id': user.id,
'name': user.name,
'is_owner': user.is_owner,
'credentials': [{'auth_provider_type': c.auth_provider_type,
'auth_provider_id': c.auth_provider_id}
for c in user.credentials],
'mfa_modules': [{
'id': module.id,
'name': module.name,
'enabled': module.id in enabled_modules,
} for module in hass.auth.auth_mfa_modules],
}))
connection.to_write.put_nowait(websocket_api.result_message(msg['id'], {
'id': user.id,
'name': user.name,
'is_owner': user.is_owner,
'credentials': [{'auth_provider_type': c.auth_provider_type,
'auth_provider_id': c.auth_provider_id}
for c in user.credentials]
}))
hass.async_create_task(async_get_current_user(connection.user))

View File

@ -0,0 +1,134 @@
"""Helpers to setup multi-factor auth module."""
import logging
import voluptuous as vol
from homeassistant import data_entry_flow
from homeassistant.components import websocket_api
from homeassistant.core import callback, HomeAssistant
WS_TYPE_SETUP_MFA = 'auth/setup_mfa'
SCHEMA_WS_SETUP_MFA = websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend({
vol.Required('type'): WS_TYPE_SETUP_MFA,
vol.Exclusive('mfa_module_id', 'module_or_flow_id'): str,
vol.Exclusive('flow_id', 'module_or_flow_id'): str,
vol.Optional('user_input'): object,
})
WS_TYPE_DEPOSE_MFA = 'auth/depose_mfa'
SCHEMA_WS_DEPOSE_MFA = websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend({
vol.Required('type'): WS_TYPE_DEPOSE_MFA,
vol.Required('mfa_module_id'): str,
})
DATA_SETUP_FLOW_MGR = 'auth_mfa_setup_flow_manager'
_LOGGER = logging.getLogger(__name__)
async def async_setup(hass):
"""Init mfa setup flow manager."""
async def _async_create_setup_flow(handler, context, data):
"""Create a setup flow. hanlder is a mfa module."""
mfa_module = hass.auth.get_auth_mfa_module(handler)
if mfa_module is None:
raise ValueError('Mfa module {} is not found'.format(handler))
user_id = data.pop('user_id')
return await mfa_module.async_setup_flow(user_id)
async def _async_finish_setup_flow(flow, flow_result):
_LOGGER.debug('flow_result: %s', flow_result)
return flow_result
hass.data[DATA_SETUP_FLOW_MGR] = data_entry_flow.FlowManager(
hass, _async_create_setup_flow, _async_finish_setup_flow)
hass.components.websocket_api.async_register_command(
WS_TYPE_SETUP_MFA, websocket_setup_mfa, SCHEMA_WS_SETUP_MFA)
hass.components.websocket_api.async_register_command(
WS_TYPE_DEPOSE_MFA, websocket_depose_mfa, SCHEMA_WS_DEPOSE_MFA)
@callback
@websocket_api.ws_require_user(allow_system_user=False)
def websocket_setup_mfa(
hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg):
"""Return a setup flow for mfa auth module."""
async def async_setup_flow(msg):
"""Return a setup flow for mfa auth module."""
flow_manager = hass.data[DATA_SETUP_FLOW_MGR]
flow_id = msg.get('flow_id')
if flow_id is not None:
result = await flow_manager.async_configure(
flow_id, msg.get('user_input'))
connection.send_message_outside(
websocket_api.result_message(
msg['id'], _prepare_result_json(result)))
return
mfa_module_id = msg.get('mfa_module_id')
mfa_module = hass.auth.get_auth_mfa_module(mfa_module_id)
if mfa_module is None:
connection.send_message_outside(websocket_api.error_message(
msg['id'], 'no_module',
'MFA module {} is not found'.format(mfa_module_id)))
return
result = await flow_manager.async_init(
mfa_module_id, data={'user_id': connection.user.id})
connection.send_message_outside(
websocket_api.result_message(
msg['id'], _prepare_result_json(result)))
hass.async_create_task(async_setup_flow(msg))
@callback
@websocket_api.ws_require_user(allow_system_user=False)
def websocket_depose_mfa(
hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg):
"""Remove user from mfa module."""
async def async_depose(msg):
"""Remove user from mfa auth module."""
mfa_module_id = msg['mfa_module_id']
try:
await hass.auth.async_disable_user_mfa(
connection.user, msg['mfa_module_id'])
except ValueError as err:
connection.send_message_outside(websocket_api.error_message(
msg['id'], 'disable_failed',
'Cannot disable MFA Module {}: {}'.format(
mfa_module_id, err)))
return
connection.send_message_outside(
websocket_api.result_message(
msg['id'], 'done'))
hass.async_create_task(async_depose(msg))
def _prepare_result_json(result):
"""Convert result to JSON."""
if result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY:
data = result.copy()
return data
if result['type'] != data_entry_flow.RESULT_TYPE_FORM:
return result
import voluptuous_serialize
data = result.copy()
schema = data['data_schema']
if schema is None:
data['data_schema'] = []
else:
data['data_schema'] = voluptuous_serialize.convert(schema)
return data

View File

@ -0,0 +1,16 @@
{
"mfa_setup":{
"totp": {
"title": "TOTP",
"step": {
"init": {
"title": "Set up two-factor authentication using TOTP",
"description": "To activate two factor authentication using time-based one-time passwords, scan the QR code with your authentication app. If you don't have one, we recommend either [Google Authenticator](https://support.google.com/accounts/answer/1066447) or [Authy](https://authy.com/).\n\n{qr_code}\n\nAfter scanning the code, enter the six digit code from your app to verify the setup. If you have problems scanning the QR code, do a manual setup with code **`{code}`**."
}
},
"error": {
"invalid_code": "Invalid code, please try again. If you get this error consistently, please make sure the clock of your Home Assistant system is accurate."
}
}
}
}

View File

@ -16,7 +16,7 @@ DEPENDENCIES = ['abode']
_LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up a sensor for an Abode device."""
import abodepy.helpers.constants as CONST
import abodepy.helpers.timeline as TIMELINE
@ -44,7 +44,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
data.devices.extend(devices)
add_devices(devices)
add_entities(devices)
class AbodeBinarySensor(AbodeDevice, BinarySensorDevice):

View File

@ -27,7 +27,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Binary Sensor platform for ADS."""
ads_hub = hass.data.get(DATA_ADS)
@ -36,7 +36,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
device_class = config.get(CONF_DEVICE_CLASS)
ads_sensor = AdsBinarySensor(ads_hub, name, ads_var, device_class)
add_devices([ads_sensor])
add_entities([ads_sensor])
class AdsBinarySensor(BinarySensorDevice):

View File

@ -28,7 +28,7 @@ ATTR_RF_LOOP4 = 'rf_loop4'
ATTR_RF_LOOP1 = 'rf_loop1'
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the AlarmDecoder binary sensor devices."""
configured_zones = discovery_info[CONF_ZONES]
@ -44,7 +44,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
zone_num, zone_name, zone_type, zone_rfid, relay_addr, relay_chan)
devices.append(device)
add_devices(devices)
add_entities(devices)
return True

View File

@ -14,7 +14,8 @@ DEPENDENCIES = ['android_ip_webcam']
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the IP Webcam binary sensors."""
if discovery_info is None:
return
@ -23,7 +24,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
name = discovery_info[CONF_NAME]
ipcam = hass.data[DATA_IP_WEBCAM][host]
async_add_devices(
async_add_entities(
[IPWebcamBinarySensor(name, host, ipcam, 'motion_active')], True)

View File

@ -20,9 +20,9 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up an APCUPSd Online Status binary sensor."""
add_devices([OnlineStatus(config, apcupsd.DATA)], True)
add_entities([OnlineStatus(config, apcupsd.DATA)], True)
class OnlineStatus(BinarySensorDevice):

View File

@ -29,7 +29,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the aREST binary sensor."""
resource = config.get(CONF_RESOURCE)
pin = config.get(CONF_PIN)
@ -47,7 +47,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
arest = ArestData(resource, pin)
add_devices([ArestBinarySensor(
add_entities([ArestBinarySensor(
arest, resource, config.get(CONF_NAME, response[CONF_NAME]),
device_class, pin)], True)

View File

@ -53,7 +53,7 @@ SENSOR_TYPES = {
}
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the August binary sensors."""
data = hass.data[DATA_AUGUST]
devices = []
@ -62,7 +62,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
for sensor_type in SENSOR_TYPES:
devices.append(AugustBinarySensor(data, sensor_type, doorbell))
add_devices(devices, True)
add_entities(devices, True)
class AugustBinarySensor(BinarySensorDevice):

View File

@ -39,7 +39,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the aurora sensor."""
if None in (hass.config.latitude, hass.config.longitude):
_LOGGER.error("Lat. or long. not set in Home Assistant config")
@ -57,7 +57,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
"Connection to aurora forecast service failed: %s", error)
return False
add_devices([AuroraSensor(aurora_data, name)], True)
add_entities([AuroraSensor(aurora_data, name)], True)
class AuroraSensor(BinarySensorDevice):

View File

@ -18,9 +18,9 @@ DEPENDENCIES = ['axis']
_LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Axis binary devices."""
add_devices([AxisBinarySensor(hass, discovery_info)], True)
add_entities([AxisBinarySensor(hass, discovery_info)], True)
class AxisBinarySensor(AxisDeviceEvent, BinarySensorDevice):

View File

@ -75,7 +75,8 @@ def update_probability(prior, prob_true, prob_false):
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the Bayesian Binary sensor."""
name = config.get(CONF_NAME)
observations = config.get(CONF_OBSERVATIONS)
@ -83,7 +84,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
probability_threshold = config.get(CONF_PROBABILITY_THRESHOLD)
device_class = config.get(CONF_DEVICE_CLASS)
async_add_devices([
async_add_entities([
BayesianBinarySensor(
name, prior, observations, probability_threshold, device_class)
], True)

View File

@ -41,7 +41,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Beaglebone Black GPIO devices."""
pins = config.get(CONF_PINS)
@ -49,7 +49,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
for pin, params in pins.items():
binary_sensors.append(BBBGPIOBinarySensor(pin, params))
add_devices(binary_sensors)
add_entities(binary_sensors)
class BBBGPIOBinarySensor(BinarySensorDevice):

View File

@ -10,7 +10,7 @@ from homeassistant.components.binary_sensor import BinarySensorDevice
DEPENDENCIES = ['blink']
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the blink binary sensors."""
if discovery_info is None:
return
@ -20,7 +20,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
for name in data.cameras:
devs.append(BlinkCameraMotionSensor(name, data))
devs.append(BlinkSystemSensor(data))
add_devices(devs, True)
add_entities(devs, True)
class BlinkCameraMotionSensor(BinarySensorDevice):

View File

@ -28,7 +28,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the available BloomSky weather binary sensors."""
bloomsky = hass.components.bloomsky
# Default needed in case of discovery
@ -36,7 +36,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
for device in bloomsky.BLOOMSKY.devices.values():
for variable in sensors:
add_devices(
add_entities(
[BloomSkySensor(bloomsky.BLOOMSKY, device, variable)], True)

View File

@ -31,7 +31,7 @@ SENSOR_TYPES_ELEC = {
SENSOR_TYPES_ELEC.update(SENSOR_TYPES)
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the BMW sensors."""
accounts = hass.data[BMW_DOMAIN]
_LOGGER.debug('Found BMW accounts: %s',
@ -51,7 +51,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
device = BMWConnectedDriveSensor(account, vehicle, key,
value[0], value[1])
devices.append(device)
add_devices(devices, True)
add_entities(devices, True)
class BMWConnectedDriveSensor(BinarySensorDevice):

View File

@ -40,7 +40,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Command line Binary Sensor."""
name = config.get(CONF_NAME)
command = config.get(CONF_COMMAND)
@ -53,7 +53,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
value_template.hass = hass
data = CommandSensorData(hass, command, command_timeout)
add_devices([CommandBinarySensor(
add_entities([CommandBinarySensor(
hass, data, name, device_class, payload_on, payload_off,
value_template)], True)

View File

@ -42,7 +42,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Concord232 binary sensor platform."""
from concord232 import client as concord232_client
@ -79,7 +79,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
)
)
add_devices(sensors, True)
add_entities(sensors, True)
def get_opening_type(zone):

View File

@ -7,21 +7,22 @@ https://home-assistant.io/components/binary_sensor.deconz/
from homeassistant.components.binary_sensor import BinarySensorDevice
from homeassistant.components.deconz.const import (
ATTR_DARK, ATTR_ON, CONF_ALLOW_CLIP_SENSOR, DOMAIN as DATA_DECONZ,
DATA_DECONZ_ID, DATA_DECONZ_UNSUB)
DATA_DECONZ_ID, DATA_DECONZ_UNSUB, DECONZ_DOMAIN)
from homeassistant.const import ATTR_BATTERY_LEVEL
from homeassistant.core import callback
from homeassistant.helpers.device_registry import CONNECTION_ZIGBEE
from homeassistant.helpers.dispatcher import async_dispatcher_connect
DEPENDENCIES = ['deconz']
async def async_setup_platform(hass, config, async_add_devices,
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Old way of setting up deCONZ binary sensors."""
pass
async def async_setup_entry(hass, config_entry, async_add_devices):
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the deCONZ binary sensor."""
@callback
def async_add_sensor(sensors):
@ -33,7 +34,7 @@ async def async_setup_entry(hass, config_entry, async_add_devices):
if sensor.type in DECONZ_BINARY_SENSOR and \
not (not allow_clip_sensor and sensor.type.startswith('CLIP')):
entities.append(DeconzBinarySensor(sensor))
async_add_devices(entities, True)
async_add_entities(entities, True)
hass.data[DATA_DECONZ_UNSUB].append(
async_dispatcher_connect(hass, 'deconz_new_sensor', async_add_sensor))
@ -113,3 +114,19 @@ class DeconzBinarySensor(BinarySensorDevice):
if self._sensor.type in PRESENCE and self._sensor.dark is not None:
attr[ATTR_DARK] = self._sensor.dark
return attr
@property
def device_info(self):
"""Return a device description for device registry."""
if (self._sensor.uniqueid is None or
self._sensor.uniqueid.count(':') != 7):
return None
serial = self._sensor.uniqueid.split('-', 1)[0]
return {
'connections': {(CONNECTION_ZIGBEE, serial)},
'identifiers': {(DECONZ_DOMAIN, serial)},
'manufacturer': self._sensor.manufacturer,
'model': self._sensor.modelid,
'name': self._sensor.name,
'sw_version': self._sensor.swversion,
}

View File

@ -7,9 +7,9 @@ https://home-assistant.io/components/demo/
from homeassistant.components.binary_sensor import BinarySensorDevice
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Demo binary sensor platform."""
add_devices([
add_entities([
DemoBinarySensor('Basement Floor Wet', False, 'moisture'),
DemoBinarySensor('Movement Backyard', True, 'motion'),
])

View File

@ -28,7 +28,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Digital Ocean droplet sensor."""
digital = hass.data.get(DATA_DIGITAL_OCEAN)
if not digital:
@ -44,7 +44,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
return False
dev.append(DigitalOceanBinarySensor(digital, droplet_id))
add_devices(dev, True)
add_entities(dev, True)
class DigitalOceanBinarySensor(BinarySensorDevice):

View File

@ -12,7 +12,7 @@ DEPENDENCIES = ['ecobee']
ECOBEE_CONFIG_FILE = 'ecobee.conf'
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Ecobee sensors."""
if discovery_info is None:
return
@ -26,7 +26,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
dev.append(EcobeeBinarySensor(sensor['name'], index))
add_devices(dev, True)
add_entities(dev, True)
class EcobeeBinarySensor(BinarySensorDevice):

View File

@ -19,7 +19,8 @@ EGARDIA_TYPE_TO_DEVICE_CLASS = {'IR Sensor': 'motion',
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Initialize the platform."""
if (discovery_info is None or
discovery_info[ATTR_DISCOVER_DEVICES] is None):
@ -27,7 +28,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
disc_info = discovery_info[ATTR_DISCOVER_DEVICES]
# multiple devices here!
async_add_devices(
async_add_entities(
(
EgardiaBinarySensor(
sensor_id=disc_info[sensor]['id'],

View File

@ -15,7 +15,7 @@ _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['eight_sleep']
async def async_setup_platform(hass, config, async_add_devices,
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the eight sleep binary sensor."""
if discovery_info is None:
@ -30,7 +30,7 @@ async def async_setup_platform(hass, config, async_add_devices,
for sensor in sensors:
all_sensors.append(EightHeatSensor(name, eight, sensor))
async_add_devices(all_sensors, True)
async_add_entities(all_sensors, True)
class EightHeatSensor(EightSleepHeatEntity, BinarySensorDevice):

View File

@ -27,13 +27,13 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Binary Sensor platform for EnOcean."""
dev_id = config.get(CONF_ID)
devname = config.get(CONF_NAME)
device_class = config.get(CONF_DEVICE_CLASS)
add_devices([EnOceanBinarySensor(dev_id, devname, device_class)])
add_entities([EnOceanBinarySensor(dev_id, devname, device_class)])
class EnOceanBinarySensor(enocean.EnOceanDevice, BinarySensorDevice):

View File

@ -23,7 +23,8 @@ DEPENDENCIES = ['envisalink']
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the Envisalink binary sensor devices."""
configured_zones = discovery_info['zones']
@ -40,7 +41,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
)
devices.append(device)
async_add_devices(devices)
async_add_entities(devices)
class EnvisalinkBinarySensor(EnvisalinkDevice, BinarySensorDevice):

View File

@ -47,7 +47,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the FFmpeg binary motion sensor."""
manager = hass.data[DATA_FFMPEG]
@ -55,7 +56,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
return
entity = FFmpegMotion(hass, manager, config)
async_add_devices([entity])
async_add_entities([entity])
class FFmpegBinarySensor(FFmpegBase, BinarySensorDevice):

View File

@ -44,7 +44,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the FFmpeg noise binary sensor."""
manager = hass.data[DATA_FFMPEG]
@ -52,7 +53,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
return
entity = FFmpegNoise(hass, manager, config)
async_add_devices([entity])
async_add_entities([entity])
class FFmpegNoise(FFmpegBinarySensor):

View File

@ -23,7 +23,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the GC100 devices."""
binary_sensors = []
ports = config.get(CONF_PORTS)
@ -31,7 +31,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
for port_addr, port_name in port.items():
binary_sensors.append(GC100BinarySensor(
port_name, port_addr, hass.data[DATA_GC100]))
add_devices(binary_sensors, True)
add_entities(binary_sensors, True)
class GC100BinarySensor(BinarySensorDevice):

View File

@ -13,13 +13,13 @@ DEVICETYPE_DEVICE_CLASS = {'motionsensor': 'motion',
'contactsensor': 'opening'}
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up Hive sensor devices."""
if discovery_info is None:
return
session = hass.data.get(DATA_HIVE)
add_devices([HiveBinarySensorEntity(session, discovery_info)])
add_entities([HiveBinarySensorEntity(session, discovery_info)])
class HiveBinarySensorEntity(BinarySensorDevice):

View File

@ -30,7 +30,7 @@ SENSOR_TYPES_CLASS = {
}
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the HomeMatic binary sensor platform."""
if discovery_info is None:
return
@ -40,7 +40,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
new_device = HMBinarySensor(conf)
devices.append(new_device)
add_devices(devices)
add_entities(devices)
class HMBinarySensor(HMDevice, BinarySensorDevice):

View File

@ -19,12 +19,12 @@ STATE_SMOKE_OFF = 'IDLE_OFF'
async def async_setup_platform(
hass, config, async_add_devices, discovery_info=None):
hass, config, async_add_entities, discovery_info=None):
"""Set up the HomematicIP Cloud binary sensor devices."""
pass
async def async_setup_entry(hass, config_entry, async_add_devices):
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the HomematicIP Cloud binary sensor from a config entry."""
from homematicip.aio.device import (
AsyncShutterContact, AsyncMotionDetectorIndoor, AsyncSmokeDetector)
@ -40,7 +40,7 @@ async def async_setup_entry(hass, config_entry, async_add_devices):
devices.append(HomematicipSmokeDetector(home, device))
if devices:
async_add_devices(devices)
async_add_entities(devices)
class HomematicipShutterContact(HomematicipGenericDevice, BinarySensorDevice):

View File

@ -26,7 +26,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up a sensor for a Hydrawise device."""
hydrawise = hass.data[DATA_HYDRAWISE].data
@ -45,7 +45,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
hydrawise.controller_status.get('running', False)
sensors.append(HydrawiseBinarySensor(zone_data, sensor_type))
add_devices(sensors, True)
add_entities(sensors, True)
class HydrawiseBinarySensor(HydrawiseEntity, BinarySensorDevice):

View File

@ -30,7 +30,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the IHC binary sensor platform."""
ihc_controller = hass.data[IHC_DATA][IHC_CONTROLLER]
info = hass.data[IHC_DATA][IHC_INFO]
@ -56,7 +56,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
sensor_type, inverting)
devices.append(sensor)
add_devices(devices)
add_entities(devices)
class IHCBinarySensor(IHCDevice, BinarySensorDevice):

View File

@ -23,7 +23,8 @@ SENSOR_TYPES = {'openClosedSensor': 'opening',
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the INSTEON device class for the hass platform."""
insteon_modem = hass.data['insteon'].get('modem')
@ -37,7 +38,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
new_entity = InsteonBinarySensor(device, state_key)
async_add_devices([new_entity])
async_add_entities([new_entity])
class InsteonBinarySensor(InsteonEntity, BinarySensorDevice):

View File

@ -35,7 +35,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the ISS sensor."""
if None in (hass.config.latitude, hass.config.longitude):
_LOGGER.error("Latitude or longitude not set in Home Assistant config")
@ -51,7 +51,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
name = config.get(CONF_NAME)
show_on_map = config.get(CONF_SHOW_ON_MAP)
add_devices([IssBinarySensor(iss_data, name, show_on_map)], True)
add_entities([IssBinarySensor(iss_data, name, show_on_map)], True)
class IssBinarySensor(BinarySensorDevice):

View File

@ -29,7 +29,7 @@ ISY_DEVICE_TYPES = {
def setup_platform(hass, config: ConfigType,
add_devices: Callable[[list], None], discovery_info=None):
add_entities: Callable[[list], None], discovery_info=None):
"""Set up the ISY994 binary sensor platform."""
devices = []
devices_by_nid = {}
@ -75,7 +75,7 @@ def setup_platform(hass, config: ConfigType,
for name, status, _ in hass.data[ISY994_PROGRAMS][DOMAIN]:
devices.append(ISYBinarySensorProgram(name, status))
add_devices(devices)
add_entities(devices)
def _detect_device_type(node) -> str:

View File

@ -54,27 +54,27 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
async def async_setup_platform(hass, config, async_add_devices,
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up binary sensor(s) for KNX platform."""
if discovery_info is not None:
async_add_devices_discovery(hass, discovery_info, async_add_devices)
async_add_entities_discovery(hass, discovery_info, async_add_entities)
else:
async_add_devices_config(hass, config, async_add_devices)
async_add_entities_config(hass, config, async_add_entities)
@callback
def async_add_devices_discovery(hass, discovery_info, async_add_devices):
def async_add_entities_discovery(hass, discovery_info, async_add_entities):
"""Set up binary sensors for KNX platform configured via xknx.yaml."""
entities = []
for device_name in discovery_info[ATTR_DISCOVER_DEVICES]:
device = hass.data[DATA_KNX].xknx.devices[device_name]
entities.append(KNXBinarySensor(hass, device))
async_add_devices(entities)
async_add_entities(entities)
@callback
def async_add_devices_config(hass, config, async_add_devices):
def async_add_entities_config(hass, config, async_add_entities):
"""Set up binary senor for KNX platform configured within platform."""
name = config.get(CONF_NAME)
import xknx
@ -97,7 +97,7 @@ def async_add_devices_config(hass, config, async_add_devices):
entity.automations.append(KNXAutomation(
hass=hass, device=binary_sensor, hook=hook,
action=action, counter=counter))
async_add_devices([entity])
async_add_entities([entity])
class KNXBinarySensor(BinarySensorDevice):
@ -105,7 +105,7 @@ class KNXBinarySensor(BinarySensorDevice):
def __init__(self, hass, device):
"""Initialize of KNX binary sensor."""
self._device = device
self.device = device
self.hass = hass
self.async_register_callbacks()
self.automations = []
@ -116,12 +116,12 @@ class KNXBinarySensor(BinarySensorDevice):
async def after_update_callback(device):
"""Call after device was updated."""
await self.async_update_ha_state()
self._device.register_device_updated_cb(after_update_callback)
self.device.register_device_updated_cb(after_update_callback)
@property
def name(self):
"""Return the name of the KNX device."""
return self._device.name
return self.device.name
@property
def available(self):
@ -136,9 +136,9 @@ class KNXBinarySensor(BinarySensorDevice):
@property
def device_class(self):
"""Return the class of this sensor."""
return self._device.device_class
return self.device.device_class
@property
def is_on(self):
"""Return true if the binary sensor is on."""
return self._device.is_on()
return self.device.is_on()

View File

@ -20,7 +20,7 @@ _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['konnected']
async def async_setup_platform(hass, config, async_add_devices,
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up binary sensors attached to a Konnected device."""
if discovery_info is None:
@ -31,7 +31,7 @@ async def async_setup_platform(hass, config, async_add_devices,
sensors = [KonnectedBinarySensor(device_id, pin_num, pin_data)
for pin_num, pin_data in
data[CONF_DEVICES][device_id][CONF_BINARY_SENSORS].items()]
async_add_devices(sensors)
async_add_entities(sensors)
class KonnectedBinarySensor(BinarySensorDevice):

View File

@ -27,7 +27,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Linode droplet sensor."""
linode = hass.data.get(DATA_LINODE)
nodes = config.get(CONF_NODES)
@ -40,7 +40,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
return
dev.append(LinodeBinarySensor(linode, node_id))
add_devices(dev, True)
add_entities(dev, True)
class LinodeBinarySensor(BinarySensorDevice):

View File

@ -13,7 +13,7 @@ from homeassistant.const import STATE_UNKNOWN
_LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Iterate through all MAX! Devices and add window shutters."""
devices = []
for handler in hass.data[DATA_KEY].values():
@ -28,7 +28,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
MaxCubeShutter(handler, name, device.rf_address))
if devices:
add_devices(devices)
add_entities(devices)
class MaxCubeShutter(BinarySensorDevice):

View File

@ -28,7 +28,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Modbus binary sensors."""
sensors = []
for coil in config.get(CONF_COILS):
@ -36,7 +36,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
coil.get(CONF_NAME),
coil.get(CONF_SLAVE),
coil.get(CONF_COIL)))
add_devices(sensors)
add_entities(sensors)
class ModbusCoilSensor(BinarySensorDevice):

View File

@ -45,7 +45,8 @@ PLATFORM_SCHEMA = mqtt.MQTT_RO_PLATFORM_SCHEMA.extend({
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the MQTT binary sensor."""
if discovery_info is not None:
config = PLATFORM_SCHEMA(discovery_info)
@ -54,7 +55,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
if value_template is not None:
value_template.hass = hass
async_add_devices([MqttBinarySensor(
async_add_entities([MqttBinarySensor(
config.get(CONF_NAME),
config.get(CONF_STATE_TOPIC),
config.get(CONF_AVAILABILITY_TOPIC),

View File

@ -23,7 +23,8 @@ SENSORS = [
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the MyChevy sensors."""
if discovery_info is None:
return
@ -34,7 +35,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
for car in hub.cars:
sensors.append(EVBinarySensor(hub, sconfig, car.vid))
async_add_devices(sensors)
async_add_entities(sensors)
class EVBinarySensor(BinarySensorDevice):

View File

@ -22,11 +22,11 @@ SENSORS = {
async def async_setup_platform(
hass, config, async_add_devices, discovery_info=None):
hass, config, async_add_entities, discovery_info=None):
"""Set up the mysensors platform for binary sensors."""
mysensors.setup_mysensors_platform(
hass, DOMAIN, discovery_info, MySensorsBinarySensor,
async_add_devices=async_add_devices)
async_add_entities=async_add_entities)
class MySensorsBinarySensor(

View File

@ -17,9 +17,10 @@ DEPENDENCIES = ['http']
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up myStrom Binary Sensor."""
hass.http.register_view(MyStromView(async_add_devices))
hass.http.register_view(MyStromView(async_add_entities))
return True
@ -31,10 +32,10 @@ class MyStromView(HomeAssistantView):
name = 'api:mystrom'
supported_actions = ['single', 'double', 'long', 'touch']
def __init__(self, add_devices):
def __init__(self, add_entities):
"""Initialize the myStrom URL endpoint."""
self.buttons = {}
self.add_devices = add_devices
self.add_entities = add_entities
@asyncio.coroutine
def get(self, request):
@ -62,7 +63,7 @@ class MyStromView(HomeAssistantView):
button_id, button_action)
self.buttons[entity_id] = MyStromBinarySensor(
'{}_{}'.format(button_id, button_action))
hass.async_add_job(self.add_devices, [self.buttons[entity_id]])
self.add_entities([self.buttons[entity_id]])
else:
new_state = True if self.buttons[entity_id].state == 'off' \
else False

View File

@ -54,14 +54,14 @@ _VALID_BINARY_SENSOR_TYPES = {**BINARY_TYPES, **CLIMATE_BINARY_TYPES,
_LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Nest binary sensors.
No longer used.
"""
async def async_setup_entry(hass, entry, async_add_devices):
async def async_setup_entry(hass, entry, async_add_entities):
"""Set up a Nest binary sensor based on a config entry."""
nest = hass.data[DATA_NEST]
@ -112,7 +112,7 @@ async def async_setup_entry(hass, entry, async_add_devices):
return sensors
async_add_devices(await hass.async_add_job(get_binary_sensors), True)
async_add_entities(await hass.async_add_job(get_binary_sensors), True)
class NestBinarySensor(NestSensorDevice, BinarySensorDevice):
@ -130,7 +130,7 @@ class NestBinarySensor(NestSensorDevice, BinarySensorDevice):
def update(self):
"""Retrieve latest state."""
value = getattr(self._device, self.variable)
value = getattr(self.device, self.variable)
if self.variable in STRUCTURE_BINARY_TYPES:
self._state = bool(STRUCTURE_BINARY_STATE_MAP
[self.variable].get(value))
@ -154,5 +154,4 @@ class NestActivityZoneSensor(NestBinarySensor):
def update(self):
"""Retrieve latest state."""
self._state = self._device.has_ongoing_motion_in_zone(
self.zone.zone_id)
self._state = self.device.has_ongoing_motion_in_zone(self.zone.zone_id)

View File

@ -57,7 +57,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the access to Netatmo binary sensor."""
netatmo = hass.components.netatmo
home = config.get(CONF_HOME)
@ -89,7 +89,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
camera_name not in config[CONF_CAMERAS]:
continue
for variable in welcome_sensors:
add_devices([NetatmoBinarySensor(
add_entities([NetatmoBinarySensor(
data, camera_name, module_name, home, timeout,
camera_type, variable)], True)
if camera_type == 'NOC':
@ -98,14 +98,14 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
camera_name not in config[CONF_CAMERAS]:
continue
for variable in presence_sensors:
add_devices([NetatmoBinarySensor(
add_entities([NetatmoBinarySensor(
data, camera_name, module_name, home, timeout,
camera_type, variable)], True)
for module_name in data.get_module_names(camera_name):
for variable in tag_sensors:
camera_type = None
add_devices([NetatmoBinarySensor(
add_entities([NetatmoBinarySensor(
data, camera_name, module_name, home, timeout,
camera_type, variable)], True)

View File

@ -40,7 +40,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the NX584 binary sensor platform."""
from nx584 import client as nx584_client
@ -68,7 +68,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
for zone in zones
if zone['number'] not in exclude}
if zone_sensors:
add_devices(zone_sensors.values())
add_entities(zone_sensors.values())
watcher = NX584Watcher(client, zone_sensors)
watcher.start()
else:

View File

@ -33,7 +33,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the available OctoPrint binary sensors."""
octoprint_api = hass.data[DOMAIN]["api"]
name = config.get(CONF_NAME)
@ -47,7 +47,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
name, SENSOR_TYPES[octo_type][3], SENSOR_TYPES[octo_type][0],
SENSOR_TYPES[octo_type][1], 'flags')
devices.append(new_sensor)
add_devices(devices, True)
add_entities(devices, True)
class OctoPrintBinarySensor(BinarySensorDevice):

View File

@ -25,7 +25,7 @@ ATTR_PROTECTION_WINDOW_ENDING_UV = 'end_uv'
async def async_setup_platform(
hass, config, async_add_devices, discovery_info=None):
hass, config, async_add_entities, discovery_info=None):
"""Set up the OpenUV binary sensor platform."""
if discovery_info is None:
return
@ -38,7 +38,7 @@ async def async_setup_platform(
binary_sensors.append(
OpenUvBinarySensor(openuv, sensor_type, name, icon))
async_add_devices(binary_sensors, True)
async_add_entities(binary_sensors, True)
class OpenUvBinarySensor(OpenUvEntity, BinarySensorDevice):

View File

@ -44,11 +44,11 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up Pilight Binary Sensor."""
disarm = config.get(CONF_DISARM_AFTER_TRIGGER)
if disarm:
add_devices([PilightTriggerSensor(
add_entities([PilightTriggerSensor(
hass=hass,
name=config.get(CONF_NAME),
variable=config.get(CONF_VARIABLE),
@ -58,7 +58,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
rst_dly_sec=config.get(CONF_RESET_DELAY_SEC),
)])
else:
add_devices([PilightBinarySensor(
add_entities([PilightBinarySensor(
hass=hass,
name=config.get(CONF_NAME),
variable=config.get(CONF_VARIABLE),

View File

@ -48,13 +48,13 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Ping Binary sensor."""
name = config.get(CONF_NAME)
host = config.get(CONF_HOST)
count = config.get(CONF_PING_COUNT)
add_devices([PingBinarySensor(name, PingData(host, count))], True)
add_entities([PingBinarySensor(name, PingData(host, count))], True)
class PingBinarySensor(BinarySensorDevice):

View File

@ -15,7 +15,7 @@ DEPENDENCIES = [QWIKSWITCH]
_LOGGER = logging.getLogger(__name__)
async def async_setup_platform(hass, _, add_devices, discovery_info=None):
async def async_setup_platform(hass, _, add_entities, discovery_info=None):
"""Add binary sensor from the main Qwikswitch component."""
if discovery_info is None:
return
@ -24,7 +24,7 @@ async def async_setup_platform(hass, _, add_devices, discovery_info=None):
_LOGGER.debug("Setup qwikswitch.binary_sensor %s, %s",
qsusb, discovery_info)
devs = [QSBinarySensor(sensor) for sensor in discovery_info[QWIKSWITCH]]
add_devices(devs)
add_entities(devs)
class QSBinarySensor(QSEntity, BinarySensorDevice):

View File

@ -24,13 +24,13 @@ DEPENDENCIES = ['rachio']
_LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Rachio binary sensors."""
devices = []
for controller in hass.data[DOMAIN_RACHIO].controllers:
devices.append(RachioControllerOnlineBinarySensor(hass, controller))
add_devices(devices)
add_entities(devices)
_LOGGER.info("%d Rachio binary sensor(s) added", len(devices))

View File

@ -25,7 +25,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up a sensor for a raincloud device."""
raincloud = hass.data[DATA_RAINCLOUD].data
@ -43,7 +43,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
for zone in raincloud.controller.faucet.zones:
sensors.append(RainCloudBinarySensor(zone, sensor_type))
add_devices(sensors, True)
add_entities(sensors, True)
return True

View File

@ -21,7 +21,7 @@ _LOGGER = logging.getLogger(__name__)
async def async_setup_platform(
hass, config, async_add_devices, discovery_info=None):
hass, config, async_add_entities, discovery_info=None):
"""Set up the RainMachine Switch platform."""
if discovery_info is None:
return
@ -34,7 +34,7 @@ async def async_setup_platform(
binary_sensors.append(
RainMachineBinarySensor(rainmachine, sensor_type, name, icon))
async_add_devices(binary_sensors, True)
async_add_entities(binary_sensors, True)
class RainMachineBinarySensor(RainMachineEntity, BinarySensorDevice):

View File

@ -24,12 +24,12 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
async def async_setup_platform(
hass, config, async_add_devices, discovery_info=None):
hass, config, async_add_entities, discovery_info=None):
"""Set up the Random binary sensor."""
name = config.get(CONF_NAME)
device_class = config.get(CONF_DEVICE_CLASS)
async_add_devices([RandomSensor(name, device_class)], True)
async_add_entities([RandomSensor(name, device_class)], True)
class RandomSensor(BinarySensorDevice):

View File

@ -42,7 +42,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the raspihats binary_sensor devices."""
I2CHatBinarySensor.I2C_HATS_MANAGER = hass.data[I2C_HATS_MANAGER]
binary_sensors = []
@ -65,7 +65,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
except I2CHatsException as ex:
_LOGGER.error("Failed to register %s I2CHat@%s %s",
board, hex(address), str(ex))
add_devices(binary_sensors)
add_entities(binary_sensors)
class I2CHatBinarySensor(BinarySensorDevice):

View File

@ -41,7 +41,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
})
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the REST binary sensor."""
name = config.get(CONF_NAME)
resource = config.get(CONF_RESOURCE)
@ -71,7 +71,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
_LOGGER.error("Unable to fetch REST data from %s", resource)
return False
add_devices([RestBinarySensor(
add_entities([RestBinarySensor(
hass, rest, name, device_class, value_template)], True)

View File

@ -42,7 +42,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
}, extra=vol.ALLOW_EXTRA)
def setup_platform(hass, config, add_devices, discovery_info=None):
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Binary Sensor platform to RFXtrx."""
import RFXtrx as rfxtrxmod
sensors = []
@ -71,7 +71,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
sensors.append(device)
rfxtrx.RFX_DEVICES[device_id] = device
add_devices(sensors)
add_entities(sensors)
def binary_sensor_update(event):
"""Call for control updates from the RFXtrx gateway."""
@ -101,7 +101,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
sensor = RfxtrxBinarySensor(event, pkt_id)
sensor.hass = hass
rfxtrx.RFX_DEVICES[device_id] = sensor
add_devices([sensor])
add_entities([sensor])
_LOGGER.info(
"Added binary sensor %s (Device ID: %s Class: %s Sub: %s)",
pkt_id, slugify(event.device.id_string.lower()),

Some files were not shown because too many files have changed in this diff Show More