diff --git a/CODEOWNERS b/CODEOWNERS index f0a412faeb1e3463dd030438663716f0a6f5d25f..d135e657c9bfaae9ff02a0cfc64b8fd4d3cbe2c6 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -59,7 +59,7 @@ homeassistant/components/sensor/tibber.py @danielhiversen homeassistant/components/sensor/waqi.py @andrey-git homeassistant/components/switch/rainmachine.py @bachya homeassistant/components/switch/tplink.py @rytilahti -homeassistant/components/xiaomi_aqara.py @danielhiversen +homeassistant/components/xiaomi_aqara.py @danielhiversen @syssi homeassistant/components/*/broadlink.py @danielhiversen homeassistant/components/*/rfxtrx.py @danielhiversen diff --git a/homeassistant/components/xiaomi_aqara.py b/homeassistant/components/xiaomi_aqara.py index 698b25adeeb972681db68d69bb3f6128c9e64341..de4fad503c9c940c4a6e30e0b3b4bf3229e62ed2 100644 --- a/homeassistant/components/xiaomi_aqara.py +++ b/homeassistant/components/xiaomi_aqara.py @@ -13,12 +13,44 @@ REQUIREMENTS = ['PyXiaomiGateway==0.6.0'] ATTR_GW_MAC = 'gw_mac' ATTR_RINGTONE_ID = 'ringtone_id' ATTR_RINGTONE_VOL = 'ringtone_vol' +ATTR_DEVICE_ID = 'device_id' CONF_DISCOVERY_RETRY = 'discovery_retry' CONF_GATEWAYS = 'gateways' CONF_INTERFACE = 'interface' DOMAIN = 'xiaomi_aqara' PY_XIAOMI_GATEWAY = "xiaomi_gw" +SERVICE_PLAY_RINGTONE = 'play_ringtone' +SERVICE_STOP_RINGTONE = 'stop_ringtone' +SERVICE_ADD_DEVICE = 'add_device' +SERVICE_REMOVE_DEVICE = 'remove_device' + +XIAOMI_AQARA_SERVICE_SCHEMA = vol.Schema({ + vol.Required(ATTR_GW_MAC): vol.All(cv.string, + vol.Any(vol.Length(min=12, max=12), + vol.Length(min=17, max=17))) +}) + +SERVICE_SCHEMA_PLAY_RINGTONE = XIAOMI_AQARA_SERVICE_SCHEMA.extend({ + vol.Required(ATTR_RINGTONE_ID): vol.Coerce(int), + vol.Optional(ATTR_RINGTONE_VOL): vol.All(vol.Coerce(int), + vol.Clamp(min=0, max=100)) +}) + +SERVICE_SCHEMA_REMOVE_DEVICE = XIAOMI_AQARA_SERVICE_SCHEMA.extend({ + vol.Required(ATTR_DEVICE_ID): vol.All(cv.string, + vol.Length(min=14, max=14)) +}) + +SERVICE_TO_METHOD = { + SERVICE_PLAY_RINGTONE: {'method': 'play_ringtone_service', + 'schema': SERVICE_SCHEMA_PLAY_RINGTONE}, + SERVICE_STOP_RINGTONE: {'method': 'stop_ringtone_service'}, + SERVICE_ADD_DEVICE: {'method': 'add_device_service'}, + SERVICE_REMOVE_DEVICE: {'method': 'remove_device_service', + 'schema': SERVICE_SCHEMA_REMOVE_DEVICE}, +} + def _validate_conf(config): """Validate a list of devices definitions.""" @@ -116,15 +148,12 @@ def setup(hass, config): hass.data[PY_XIAOMI_GATEWAY].stop_listen() hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_xiaomi) + # pylint: disable=unused-variable def play_ringtone_service(call): """Service to play ringtone through Gateway.""" - ring_id = call.data.get(ATTR_RINGTONE_ID) - gw_sid = call.data.get(ATTR_GW_MAC) - if ring_id is None or gw_sid is None: - _LOGGER.error("Mandatory parameters is not specified.") - return + ring_id = int(call.data.get(ATTR_RINGTONE_ID)) + gw_sid = call.data.get(ATTR_GW_MAC).replace(":", "").lower() - ring_id = int(ring_id) if ring_id in [9, 14-19]: _LOGGER.error('Specified mid: %s is not defined in gateway.', ring_id) @@ -136,8 +165,6 @@ def setup(hass, config): else: ringtone = {'mid': ring_id, 'vol': int(ring_vol)} - gw_sid = gw_sid.replace(":", "").lower() - for (_, gateway) in hass.data[PY_XIAOMI_GATEWAY].gateways.items(): if gateway.sid == gw_sid: gateway.write_to_hub(gateway.sid, **ringtone) @@ -145,15 +172,10 @@ def setup(hass, config): else: _LOGGER.error('Unknown gateway sid: %s was specified.', gw_sid) + # pylint: disable=unused-variable def stop_ringtone_service(call): """Service to stop playing ringtone on Gateway.""" - gw_sid = call.data.get(ATTR_GW_MAC) - if gw_sid is None: - _LOGGER.error("Mandatory parameter (%s) is not specified.", - ATTR_GW_MAC) - return - - gw_sid = gw_sid.replace(":", "").lower() + gw_sid = call.data.get(ATTR_GW_MAC).replace(":", "").lower() for (_, gateway) in hass.data[PY_XIAOMI_GATEWAY].gateways.items(): if gateway.sid == gw_sid: ringtone = {'mid': 10000} @@ -162,12 +184,43 @@ def setup(hass, config): else: _LOGGER.error('Unknown gateway sid: %s was specified.', gw_sid) - hass.services.async_register(DOMAIN, 'play_ringtone', - play_ringtone_service, - description=None, schema=None) - hass.services.async_register(DOMAIN, 'stop_ringtone', - stop_ringtone_service, - description=None, schema=None) + # pylint: disable=unused-variable + def add_device_service(call): + """Service to add a new sub-device within the next 30 seconds.""" + gw_sid = call.data.get(ATTR_GW_MAC).replace(":", "").lower() + for (_, gateway) in hass.data[PY_XIAOMI_GATEWAY].gateways.items(): + if gateway.sid == gw_sid: + join_permission = {'join_permission': 'yes'} + gateway.write_to_hub(gateway.sid, **join_permission) + hass.components.persistent_notification.async_create( + 'Join permission enabled for 30 seconds! ' + 'Please press the pairing button of the new device once.', + title='Xiaomi Aqara Gateway') + break + else: + _LOGGER.error('Unknown gateway sid: %s was specified.', gw_sid) + + # pylint: disable=unused-variable + def remove_device_service(call): + """Service to remove a sub-device from the gateway.""" + device_id = call.data.get(ATTR_DEVICE_ID) + gw_sid = call.data.get(ATTR_GW_MAC).replace(":", "").lower() + remove_device = {'remove_device': device_id} + for (_, gateway) in hass.data[PY_XIAOMI_GATEWAY].gateways.items(): + if gateway.sid == gw_sid: + gateway.write_to_hub(gateway.sid, **remove_device) + break + else: + _LOGGER.error('Unknown gateway sid: %s was specified.', gw_sid) + + for xiaomi_aqara_service in SERVICE_TO_METHOD: + schema = SERVICE_TO_METHOD[xiaomi_aqara_service].get( + 'schema', XIAOMI_AQARA_SERVICE_SCHEMA) + service_handler = SERVICE_TO_METHOD[xiaomi_aqara_service].get('method') + hass.services.async_register( + DOMAIN, xiaomi_aqara_service, service_handler, + description=None, schema=schema) + return True